2018-11-15 18:10:52 +00:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* FuzeWorks Framework Database Component.
|
|
|
|
*
|
|
|
|
* The FuzeWorks PHP FrameWork
|
|
|
|
*
|
|
|
|
* Copyright (C) 2013-2018 TechFuze
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
|
|
* copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
* SOFTWARE.
|
|
|
|
*
|
|
|
|
* @author TechFuze
|
|
|
|
* @copyright Copyright (c) 2013 - 2018, TechFuze. (http://techfuze.net)
|
|
|
|
* @license https://opensource.org/licenses/MIT MIT License
|
|
|
|
*
|
|
|
|
* @link http://techfuze.net/fuzeworks
|
|
|
|
* @since Version 1.1.4
|
|
|
|
*
|
|
|
|
* @version Version 1.1.4
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace FuzeWorks;
|
2019-02-26 19:46:33 +00:00
|
|
|
use FuzeWorks\DatabaseEngine\iDatabaseEngine;
|
2019-07-22 09:43:01 +00:00
|
|
|
use FuzeWorks\DatabaseEngine\MongoEngine;
|
2019-02-26 19:46:33 +00:00
|
|
|
use FuzeWorks\DatabaseEngine\PDOEngine;
|
|
|
|
use FuzeWorks\Event\DatabaseLoadDriverEvent;
|
2019-08-21 14:42:47 +00:00
|
|
|
use FuzeWorks\Event\DatabaseLoadTableModelEvent;
|
2018-11-15 18:10:52 +00:00
|
|
|
use FuzeWorks\Exception\DatabaseException;
|
2019-02-26 19:46:33 +00:00
|
|
|
use FuzeWorks\Exception\EventException;
|
2019-08-21 14:42:47 +00:00
|
|
|
use FuzeWorks\Model\iDatabaseTableModel;
|
|
|
|
use FuzeWorks\Model\MongoTableModel;
|
|
|
|
use FuzeWorks\Model\PDOTableModel;
|
2018-11-15 18:10:52 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Database loading class
|
|
|
|
*
|
|
|
|
* Loads databases, forges and utilities in a standardized manner.
|
|
|
|
*
|
|
|
|
* @author TechFuze <contact@techfuze.net>
|
|
|
|
* @copyright (c) 2013 - 2014, TechFuze. (https://techfuze.net)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
class Database
|
|
|
|
{
|
2019-02-26 19:46:33 +00:00
|
|
|
|
2018-11-15 18:10:52 +00:00
|
|
|
/**
|
2019-02-26 19:46:33 +00:00
|
|
|
* Current database config as found the database config file with highest priority
|
|
|
|
*
|
|
|
|
* @var array
|
2018-11-15 18:10:52 +00:00
|
|
|
*/
|
2019-02-26 19:46:33 +00:00
|
|
|
protected $dbConfig;
|
2018-11-15 18:10:52 +00:00
|
|
|
|
|
|
|
/**
|
2019-02-26 19:46:33 +00:00
|
|
|
* All engines that can be used for databases
|
|
|
|
*
|
|
|
|
* @var iDatabaseEngine[]
|
2018-11-15 18:10:52 +00:00
|
|
|
*/
|
2019-02-26 19:46:33 +00:00
|
|
|
protected $engines = [];
|
2018-11-15 18:10:52 +00:00
|
|
|
|
2019-08-21 14:42:47 +00:00
|
|
|
/**
|
|
|
|
* All tableModels that can be used for connections
|
|
|
|
*
|
|
|
|
* @var iDatabaseTableModel[]
|
|
|
|
*/
|
|
|
|
protected $tableModels = [];
|
|
|
|
|
2018-11-15 18:10:52 +00:00
|
|
|
/**
|
2019-02-26 19:46:33 +00:00
|
|
|
* Whether all DatabaseEngines have been loaded yet
|
|
|
|
*
|
|
|
|
* @var bool
|
2018-11-15 18:10:52 +00:00
|
|
|
*/
|
2019-02-26 19:46:33 +00:00
|
|
|
protected $enginesLoaded = false;
|
|
|
|
|
|
|
|
/**
|
2019-08-21 14:42:47 +00:00
|
|
|
* Array of all the database engines
|
2019-02-26 19:46:33 +00:00
|
|
|
*
|
|
|
|
* @var iDatabaseEngine[]
|
|
|
|
*/
|
|
|
|
protected $connections = [];
|
2019-08-21 14:42:47 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Array of all the tableModels
|
|
|
|
*
|
|
|
|
* @var iDatabaseTableModel[]
|
|
|
|
*/
|
|
|
|
protected $tables;
|
2018-11-15 18:10:52 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Register with the TracyBridge upon startup
|
|
|
|
*/
|
2019-02-26 19:46:33 +00:00
|
|
|
public function init()
|
2018-11-15 18:10:52 +00:00
|
|
|
{
|
2019-02-26 19:46:33 +00:00
|
|
|
$this->dbConfig = Factory::getInstance()->config->get('database')->toArray();
|
|
|
|
|
2018-11-15 18:10:52 +00:00
|
|
|
if (class_exists('Tracy\Debugger', true))
|
|
|
|
DatabaseTracyBridge::register();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-02-26 19:46:33 +00:00
|
|
|
* Close connections when shutting down FuzeWorks
|
|
|
|
*/
|
|
|
|
public function __destruct()
|
|
|
|
{
|
|
|
|
foreach ($this->connections as $connection)
|
|
|
|
$connection->tearDown();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-11-15 18:10:52 +00:00
|
|
|
*
|
2019-02-26 19:46:33 +00:00
|
|
|
* When providing a database using the databaseLoadDriverEvent, parameters and connectionName
|
|
|
|
* will be ignored.
|
2018-11-15 18:10:52 +00:00
|
|
|
*
|
2019-02-26 19:46:33 +00:00
|
|
|
* @param string $connectionName
|
|
|
|
* @param string $engineName
|
|
|
|
* @param array $parameters
|
|
|
|
* @return iDatabaseEngine
|
2018-11-15 18:10:52 +00:00
|
|
|
* @throws DatabaseException
|
|
|
|
*/
|
2019-02-26 19:46:33 +00:00
|
|
|
public function get(string $connectionName = 'default', string $engineName = '', array $parameters = []): iDatabaseEngine
|
2018-11-15 18:10:52 +00:00
|
|
|
{
|
|
|
|
// Fire the event to allow settings to be changed
|
2019-02-26 19:46:33 +00:00
|
|
|
/** @var DatabaseLoadDriverEvent $event */
|
2019-07-22 09:43:01 +00:00
|
|
|
try {
|
|
|
|
$event = Events::fireEvent('databaseLoadDriverEvent', strtolower($engineName), $parameters, $connectionName);
|
|
|
|
} catch (EventException $e) {
|
|
|
|
throw new DatabaseException("Could not get database. databaseLoadDriverEvent threw exception: '".$e->getMessage()."'");
|
|
|
|
}
|
2018-11-15 18:10:52 +00:00
|
|
|
if ($event->isCancelled())
|
2019-02-26 19:46:33 +00:00
|
|
|
throw new DatabaseException("Could not get database. Cancelled by databaseLoadDriverEvent.");
|
2018-11-15 18:10:52 +00:00
|
|
|
|
2019-02-26 19:46:33 +00:00
|
|
|
/** @var iDatabaseEngine $engine */
|
|
|
|
// If a databaseEngine is provided by the event, use that. Otherwise search in the list of engines
|
|
|
|
if (is_object($event->databaseEngine) && $event->databaseEngine instanceof iDatabaseEngine)
|
2018-11-15 18:10:52 +00:00
|
|
|
{
|
2019-02-26 19:46:33 +00:00
|
|
|
// Do intervention first
|
|
|
|
$engine = $this->connections[$event->connectionName] = $event->databaseEngine;
|
|
|
|
if (!$engine->isSetup())
|
|
|
|
$engine->setUp($event->parameters);
|
2018-11-15 18:10:52 +00:00
|
|
|
}
|
2019-02-26 19:46:33 +00:00
|
|
|
elseif (isset($this->connections[$event->connectionName]))
|
2018-11-15 18:10:52 +00:00
|
|
|
{
|
2019-02-26 19:46:33 +00:00
|
|
|
// Do already exists second
|
|
|
|
$engine = $this->connections[$event->connectionName];
|
2018-11-15 18:10:52 +00:00
|
|
|
}
|
2019-02-26 19:46:33 +00:00
|
|
|
elseif (!empty($event->engineName) && !empty($event->parameters))
|
2018-11-15 18:10:52 +00:00
|
|
|
{
|
2019-02-26 19:46:33 +00:00
|
|
|
// Do provided config third
|
2019-08-21 14:42:47 +00:00
|
|
|
$engineClass = get_class($this->fetchEngine($event->engineName));
|
2019-02-26 19:46:33 +00:00
|
|
|
$engine = $this->connections[$event->connectionName] = new $engineClass();
|
|
|
|
$engine->setUp($event->parameters);
|
2018-11-15 18:10:52 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-02-26 19:46:33 +00:00
|
|
|
// Do external config fourth
|
|
|
|
if (!isset($this->dbConfig['connections'][$event->connectionName]))
|
|
|
|
throw new DatabaseException("Could not get database. Database not found in config.");
|
|
|
|
|
|
|
|
$engineName = $this->dbConfig['connections'][$event->connectionName]['engineName'];
|
2019-08-21 14:42:47 +00:00
|
|
|
$engineClass = get_class($this->fetchEngine($engineName));
|
2019-02-26 19:46:33 +00:00
|
|
|
$engine = $this->connections[$event->connectionName] = new $engineClass();
|
|
|
|
$engine->setUp($this->dbConfig['connections'][$event->connectionName]);
|
2018-11-15 18:10:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tie it into the Tracy Bar if available
|
|
|
|
if (class_exists('\Tracy\Debugger', true))
|
2019-02-26 19:46:33 +00:00
|
|
|
DatabaseTracyBridge::registerDatabase($engine);
|
2018-11-15 18:10:52 +00:00
|
|
|
|
2019-02-26 19:46:33 +00:00
|
|
|
return $engine;
|
2018-11-15 18:10:52 +00:00
|
|
|
}
|
|
|
|
|
2019-08-21 14:42:47 +00:00
|
|
|
/**
|
|
|
|
* @param string $tableName
|
|
|
|
* @param string $tableModelName
|
|
|
|
* @param string $connectionName
|
|
|
|
* @param array $parameters
|
|
|
|
* @return iDatabaseTableModel
|
|
|
|
* @throws DatabaseException
|
|
|
|
*/
|
|
|
|
public function getTableModel(string $tableName, string $tableModelName, string $connectionName = 'default', array $parameters = []): iDatabaseTableModel
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
/** @var DatabaseLoadTableModelEvent $event */
|
|
|
|
$event = Events::fireEvent('databaseLoadTableModelEvent', strtolower($tableModelName), $parameters, $connectionName, $tableName);
|
|
|
|
} catch (EventException $e) {
|
|
|
|
throw new DatabaseException("Could not get TableModel. databaseLoadTableModelEvent threw exception: '" . $e->getMessage() . "'");
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($event->isCancelled())
|
|
|
|
throw new DatabaseException("Could not get TableModel. Cancelled by databaseLoadTableModelEvent.");
|
|
|
|
|
|
|
|
/** @var iDatabaseTableModel $tableModel */
|
|
|
|
// If a TableModel is provided by the event, use that. Otherwise search in the list of tableModels
|
|
|
|
if (is_object($event->tableModel) && $event->tableModel instanceof iDatabaseTableModel)
|
|
|
|
{
|
|
|
|
$tableModel = $this->tables[$event->connectionName . "|" . $event->tableName] = $event->tableModel;
|
|
|
|
if (!$tableModel->setup())
|
|
|
|
$tableModel->setUp($this->get($event->connectionName, $tableModel->getEngineName(), $event->parameters), $event->tableName);
|
|
|
|
}
|
|
|
|
// If the connection already exists, use that
|
|
|
|
elseif (isset($this->tables[$event->connectionName . "|" . $event->tableName]))
|
|
|
|
{
|
|
|
|
$tableModel = $this->tables[$event->connectionName . "|" . $event->tableName];
|
|
|
|
}
|
|
|
|
// Otherwise use the provided configuration
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$tableModelClass = get_class($this->fetchTableModel($event->tableModelName));
|
|
|
|
$tableModel = $this->tables[$event->connectionName . "|" . $event->tableName] = new $tableModelClass();
|
|
|
|
$tableModel->setUp($this->get($event->connectionName, $tableModel->getEngineName(), $event->parameters), $event->tableName);
|
|
|
|
}
|
|
|
|
|
|
|
|
// And return the tableModel
|
|
|
|
return $tableModel;
|
|
|
|
}
|
|
|
|
|
2018-11-15 18:10:52 +00:00
|
|
|
/**
|
2019-02-26 19:46:33 +00:00
|
|
|
* Get a loaded database engine.
|
2018-11-15 18:10:52 +00:00
|
|
|
*
|
2019-02-26 19:46:33 +00:00
|
|
|
* @param string $engineName
|
|
|
|
* @return iDatabaseEngine
|
|
|
|
* @throws DatabaseException
|
|
|
|
*/
|
2019-08-21 14:42:47 +00:00
|
|
|
public function fetchEngine(string $engineName): iDatabaseEngine
|
2019-02-26 19:46:33 +00:00
|
|
|
{
|
|
|
|
// First retrieve the name
|
|
|
|
$engineName = strtolower($engineName);
|
|
|
|
|
|
|
|
// Then load all engines
|
2019-08-21 14:42:47 +00:00
|
|
|
$this->loadDatabaseComponents();
|
2019-02-26 19:46:33 +00:00
|
|
|
|
|
|
|
// If the engine exists, return it
|
|
|
|
if (isset($this->engines[$engineName]))
|
|
|
|
return $this->engines[$engineName];
|
|
|
|
|
|
|
|
// Otherwise throw exception
|
|
|
|
throw new DatabaseException("Could not get engine. Engine does not exist.");
|
|
|
|
}
|
|
|
|
|
2019-08-21 14:42:47 +00:00
|
|
|
/**
|
|
|
|
* Fetch a loaded TableModel
|
|
|
|
*
|
|
|
|
* @param string $tableModelName
|
|
|
|
* @return iDatabaseTableModel
|
|
|
|
* @throws DatabaseException
|
|
|
|
*/
|
|
|
|
public function fetchTableModel(string $tableModelName): iDatabaseTableModel
|
|
|
|
{
|
|
|
|
// First retrieve the name
|
|
|
|
$tableModelName = strtolower($tableModelName);
|
|
|
|
|
|
|
|
// Then load all the tableModels
|
|
|
|
$this->loadDatabaseComponents();
|
|
|
|
|
|
|
|
// If the tableModel exists, return it
|
|
|
|
if (isset($this->tableModels[$tableModelName]))
|
|
|
|
return $this->tableModels[$tableModelName];
|
|
|
|
|
|
|
|
// Otherwise throw an exception
|
|
|
|
throw new DatabaseException("Could not get tableModel. TableModel does not exist.");
|
|
|
|
}
|
|
|
|
|
2019-02-26 19:46:33 +00:00
|
|
|
/**
|
|
|
|
* Register a new database engine
|
2018-11-15 18:10:52 +00:00
|
|
|
*
|
2019-02-26 19:46:33 +00:00
|
|
|
* @param iDatabaseEngine $databaseEngine
|
|
|
|
* @return bool
|
2018-11-15 18:10:52 +00:00
|
|
|
* @throws DatabaseException
|
|
|
|
*/
|
2019-02-26 19:46:33 +00:00
|
|
|
public function registerEngine(iDatabaseEngine $databaseEngine): bool
|
2018-11-15 18:10:52 +00:00
|
|
|
{
|
2019-02-26 19:46:33 +00:00
|
|
|
// First retrieve the name
|
|
|
|
$engineName = strtolower($databaseEngine->getName());
|
2018-11-15 18:10:52 +00:00
|
|
|
|
2019-02-26 19:46:33 +00:00
|
|
|
// Check if the engine is already set
|
|
|
|
if (isset($this->engines[$engineName]))
|
|
|
|
throw new DatabaseException("Could not register engine. Engine '".$engineName."' already registered.");
|
2018-11-15 18:10:52 +00:00
|
|
|
|
|
|
|
|
2019-02-26 19:46:33 +00:00
|
|
|
// Install it
|
|
|
|
$this->engines[$engineName] = $databaseEngine;
|
|
|
|
Logger::log("Registered Database Engine: '" . $engineName . "'");
|
2018-11-15 18:10:52 +00:00
|
|
|
|
2019-02-26 19:46:33 +00:00
|
|
|
return true;
|
2018-11-15 18:10:52 +00:00
|
|
|
}
|
|
|
|
|
2019-08-21 14:42:47 +00:00
|
|
|
/**
|
|
|
|
* Register a new database tableModel
|
|
|
|
*
|
|
|
|
* @param iDatabaseTableModel $tableModel
|
|
|
|
* @return bool
|
|
|
|
* @throws DatabaseException
|
|
|
|
*/
|
|
|
|
public function registerTableModel(iDatabaseTableModel $tableModel): bool
|
|
|
|
{
|
|
|
|
// First retrieve the name
|
|
|
|
$tableModelName = strtolower($tableModel->getName());
|
|
|
|
|
|
|
|
// Check if the tableModel is already set
|
|
|
|
if (isset($this->tableModels[$tableModelName]))
|
|
|
|
throw new DatabaseException("Could not register tableModel. TableModel '" . $tableModelName . "' already registered.");
|
|
|
|
|
|
|
|
// Install it
|
|
|
|
$this->tableModels[$tableModelName] = $tableModel;
|
|
|
|
Logger::log("Registered TableModel type: '" . $tableModelName . "'");
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-11-15 18:10:52 +00:00
|
|
|
/**
|
2019-02-26 19:46:33 +00:00
|
|
|
* Load all databaseEngines by firing a databaseLoadEngineEvent and by loading all the default engines
|
2018-11-15 18:10:52 +00:00
|
|
|
*
|
2019-02-26 19:46:33 +00:00
|
|
|
* @return bool
|
2018-11-15 18:10:52 +00:00
|
|
|
* @throws DatabaseException
|
|
|
|
*/
|
2019-08-21 14:42:47 +00:00
|
|
|
protected function loadDatabaseComponents(): bool
|
2018-11-15 18:10:52 +00:00
|
|
|
{
|
2019-02-26 19:46:33 +00:00
|
|
|
// If already loaded, skip
|
|
|
|
if ($this->enginesLoaded)
|
2018-11-15 18:10:52 +00:00
|
|
|
return false;
|
|
|
|
|
2019-02-26 19:46:33 +00:00
|
|
|
// Fire engine event
|
|
|
|
try {
|
|
|
|
Events::fireEvent('databaseLoadEngineEvent');
|
|
|
|
} catch (EventException $e) {
|
|
|
|
throw new DatabaseException("Could not load database engines. databaseLoadEngineEvent threw exception: '" . $e->getMessage() . "'");
|
2018-11-15 18:10:52 +00:00
|
|
|
}
|
|
|
|
|
2019-02-26 19:46:33 +00:00
|
|
|
// Load the engines provided by the DatabaseComponent
|
|
|
|
$this->registerEngine(new PDOEngine());
|
2019-07-22 09:43:01 +00:00
|
|
|
$this->registerEngine(new MongoEngine());
|
2018-11-15 18:10:52 +00:00
|
|
|
|
2019-08-21 14:42:47 +00:00
|
|
|
// Load the tableModels provided by the DatabaseComponent
|
|
|
|
$this->registerTableModel(new PDOTableModel());
|
|
|
|
$this->registerTableModel(new MongoTableModel());
|
|
|
|
|
2019-02-26 19:46:33 +00:00
|
|
|
// And save results
|
|
|
|
$this->enginesLoaded = true;
|
|
|
|
return true;
|
2018-11-15 18:10:52 +00:00
|
|
|
}
|
2019-02-26 19:46:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2018-11-15 18:10:52 +00:00
|
|
|
}
|