- fixed DB setup error: "`system`.`description` can´t have a default value", closed #701 - upgraded "lazyload" js lib `v1.9.5` → `v1.9.7` - upgraded multiple 3rd party NPM dependencies for Gulp build
292 lines
8.2 KiB
PHP
292 lines
8.2 KiB
PHP
<?php
|
|
/**
|
|
* Created by PhpStorm.
|
|
* User: exodus4d
|
|
* Date: 30.07.2015
|
|
* Time: 15:55
|
|
*/
|
|
|
|
namespace DB;
|
|
use controller\LogController;
|
|
use lib\Config;
|
|
|
|
class Database extends \Prefab {
|
|
|
|
/**
|
|
* if true, errors will not get logged
|
|
* @var bool
|
|
*/
|
|
private $silent = false;
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
private $errors = [];
|
|
|
|
/**
|
|
* connect to the DB server itself -> NO database is used
|
|
* -> can be used to check if a certain DB exists without connecting to it directly
|
|
* @param string $dbKey
|
|
* @return SQL|null
|
|
*/
|
|
public function connectToServer(string $dbKey = 'PF'){
|
|
$dbConfig = Config::getDatabaseConfig($dbKey);
|
|
$dbConfig['DNS'] = str_replace(';dbname=', '', $dbConfig['DNS'] );
|
|
$dbConfig['NAME'] = '';
|
|
return call_user_func_array([$this, 'connect'], $dbConfig);
|
|
}
|
|
|
|
/**
|
|
* tries to create a database if not exists
|
|
* -> DB user needs rights to create a DB
|
|
* @param string $dbKey
|
|
* @return SQL|null
|
|
*/
|
|
public function createDB(string $dbKey = 'PF'){
|
|
$db = null;
|
|
$dbConfig = Config::getDatabaseConfig($dbKey);
|
|
// remove database from $dsn (we want to crate it)
|
|
$newDbName = $dbConfig['NAME'];
|
|
if(!empty($newDbName)){
|
|
$dbConfig['NAME'] = '';
|
|
$dbConfig['DNS'] = str_replace(';dbname=', '', $dbConfig['DNS'] );
|
|
|
|
$db = call_user_func_array([$this, 'connect'], $dbConfig);
|
|
|
|
if(!is_null($db)){
|
|
$schema = new SQL\Schema($db);
|
|
if(!in_array($newDbName, $schema->getDatabases())){
|
|
$db->exec("CREATE DATABASE IF NOT EXISTS
|
|
`" . $newDbName . "` DEFAULT CHARACTER SET utf8
|
|
COLLATE utf8_general_ci;");
|
|
$db->exec("USE `" . $newDbName . "`");
|
|
|
|
// check if DB create was successful
|
|
$dbCheck = $db->exec("SELECT DATABASE()");
|
|
if(
|
|
!empty($dbCheck[0]) &&
|
|
!empty($checkDbName = reset($dbCheck[0])) &&
|
|
$checkDbName == $newDbName
|
|
){
|
|
self::prepareDBConnection($db);
|
|
self::prepareDatabase($db);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $db;
|
|
}
|
|
|
|
/**
|
|
* get database
|
|
* @param string $dbKey
|
|
* @return SQL|null
|
|
*/
|
|
public function getDB(string $dbKey = 'PF'){
|
|
$f3 = \Base::instance();
|
|
// "Hive" Key for DB object cache
|
|
$dbHiveKey = $this->getDbHiveKey($dbKey);
|
|
if( !$f3->exists($dbHiveKey, $db) ){
|
|
$dbConfig = Config::getDatabaseConfig($dbKey);
|
|
$db = call_user_func_array([$this, 'connect'], $dbConfig);
|
|
if(!is_null($db)){
|
|
self::prepareDBConnection($db);
|
|
$f3->set($dbHiveKey, $db);
|
|
}
|
|
}
|
|
|
|
return $db;
|
|
}
|
|
|
|
/**
|
|
* get a unique hive key for each DB connection
|
|
* @param $dbKey
|
|
* @return string
|
|
*/
|
|
protected function getDbHiveKey($dbKey){
|
|
return 'DB_' . $dbKey;
|
|
}
|
|
|
|
/**
|
|
* connect to a database
|
|
* @param string $dns
|
|
* @param string $name
|
|
* @param string $user
|
|
* @param string $password
|
|
* @param string $alias
|
|
* @return SQL|null
|
|
*/
|
|
protected function connect($dns, $name, $user, $password, $alias){
|
|
$db = null;
|
|
$f3 = \Base::instance();
|
|
|
|
$options = [
|
|
\PDO::MYSQL_ATTR_COMPRESS => true,
|
|
\PDO::ATTR_TIMEOUT => \Base::instance()->get('REQUIREMENTS.MYSQL.PDO_TIMEOUT'),
|
|
];
|
|
|
|
// set ERRMODE depending on pathfinders global DEBUG level
|
|
if($f3->get('DEBUG') >= 3){
|
|
$options[\PDO::ATTR_ERRMODE] = \PDO::ERRMODE_WARNING;
|
|
}else{
|
|
$options[\PDO::ATTR_ERRMODE] = \PDO::ERRMODE_EXCEPTION;
|
|
}
|
|
|
|
try {
|
|
$db = new SQL(
|
|
$dns . $name,
|
|
$user,
|
|
$password,
|
|
$options
|
|
);
|
|
}catch(\PDOException $e){
|
|
$this->pushError($alias, $e);
|
|
if(!$this->isSilent()){
|
|
self::getLogger()->write($e);
|
|
}
|
|
}
|
|
|
|
return $db;
|
|
}
|
|
|
|
/**
|
|
* get all table names from a DB
|
|
* @param string $dbKey
|
|
* @return array|bool
|
|
*/
|
|
public function getTables($dbKey = 'PF'){
|
|
$schema = new SQL\Schema( $this->getDB($dbKey) );
|
|
return $schema->getTables();
|
|
}
|
|
|
|
/**
|
|
* checks whether a table exists on a DB or not
|
|
* @param $table
|
|
* @param string $dbKey
|
|
* @return bool
|
|
*/
|
|
public function tableExists($table, $dbKey = 'PF'){
|
|
$tableNames = $this->getTables($dbKey);
|
|
return in_array($table, $tableNames);
|
|
}
|
|
|
|
/**
|
|
* get current row (data) count for an existing table
|
|
* -> returns 0 if table not exists or empty
|
|
* @param $table
|
|
* @param string $dbKey
|
|
* @return int
|
|
*/
|
|
public function getRowCount($table, $dbKey = 'PF') {
|
|
$count = 0;
|
|
if( $this->tableExists($table, $dbKey) ){
|
|
$db = $this->getDB($dbKey);
|
|
$countRes = $db->exec("SELECT COUNT(*) `num` FROM " . $db->quotekey($table));
|
|
if(isset($countRes[0]['num'])){
|
|
$count = (int)$countRes[0]['num'];
|
|
}
|
|
}
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
public function isSilent() : bool{
|
|
return $this->silent;
|
|
}
|
|
|
|
/**
|
|
* set "silent" mode (no error logging)
|
|
* -> optional clear $this->errors
|
|
* @param bool $silent
|
|
* @param bool $clearErrors
|
|
*/
|
|
public function setSilent(bool $silent, bool $clearErrors = false){
|
|
$this->silent = $silent;
|
|
if($clearErrors){
|
|
$this->errors = [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* push new Exception into static error history
|
|
* @param string $alias
|
|
* @param \PDOException $e
|
|
*/
|
|
protected function pushError(string $alias, \PDOException $e){
|
|
if(!is_array($this->errors[$alias])){
|
|
$this->errors[$alias] = [];
|
|
}
|
|
|
|
// prevent adding same errors twice
|
|
if(!empty($this->errors[$alias])){
|
|
$lastError = array_values($this->errors[$alias])[0];
|
|
if($lastError->getMessage() === $e->getMessage()){
|
|
return;
|
|
}
|
|
}
|
|
|
|
array_unshift($this->errors[$alias], $e);
|
|
if(count($this->errors[$alias]) > 5){
|
|
$this->errors[$alias] = array_pop($this->errors[$alias]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* get last recent Exceptions from error history
|
|
* @param string $alias
|
|
* @param int $limit
|
|
* @return \PDOException[]
|
|
*/
|
|
public function getErrors(string $alias, int $limit = 1){
|
|
return array_slice((array)$this->errors[$alias] , 0, $limit);
|
|
}
|
|
|
|
/**
|
|
* prepare current DB
|
|
* -> set session connection variables
|
|
* @param SQL $db
|
|
*/
|
|
public static function prepareDBConnection(SQL &$db){
|
|
// set DB timezone to UTC +00:00 (eve server time)
|
|
$db->exec('SET @@session.time_zone = "+00:00";');
|
|
|
|
// set default storage engine
|
|
$db->exec('SET @@session.default_storage_engine = "' .
|
|
self::getRequiredMySqlVariables('DEFAULT_STORAGE_ENGINE') . '"');
|
|
}
|
|
|
|
/**
|
|
* set some default config for current DB
|
|
* @param SQL $db
|
|
*/
|
|
public static function prepareDatabase(SQL &$db){
|
|
if($db->name()){
|
|
// set/change default "character set" and "collation"
|
|
$db->exec('ALTER DATABASE ' . $db->quotekey($db->name())
|
|
. ' CHARACTER SET ' . self::getRequiredMySqlVariables('CHARACTER_SET_DATABASE')
|
|
. ' COLLATE ' . self::getRequiredMySqlVariables('COLLATION_DATABASE')
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* get required MySQL variable value
|
|
* @param string $key
|
|
* @return string|null
|
|
*/
|
|
public static function getRequiredMySqlVariables(string $key){
|
|
\Base::instance()->exists('REQUIREMENTS[MYSQL][VARS][' . $key . ']', $data);
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* get logger for DB logging
|
|
* @return \Log
|
|
*/
|
|
static function getLogger(){
|
|
return LogController::getLogger('ERROR');
|
|
}
|
|
} |