Commit 3ac1100c by Scott

Move queued selectspecs to DbSelect

parent 5b736070
......@@ -37,7 +37,7 @@ require_once QA_INCLUDE_DIR.'db/maxima.php';
function qa_db_select_with_pending() // any number of parameters read via func_get_args()
{
$selectspecs = func_get_args();
$dbSelect = new \Q2A\Database\DbSelect(qa_service('database'));
$dbSelect = qa_service('dbselect');
return qa_call([$dbSelect, 'selectWithPending'], $selectspecs);
}
......@@ -45,67 +45,52 @@ function qa_db_select_with_pending() // any number of parameters read via func_g
/**
* Queue a $selectspec for running later, with $pendingid (used for retrieval)
* @deprecated 1.9.0 Use DbSelect->queuePending() instead.
* @param string $pendingid
* @param array $selectspec
*/
function qa_db_queue_pending_select($pendingid, $selectspec)
{
global $qa_db_pending_selectspecs;
$qa_db_pending_selectspecs[$pendingid] = $selectspec;
qa_service('dbselect')->queuePending($pendingid, $selectspec);
}
/**
* Get the result of the queued SELECT query identified by $pendingid. Run the query if it hasn't run already. If
* $selectspec is supplied, it doesn't matter if this hasn't been queued before - it will be queued and run now.
* @deprecated 1.9.0 Use DbSelect->getPendingResult() instead.
* @param string $pendingid
* @param array|null $selectspec
* @return mixed
*/
function qa_db_get_pending_result($pendingid, $selectspec = null)
{
global $qa_db_pending_selectspecs, $qa_db_pending_results;
if (isset($selectspec)) {
qa_db_queue_pending_select($pendingid, $selectspec);
} elseif (!isset($qa_db_pending_selectspecs[$pendingid])) {
qa_fatal_error('Pending query was never set up: ' . $pendingid);
}
if (!isset($qa_db_pending_results[$pendingid])) {
qa_db_select_with_pending();
}
return $qa_db_pending_results[$pendingid];
return qa_service('dbselect')->getPendingResult($pendingid, $selectspec);
}
/**
* Remove the results of queued SELECT query identified by $pendingid if it has already been run. This means it will
* run again if its results are requested via qa_db_get_pending_result()
* @deprecated 1.9.0 Use DbSelect->flushPendingResult() instead.
* @param string $pendingid
*/
function qa_db_flush_pending_result($pendingid)
{
global $qa_db_pending_results;
unset($qa_db_pending_results[$pendingid]);
qa_service('dbselect')->flushPendingResult($pendingid);
}
/**
* Modify a selectspec to count the number of items. This assumes the original selectspec does not have a LIMIT clause.
* Currently works with message inbox/outbox functions and user-flags function.
* @deprecated 1.9.0 Use DbSelect->selectspecWithCount() instead.
* @param array $selectspec
* @return array
*/
function qa_db_selectspec_count($selectspec)
{
$selectspec['columns'] = array('count' => 'COUNT(*)');
$selectspec['single'] = true;
unset($selectspec['arraykey']);
return $selectspec;
return qa_service('dbselect')->selectspecWithCount($selectspec);
}
......
......@@ -1899,7 +1899,7 @@ function qa_app()
/**
* Helper function to access services in the Container.
* Helper function to get/set services.
* If the $key parameter is set and the $object parameter is null the container is called to resolve the $key.
* If the $key and the $object parameters are null the container is called to bind the $object to the $key.
* @param mixed $key Identifier for the object to get/set.
......@@ -1911,10 +1911,10 @@ function qa_service($key, $object = null)
$app = Application::getInstance();
if ($object === null) {
return $app->getContainer()->get($key);
return $app->getService($key);
}
$app->getContainer()->set($key, $object);
$app->registerService($key, $object);
}
......
......@@ -435,7 +435,7 @@ function qa_db_list_tables($onlyTablesWithPrefix = false)
*/
function qa_db_single_select($selectspec)
{
$dbSelect = new \Q2A\Database\DbSelect(qa_service('database'));
$dbSelect = qa_service('dbselect');
return $dbSelect->singleSelect($selectspec);
}
......@@ -450,7 +450,7 @@ function qa_db_single_select($selectspec)
*/
function qa_db_multi_select($selectspecs)
{
$dbSelect = new \Q2A\Database\DbSelect(qa_service('database'));
$dbSelect = qa_service('dbselect');
return $dbSelect->multiSelect($selectspecs);
}
......
......@@ -18,20 +18,27 @@
namespace Q2A\App;
use Q2A\Http\Router;
use Q2A\Database\DbConnection;
use Q2A\Database\DbSelect;
use Q2A\Exceptions\FatalErrorException;
use Q2A\Http\Router;
use Q2A\Util\Set;
class Application
{
/** @var Container */
private $container;
/** @var Set */
protected $services;
/** @var Set */
protected $dataStore;
/** @var static */
protected static $instance;
protected function __construct()
{
$this->container = new Container();
$this->services = new Set();
$this->dataStore = new Set();
$this->registerCoreServices();
}
......@@ -49,20 +56,56 @@ class Application
}
/**
* Register the services used by the core.
* Return the specified service.
* @throws FatalErrorException
* @param string $key The key to look for
* @return mixed
*/
private function registerCoreServices()
public function getService($key)
{
$obj = $this->services->get($key);
if ($obj === null) {
throw new FatalErrorException(sprintf('Key "%s" not found in container', $key));
}
return $obj;
}
/**
* Adds a new service to the container.
* @param string $key The key to look for
* @param mixed $value The object to add
* @return void
*/
public function registerService($key, $value)
{
$this->container->set('router', new Router());
$this->container->set('database', new DbConnection());
$this->services->set($key, $value);
}
/**
* Return the container instance.
* @return Container
* Retrieve data from the global storage.
*/
public function getContainer()
public function getData($key)
{
return $this->dataStore->get($key);
}
/**
* Store some data in the global storage.
*/
public function setData($key, $value)
{
return $this->dataStore->set($key, $value);
}
/**
* Register the services used by the core.
*/
private function registerCoreServices()
{
return $this->container;
$db = new DbConnection();
$this->services->set('router', new Router());
$this->services->set('database', $db);
$this->services->set('dbselect', new DbSelect($db));
}
}
......@@ -19,6 +19,7 @@
namespace Q2A\Database;
use Q2A\Storage\CacheFactory;
use Q2A\Util\Set;
/*
The selectspec array can contain the elements below. See db/selects.php for lots of examples.
......@@ -67,8 +68,15 @@ use Q2A\Storage\CacheFactory;
class DbSelect
{
/** @var DbConnection */
protected $db;
/** @var array */
protected $pendingSelects = [];
/** @var array */
protected $pendingResults = [];
public function __construct(DbConnection $db)
{
$this->db = $db;
......@@ -254,8 +262,6 @@ class DbSelect
{
require_once QA_INCLUDE_DIR . 'app/options.php';
global $qa_db_pending_selectspecs, $qa_db_pending_results;
$selectspecs = func_get_args();
$singleresult = (count($selectspecs) == 1);
$outresults = array();
......@@ -267,22 +273,18 @@ class DbSelect
}
}
if (is_array($qa_db_pending_selectspecs)) {
foreach ($qa_db_pending_selectspecs as $pendingid => $selectspec) {
if (!isset($qa_db_pending_results[$pendingid])) {
$selectspecs['pending_' . $pendingid] = $selectspec;
}
foreach ($this->pendingSelects as $pendingid => $selectspec) {
if (!isset($this->pendingResults[$pendingid])) {
$selectspecs['pending_' . $pendingid] = $selectspec;
}
}
$outresults = $outresults + $this->multiSelect($selectspecs);
if (is_array($qa_db_pending_selectspecs)) {
foreach ($qa_db_pending_selectspecs as $pendingid => $selectspec) {
if (!isset($qa_db_pending_results[$pendingid])) {
$qa_db_pending_results[$pendingid] = $outresults['pending_' . $pendingid];
unset($outresults['pending_' . $pendingid]);
}
foreach ($this->pendingSelects as $pendingid => $selectspec) {
if (!isset($this->pendingResults[$pendingid])) {
$this->pendingResults[$pendingid] = $outresults['pending_' . $pendingid];
unset($outresults['pending_' . $pendingid]);
}
}
......@@ -290,6 +292,64 @@ class DbSelect
}
/**
* Queue a $selectspec for running later, with $pendingid (used for retrieval)
* @param string $pendingid
* @param array $selectspec
*/
public function queuePending($pendingid, $selectspec)
{
$this->pendingSelects[$pendingid] = $selectspec;
}
/**
* Get the result of the queued SELECT query identified by $pendingid. Run the query if it hasn't run already. If
* $selectspec is supplied, it doesn't matter if this hasn't been queued before - it will be queued and run now.
* @param string $pendingid
* @param array|null $selectspec
* @return mixed
*/
public function getPendingResult($pendingid, $selectspec = null)
{
if (isset($selectspec)) {
$this->queuePending($pendingid, $selectspec);
} elseif (!isset($this->pendingSelects[$pendingid])) {
qa_fatal_error('Pending query was never set up: ' . $pendingid);
}
if (!isset($this->pendingResults[$pendingid])) {
$this->selectWithPending();
}
return $this->pendingResults[$pendingid];
}
/**
* Remove the results of queued SELECT query identified by $pendingid if it has already been run. This means it will
* run again if its results are requested via qa_db_get_pending_result()
* @param string $pendingid
*/
public function flushPendingResult($pendingid)
{
unset($this->pendingResults[$pendingid]);
}
/**
* Modify a selectspec to count the number of items. This assumes the original selectspec does not have a LIMIT clause.
* Currently works with message inbox/outbox functions and user-flags function.
* @param array $selectspec
* @return array
*/
public function selectspecWithCount($selectspec)
{
$selectspec['columns'] = array('count' => 'COUNT(*)');
$selectspec['single'] = true;
unset($selectspec['arraykey']);
return $selectspec;
}
/**
* Post-process $outresult according to $selectspec, applying 'sortasc', 'sortdesc', 'arrayvalue' and 'single'.
* @param array $outresult
* @param array $selectspec
......
......@@ -16,14 +16,15 @@
More about this license: http://www.question2answer.org/license.php
*/
namespace Q2A\App;
namespace Q2A\Util;
use Q2A\Exceptions\FatalErrorException;
class Container
/**
* Simple object store.
*/
class Set
{
/** @var array */
protected $services = array();
protected $items = [];
/**
* Bind an object to a key.
......@@ -32,21 +33,20 @@ class Container
*/
public function set($key, $object)
{
$this->services[$key] = $object;
$this->items[$key] = $object;
}
/**
* Return an object assigned to the given key. If the key is not found an exception is thrown.
* @throws FatalErrorException
* Return an object assigned to the given key, otherwise null.
* @param string $key The key to look for
* @return mixed
*/
public function get($key)
{
if (isset($this->services[$key])) {
return $this->services[$key];
if (isset($this->items[$key])) {
return $this->items[$key];
}
throw new FatalErrorException(sprintf('Key "%s" not found in container', $key));
return null;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment