misuzu/src/Database.php

153 lines
4.4 KiB
PHP
Raw Normal View History

2018-01-03 20:50:29 +01:00
<?php
namespace Misuzu;
use Misuzu\Config\ConfigManager;
2018-04-30 23:39:43 +02:00
use PDO;
use InvalidArgumentException;
2018-01-03 20:50:29 +01:00
2018-04-30 23:39:43 +02:00
final class Database
2018-01-03 20:50:29 +01:00
{
/**
2018-04-30 23:39:43 +02:00
* Array of supported abstraction layers.
*/
2018-04-30 23:39:43 +02:00
private const SUPPORTED = [
2018-01-03 20:50:29 +01:00
'mysql',
'sqlite',
];
2018-04-30 23:39:43 +02:00
/**
* Default hostname.
*/
private const DEFAULT_HOST = '127.0.0.1';
/**
* The default port for MySQL.
*/
private const DEFAULT_PORT_MYSQL = 3306;
/**
2018-04-30 23:39:43 +02:00
* @var Database
*/
2018-04-30 23:39:43 +02:00
private static $instance;
/**
2018-04-30 23:39:43 +02:00
* @var PDO[]
*/
2018-04-30 23:39:43 +02:00
private $connections = [];
/**
2018-04-30 23:39:43 +02:00
* @var ConfigManager
*/
2018-04-30 23:39:43 +02:00
private $configManager;
/**
2018-04-30 23:39:43 +02:00
* @var string
*/
2018-04-30 23:39:43 +02:00
private $default;
public static function getInstance(): Database
{
if (!(self::$instance instanceof static)) {
throw new \UnexpectedValueException('No instance of Database exists yet.');
}
return self::$instance;
}
2018-01-03 20:50:29 +01:00
public function __construct(
ConfigManager $config,
2018-04-30 23:39:43 +02:00
string $default = 'default'
2018-01-03 20:50:29 +01:00
) {
2018-04-30 23:39:43 +02:00
if (self::$instance instanceof static) {
throw new \UnexpectedValueException('Only one instance of Database may exist.');
}
2018-01-03 20:50:29 +01:00
2018-04-30 23:39:43 +02:00
self::$instance = $this;
$this->default = $default;
$this->configManager = $config;
}
2018-01-03 20:50:29 +01:00
2018-04-30 23:39:43 +02:00
public static function connection(?string $name = null): PDO
{
return self::getInstance()->getConnection($name);
}
2018-01-03 20:50:29 +01:00
2018-04-30 23:39:43 +02:00
public function getConnection(?string $name = null): PDO
{
$name = $name ?? $this->default;
return $this->connections[$name] ?? $this->addConnection($name);
2018-01-03 20:50:29 +01:00
}
2018-04-30 23:39:43 +02:00
public function addConnection(string $name): PDO
2018-01-03 20:50:29 +01:00
{
2018-04-30 23:39:43 +02:00
$section = "Database.{$name}";
2018-01-03 20:50:29 +01:00
if (!$this->configManager->contains($section, 'driver')) {
throw new InvalidArgumentException('Config section not found!');
2018-01-03 20:50:29 +01:00
}
$driver = $this->configManager->get($section, 'driver');
2018-04-30 23:39:43 +02:00
if (!in_array($driver, self::SUPPORTED)) {
throw new InvalidArgumentException('Unsupported driver.');
2018-01-03 20:50:29 +01:00
}
2018-04-30 23:39:43 +02:00
$dsn = $driver . ':';
$options = [
PDO::ATTR_CASE => PDO::CASE_NATURAL,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::ATTR_EMULATE_PREPARES => false,
2018-01-03 20:50:29 +01:00
];
switch ($driver) {
2018-04-30 23:39:43 +02:00
case 'sqlite':
if ($this->configManager->get($section, 'memory', 'bool', false)) {
$dsn .= ':memory:';
} else {
$databasePath = realpath(
$this->configManager->get($section, 'database', 'string', __DIR__ . '/../store/misuzu.db')
);
if ($databasePath === false) {
throw new \UnexpectedValueException("Database does not exist.");
}
$dsn .= $databasePath . ';';
}
2018-01-03 20:50:29 +01:00
break;
2018-04-30 23:39:43 +02:00
case 'mysql':
2018-01-03 20:50:29 +01:00
$is_unix_socket = $this->configManager->contains($section, 'unix_socket');
2018-04-30 23:39:43 +02:00
if ($is_unix_socket) {
$dsn .= 'unix_socket=' . $this->configManager->get($section, 'unix_socket', 'string') . ';';
} else {
$dsn .= 'host=' . $this->configManager->get($section, 'host', 'string', self::DEFAULT_HOST) . ';';
$dsn .= 'port=' . $this->configManager->get($section, 'port', 'int', self::DEFAULT_PORT_MYSQL) . ';';
}
2018-01-03 20:50:29 +01:00
2018-04-30 23:39:43 +02:00
$dsn .= 'charset=' . (
$this->configManager->contains($section, 'charset')
? $this->configManager->get($section, 'charset', 'string')
: 'utf8mb4'
) . ';';
2018-01-03 20:50:29 +01:00
2018-04-30 23:39:43 +02:00
$dsn .= 'dbname=' . $this->configManager->get($section, 'database', 'string', 'misuzu') . ';';
2018-01-03 20:50:29 +01:00
2018-05-16 04:58:21 +02:00
$options[PDO::MYSQL_ATTR_INIT_COMMAND] = "SET SESSION sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'";
2018-01-03 20:50:29 +01:00
break;
}
2018-04-30 23:39:43 +02:00
$connection = new PDO(
$dsn,
$this->configManager->get($section, 'username', 'string', null),
$this->configManager->get($section, 'password', 'string', null),
$options
);
return $this->connections[$name] = $connection;
2018-01-03 20:50:29 +01:00
}
}