2016-10-12 22:12:25 -04:00
|
|
|
<?php declare(strict_types=1);
|
2014-03-31 12:47:07 -04:00
|
|
|
/**
|
|
|
|
* Query
|
|
|
|
*
|
2016-09-07 13:17:17 -04:00
|
|
|
* SQL Query Builder / Database Abstraction Layer
|
2014-03-31 12:47:07 -04:00
|
|
|
*
|
2018-01-19 13:43:19 -05:00
|
|
|
* PHP version 7.1
|
2016-09-07 13:17:17 -04:00
|
|
|
*
|
|
|
|
* @package Query
|
|
|
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
2018-01-19 13:43:19 -05:00
|
|
|
* @copyright 2012 - 2018 Timothy J. Warren
|
2016-09-07 13:17:17 -04:00
|
|
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
|
|
|
* @link https://git.timshomepage.net/aviat4ion/Query
|
2014-03-31 12:47:07 -04:00
|
|
|
*/
|
2014-04-02 17:08:50 -04:00
|
|
|
namespace Query;
|
|
|
|
|
2016-10-12 20:32:23 -04:00
|
|
|
use DomainException;
|
|
|
|
|
2014-03-31 12:47:07 -04:00
|
|
|
/**
|
|
|
|
* Connection manager class to manage connections for the
|
|
|
|
* Query method
|
|
|
|
*/
|
2015-11-10 10:12:23 -05:00
|
|
|
final class ConnectionManager {
|
2014-03-31 12:47:07 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Map of named database connections
|
|
|
|
* @var array
|
|
|
|
*/
|
2016-09-07 13:10:03 -04:00
|
|
|
private $connections = [];
|
2014-03-31 12:47:07 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Class instance variable
|
2018-01-22 16:04:29 -05:00
|
|
|
* @var ConnectionManager|null
|
2014-03-31 12:47:07 -04:00
|
|
|
*/
|
2018-01-22 16:04:29 -05:00
|
|
|
private static $instance;
|
2014-03-31 12:47:07 -04:00
|
|
|
|
|
|
|
/**
|
2014-03-31 16:01:58 -04:00
|
|
|
* Private constructor to prevent multiple instances
|
2014-04-01 14:54:38 -04:00
|
|
|
* @codeCoverageIgnore
|
2014-03-31 12:47:07 -04:00
|
|
|
*/
|
2016-10-12 22:12:25 -04:00
|
|
|
private function __construct()
|
2016-10-12 20:32:23 -04:00
|
|
|
{
|
|
|
|
}
|
2014-03-31 16:01:58 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Private clone method to prevent cloning
|
2016-09-07 14:22:52 -04:00
|
|
|
*
|
2016-10-12 20:32:23 -04:00
|
|
|
* @throws DomainException
|
2016-09-07 14:22:52 -04:00
|
|
|
* @return void
|
2014-03-31 16:01:58 -04:00
|
|
|
*/
|
2015-07-30 16:40:30 -04:00
|
|
|
public function __clone()
|
|
|
|
{
|
2016-10-12 20:32:23 -04:00
|
|
|
throw new DomainException("Can't clone singleton");
|
2015-07-30 16:40:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prevent serialization of this object
|
2016-09-07 14:22:52 -04:00
|
|
|
*
|
2016-10-12 20:32:23 -04:00
|
|
|
* @throws DomainException
|
2016-09-07 14:22:52 -04:00
|
|
|
* @return void
|
2015-07-30 16:40:30 -04:00
|
|
|
*/
|
|
|
|
public function __sleep()
|
|
|
|
{
|
2018-01-22 16:04:29 -05:00
|
|
|
throw new DomainException('No serializing of singleton');
|
2015-07-30 16:40:30 -04:00
|
|
|
}
|
2014-03-31 12:47:07 -04:00
|
|
|
|
|
|
|
/**
|
2014-04-22 14:02:54 -04:00
|
|
|
* Make sure serialize/deserialize doesn't work
|
2016-09-07 14:22:52 -04:00
|
|
|
*
|
2016-10-12 20:32:23 -04:00
|
|
|
* @throws DomainException
|
2016-09-07 14:22:52 -04:00
|
|
|
* @return void
|
2014-03-31 12:47:07 -04:00
|
|
|
*/
|
2015-07-30 16:40:30 -04:00
|
|
|
public function __wakeup()
|
2014-03-31 12:47:07 -04:00
|
|
|
{
|
2016-10-12 20:32:23 -04:00
|
|
|
throw new DomainException("Can't unserialize singleton");
|
2014-03-31 12:47:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a connection manager instance
|
|
|
|
*
|
|
|
|
* @staticvar null $instance
|
2015-11-10 20:58:32 -05:00
|
|
|
* @return ConnectionManager
|
2014-03-31 12:47:07 -04:00
|
|
|
*/
|
2016-10-13 21:55:23 -04:00
|
|
|
public static function getInstance(): ConnectionManager
|
2014-03-31 12:47:07 -04:00
|
|
|
{
|
2016-09-07 13:10:03 -04:00
|
|
|
if (self::$instance === NULL)
|
2015-11-11 09:25:21 -05:00
|
|
|
{
|
|
|
|
self::$instance = new self();
|
|
|
|
}
|
2014-03-31 12:47:07 -04:00
|
|
|
|
|
|
|
return self::$instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the connection specified by the name given
|
|
|
|
*
|
2014-04-02 18:53:48 -04:00
|
|
|
* @param string|array|object $name
|
2016-10-13 21:55:23 -04:00
|
|
|
* @return QueryBuilderInterface
|
2018-01-26 15:45:46 -05:00
|
|
|
* @throws Exception\NonExistentConnectionException
|
2014-03-31 12:47:07 -04:00
|
|
|
*/
|
2016-10-13 21:55:23 -04:00
|
|
|
public function getConnection($name = ''): QueryBuilderInterface
|
2014-03-31 12:47:07 -04:00
|
|
|
{
|
2014-04-22 14:02:54 -04:00
|
|
|
// If the parameter is a string, use it as an array index
|
2014-03-31 12:47:07 -04:00
|
|
|
if (is_scalar($name) && isset($this->connections[$name]))
|
|
|
|
{
|
|
|
|
return $this->connections[$name];
|
|
|
|
}
|
2018-01-23 13:49:51 -05:00
|
|
|
else if (empty($name) && ! empty($this->connections)) // Otherwise, return the last one
|
2014-03-31 12:47:07 -04:00
|
|
|
{
|
|
|
|
return end($this->connections);
|
|
|
|
}
|
2014-04-24 14:50:53 -04:00
|
|
|
|
|
|
|
// You should actually connect before trying to get a connection...
|
2018-01-26 15:45:46 -05:00
|
|
|
throw new Exception\NonExistentConnectionException('The specified connection does not exist');
|
2014-03-31 12:47:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse the passed parameters and return a connection
|
|
|
|
*
|
2018-01-26 08:39:30 -05:00
|
|
|
* @param object|array $params
|
2018-01-26 15:45:46 -05:00
|
|
|
* @throws Exception\BadDBDriverException
|
2016-10-13 21:55:23 -04:00
|
|
|
* @return QueryBuilderInterface
|
2014-03-31 12:47:07 -04:00
|
|
|
*/
|
2018-01-26 08:39:30 -05:00
|
|
|
public function connect($params): QueryBuilderInterface
|
2014-03-31 12:47:07 -04:00
|
|
|
{
|
2018-01-26 08:39:30 -05:00
|
|
|
[$dsn, $dbtype, $params, $options] = $this->parseParams($params);
|
2014-03-31 12:47:07 -04:00
|
|
|
|
2015-07-16 16:56:13 -04:00
|
|
|
$dbtype = ucfirst($dbtype);
|
|
|
|
$driver = "\\Query\\Drivers\\{$dbtype}\\Driver";
|
2014-04-02 17:08:50 -04:00
|
|
|
|
2014-03-31 12:47:07 -04:00
|
|
|
// Create the database connection
|
2018-01-23 11:29:43 -05:00
|
|
|
$db = ! empty($params->user)
|
2014-04-02 17:08:50 -04:00
|
|
|
? new $driver($dsn, $params->user, $params->pass, $options)
|
|
|
|
: new $driver($dsn, '', '', $options);
|
2014-03-31 12:47:07 -04:00
|
|
|
|
|
|
|
// Set the table prefix, if it exists
|
|
|
|
if (isset($params->prefix))
|
|
|
|
{
|
2016-10-13 21:55:23 -04:00
|
|
|
$db->setTablePrefix($params->prefix);
|
2014-03-31 12:47:07 -04:00
|
|
|
}
|
|
|
|
|
2014-04-23 15:53:16 -04:00
|
|
|
// Create Query Builder object
|
2015-11-10 10:12:23 -05:00
|
|
|
$conn = new QueryBuilder($db, new QueryParser($db));
|
2014-04-23 15:53:16 -04:00
|
|
|
|
2014-03-31 12:47:07 -04:00
|
|
|
|
|
|
|
// Save it for later
|
|
|
|
if (isset($params->alias))
|
|
|
|
{
|
|
|
|
$this->connections[$params->alias] = $conn;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$this->connections[] = $conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parses params into a dsn and option array
|
|
|
|
*
|
2015-07-17 16:01:41 -04:00
|
|
|
* @param \stdClass $params
|
2018-01-26 08:39:30 -05:00
|
|
|
* @return object|array
|
2018-01-26 15:45:46 -05:00
|
|
|
* @throws Exception\BadDBDriverException
|
2014-03-31 12:47:07 -04:00
|
|
|
*/
|
2018-01-26 08:39:30 -05:00
|
|
|
public function parseParams($params): array
|
2014-04-03 13:28:30 -04:00
|
|
|
{
|
2018-01-26 08:39:30 -05:00
|
|
|
$params = (object) $params;
|
2014-03-31 12:47:07 -04:00
|
|
|
$params->type = strtolower($params->type);
|
|
|
|
$dbtype = ($params->type !== 'postgresql') ? $params->type : 'pgsql';
|
2015-07-16 16:56:13 -04:00
|
|
|
$dbtype = ucfirst($dbtype);
|
2014-03-31 12:47:07 -04:00
|
|
|
|
|
|
|
// Make sure the class exists
|
2015-07-16 16:56:13 -04:00
|
|
|
if ( ! class_exists("\\Query\\Drivers\\{$dbtype}\\Driver"))
|
2014-03-31 12:47:07 -04:00
|
|
|
{
|
2018-01-26 15:45:46 -05:00
|
|
|
throw new Exception\BadDBDriverException('Database driver does not exist, or is not supported');
|
2014-03-31 12:47:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set additional PDO options
|
2016-09-07 13:10:03 -04:00
|
|
|
$options = [];
|
2014-03-31 12:47:07 -04:00
|
|
|
|
|
|
|
if (isset($params->options))
|
|
|
|
{
|
|
|
|
$options = (array) $params->options;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the dsn for the database to connect to
|
2018-01-23 11:29:43 -05:00
|
|
|
if(strtolower($dbtype) === 'sqlite')
|
2015-07-17 16:01:41 -04:00
|
|
|
{
|
|
|
|
$dsn = $params->file;
|
|
|
|
}
|
2015-07-17 15:38:06 -04:00
|
|
|
else
|
|
|
|
{
|
2016-10-13 21:55:23 -04:00
|
|
|
$dsn = $this->createDsn($dbtype, $params);
|
2015-07-17 15:38:06 -04:00
|
|
|
}
|
|
|
|
|
2014-03-31 12:47:07 -04:00
|
|
|
|
2016-09-07 13:10:03 -04:00
|
|
|
return [$dsn, $dbtype, $params, $options];
|
2014-03-31 12:47:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create the dsn from the db type and params
|
|
|
|
*
|
2018-01-24 13:14:03 -05:00
|
|
|
* @codeCoverageIgnore
|
2014-03-31 12:47:07 -04:00
|
|
|
* @param string $dbtype
|
2018-01-26 08:39:30 -05:00
|
|
|
* @param array|object $params
|
2014-03-31 12:47:07 -04:00
|
|
|
* @return string
|
|
|
|
*/
|
2018-01-26 08:39:30 -05:00
|
|
|
private function createDsn(string $dbtype, $params): string
|
2014-03-31 12:47:07 -04:00
|
|
|
{
|
2016-09-07 13:10:03 -04:00
|
|
|
$pairs = [];
|
2014-04-01 15:41:38 -04:00
|
|
|
|
2015-07-17 16:01:41 -04:00
|
|
|
if ( ! empty($params->database))
|
|
|
|
{
|
2016-09-07 13:10:03 -04:00
|
|
|
$pairs[] = implode('=', ['dbname', $params->database]);
|
2015-07-17 16:01:41 -04:00
|
|
|
}
|
2014-03-31 12:47:07 -04:00
|
|
|
|
2016-09-07 13:10:03 -04:00
|
|
|
$skip = [
|
2015-07-17 16:01:41 -04:00
|
|
|
'name' => 'name',
|
|
|
|
'pass' => 'pass',
|
|
|
|
'user' => 'user',
|
|
|
|
'type' => 'type',
|
|
|
|
'prefix' => 'prefix',
|
|
|
|
'options' => 'options',
|
|
|
|
'database' => 'database',
|
|
|
|
'alias' => 'alias'
|
2016-09-07 13:10:03 -04:00
|
|
|
];
|
2015-07-17 16:01:41 -04:00
|
|
|
|
|
|
|
foreach($params as $key => $val)
|
|
|
|
{
|
2018-01-23 11:29:43 -05:00
|
|
|
if (( ! array_key_exists($key, $skip)) && ! empty($val))
|
2014-03-31 12:47:07 -04:00
|
|
|
{
|
2016-09-07 13:10:03 -04:00
|
|
|
$pairs[] = implode('=', [$key, $val]);
|
2014-03-31 12:47:07 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-20 15:24:21 -04:00
|
|
|
return strtolower($dbtype) . ':' . implode(';', $pairs);
|
2014-03-31 12:47:07 -04:00
|
|
|
}
|
2016-10-13 21:55:23 -04:00
|
|
|
}
|