2016-04-12 19:31:39 +02:00
|
|
|
<?php
|
|
|
|
|
2018-03-04 09:34:19 +01:00
|
|
|
namespace PHPCensor;
|
|
|
|
|
2016-04-12 19:31:39 +02:00
|
|
|
class Database extends \PDO
|
|
|
|
{
|
2018-02-28 14:53:21 +01:00
|
|
|
const MYSQL_TYPE = 'mysql';
|
|
|
|
const POSTGRESQL_TYPE = 'pgsql';
|
|
|
|
|
2018-02-28 17:34:07 +01:00
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $type = 'read';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var boolean
|
|
|
|
*/
|
2016-04-20 12:30:26 +02:00
|
|
|
protected static $initialised = false;
|
2018-02-28 17:34:07 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected static $servers = [
|
|
|
|
'read' => [],
|
|
|
|
'write' => []
|
|
|
|
];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected static $connections = [
|
|
|
|
'read' => null,
|
|
|
|
'write' => null
|
|
|
|
];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected static $dsn = [
|
|
|
|
'read' => '',
|
|
|
|
'write' => ''
|
|
|
|
];
|
|
|
|
|
|
|
|
protected static $details = [];
|
2016-04-20 12:30:26 +02:00
|
|
|
|
2017-04-16 16:18:21 +02:00
|
|
|
/**
|
|
|
|
* @param string $table
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function lastInsertIdExtended($table = null)
|
|
|
|
{
|
2018-02-28 14:53:21 +01:00
|
|
|
if ($table && self::POSTGRESQL_TYPE === $this->getAttribute(self::ATTR_DRIVER_NAME)) {
|
2018-03-01 11:18:59 +01:00
|
|
|
return parent::lastInsertId('"' . $table . '_id_seq"');
|
2017-04-16 16:18:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return parent::lastInsertId();
|
|
|
|
}
|
|
|
|
|
2016-04-20 12:30:26 +02:00
|
|
|
protected static function init()
|
|
|
|
{
|
2016-08-11 16:32:42 +02:00
|
|
|
$config = Config::getInstance();
|
2016-04-20 12:30:26 +02:00
|
|
|
$settings = $config->get('b8.database', []);
|
2016-08-11 16:32:42 +02:00
|
|
|
|
|
|
|
self::$servers['read'] = $settings['servers']['read'];
|
2016-04-20 12:30:26 +02:00
|
|
|
self::$servers['write'] = $settings['servers']['write'];
|
2018-02-28 14:53:21 +01:00
|
|
|
|
2018-02-28 17:34:07 +01:00
|
|
|
self::$details['driver'] = $settings['type'];
|
|
|
|
self::$details['db'] = $settings['name'];
|
|
|
|
self::$details['user'] = $settings['username'];
|
|
|
|
self::$details['pass'] = $settings['password'];
|
2017-01-29 03:49:43 +01:00
|
|
|
|
2016-04-20 12:30:26 +02:00
|
|
|
self::$initialised = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $type
|
|
|
|
*
|
2018-03-04 09:34:19 +01:00
|
|
|
* @return Database
|
2017-11-05 15:48:36 +01:00
|
|
|
*
|
2016-04-20 12:30:26 +02:00
|
|
|
* @throws \Exception
|
|
|
|
*/
|
|
|
|
public static function getConnection($type = 'read')
|
|
|
|
{
|
|
|
|
if (!self::$initialised) {
|
|
|
|
self::init();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_null(self::$connections[$type])) {
|
2017-01-29 03:49:43 +01:00
|
|
|
// Shuffle, so we pick a random server:
|
|
|
|
$servers = self::$servers[$type];
|
|
|
|
shuffle($servers);
|
2016-04-20 12:30:26 +02:00
|
|
|
|
|
|
|
$connection = null;
|
|
|
|
|
|
|
|
// Loop until we get a working connection:
|
|
|
|
while (count($servers)) {
|
|
|
|
// Pull the next server:
|
|
|
|
$server = array_shift($servers);
|
|
|
|
|
2018-02-28 17:34:07 +01:00
|
|
|
self::$dsn[$type] = self::$details['driver'] . ':host=' . $server['host'];
|
2017-01-29 03:49:43 +01:00
|
|
|
if (isset($server['port'])) {
|
2018-02-28 17:34:07 +01:00
|
|
|
self::$dsn[$type] .= ';port=' . (integer)$server['port'];
|
2016-04-20 12:30:26 +02:00
|
|
|
}
|
2018-02-28 17:34:07 +01:00
|
|
|
self::$dsn[$type] .= ';dbname=' . self::$details['db'];
|
2016-04-20 12:30:26 +02:00
|
|
|
|
2017-05-29 13:50:18 +02:00
|
|
|
$pdoOptions = [
|
2018-02-28 17:34:07 +01:00
|
|
|
\PDO::ATTR_PERSISTENT => false,
|
|
|
|
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
|
|
|
|
\PDO::ATTR_TIMEOUT => 2,
|
2017-05-29 13:50:18 +02:00
|
|
|
];
|
2018-02-28 17:34:07 +01:00
|
|
|
if (self::MYSQL_TYPE === self::$details['driver']) {
|
2017-05-29 13:50:18 +02:00
|
|
|
$pdoOptions[\PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES 'UTF8'";
|
|
|
|
}
|
|
|
|
|
2016-04-20 12:30:26 +02:00
|
|
|
// Try to connect:
|
|
|
|
try {
|
2017-01-29 03:49:43 +01:00
|
|
|
$connection = new self(
|
2018-02-28 17:34:07 +01:00
|
|
|
self::$dsn[$type],
|
2016-04-20 12:30:26 +02:00
|
|
|
self::$details['user'],
|
|
|
|
self::$details['pass'],
|
2017-05-29 13:50:18 +02:00
|
|
|
$pdoOptions
|
2017-01-29 03:49:43 +01:00
|
|
|
);
|
2018-02-28 17:34:07 +01:00
|
|
|
$connection->setType($type);
|
2016-04-20 12:30:26 +02:00
|
|
|
} catch (\PDOException $ex) {
|
|
|
|
$connection = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Opened a connection? Break the loop:
|
|
|
|
if ($connection) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// No connection? Oh dear.
|
2018-02-28 12:37:22 +01:00
|
|
|
if (!$connection && $type === 'read') {
|
2016-04-20 12:30:26 +02:00
|
|
|
throw new \Exception('Could not connect to any ' . $type . ' servers.');
|
|
|
|
}
|
|
|
|
|
|
|
|
self::$connections[$type] = $connection;
|
|
|
|
}
|
|
|
|
|
|
|
|
return self::$connections[$type];
|
|
|
|
}
|
|
|
|
|
2018-02-28 14:53:21 +01:00
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
2016-04-20 12:30:26 +02:00
|
|
|
public function getDetails()
|
|
|
|
{
|
|
|
|
return self::$details;
|
|
|
|
}
|
2016-04-12 19:31:39 +02:00
|
|
|
|
2018-02-28 17:34:07 +01:00
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getDsn()
|
|
|
|
{
|
|
|
|
return self::$dsn[$this->type];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $type
|
|
|
|
*/
|
|
|
|
public function setType($type)
|
|
|
|
{
|
|
|
|
$this->type = $type;
|
|
|
|
}
|
|
|
|
|
2016-04-12 19:31:39 +02:00
|
|
|
public static function reset()
|
|
|
|
{
|
2016-04-20 12:30:26 +02:00
|
|
|
self::$connections = ['read' => null, 'write' => null];
|
2016-04-12 19:31:39 +02:00
|
|
|
self::$initialised = false;
|
|
|
|
}
|
2017-01-29 03:49:43 +01:00
|
|
|
|
2018-02-28 14:53:21 +01:00
|
|
|
/**
|
|
|
|
* @param string $statement
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
protected function quoteNames($statement)
|
2017-01-29 03:49:43 +01:00
|
|
|
{
|
|
|
|
$quote = '';
|
2018-02-28 17:34:07 +01:00
|
|
|
if (self::MYSQL_TYPE === self::$details['driver']) {
|
2017-01-29 03:49:43 +01:00
|
|
|
$quote = '`';
|
2018-02-28 17:34:07 +01:00
|
|
|
} elseif (self::POSTGRESQL_TYPE === self::$details['driver']) {
|
2017-01-29 03:49:43 +01:00
|
|
|
$quote = '"';
|
|
|
|
}
|
2018-01-18 15:51:33 +01:00
|
|
|
|
2018-02-28 14:53:21 +01:00
|
|
|
return preg_replace('/{{(.*?)}}/', ($quote . '\1' . $quote), $statement);
|
|
|
|
}
|
2017-01-29 03:49:43 +01:00
|
|
|
|
2018-02-28 14:53:21 +01:00
|
|
|
/**
|
|
|
|
* @param string $statement
|
2018-03-08 04:54:52 +01:00
|
|
|
* @param array $driverOptions
|
2018-02-28 14:53:21 +01:00
|
|
|
*
|
|
|
|
* @return \PDOStatement
|
|
|
|
*/
|
2018-03-08 04:54:52 +01:00
|
|
|
public function prepareCommon($statement, array $driverOptions = [])
|
2018-02-28 14:53:21 +01:00
|
|
|
{
|
2018-03-08 04:54:52 +01:00
|
|
|
return parent::prepare($this->quoteNames($statement), $driverOptions);
|
2017-01-29 03:49:43 +01:00
|
|
|
}
|
2016-04-12 19:31:39 +02:00
|
|
|
}
|