Created
December 1, 2017 05:27
-
-
Save pentagonal/f57994f4568813caf05ba56d7ddf6bee to your computer and use it in GitHub Desktop.
Phalcon Database Class Setup for confusing configuration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* MIT License | |
* | |
* Copyright (c) 2017, Pentagonal | |
* | |
* 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 NON INFRINGEMENT. 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. | |
*/ | |
namespace MyApplication; | |
use Phalcon\Config; | |
use Phalcon\Db; | |
/** @noinspection PhpHierarchyChecksInspection */ | |
/** | |
* Class Database | |
* @package MyApplication | |
* | |
* @mixin Db\AdapterInterface | |
*/ | |
class Database extends Db | |
{ | |
/** | |
* Default Adapter | |
*/ | |
const ADAPTER_DEFAULT = self::ADAPTER_MYSQL; | |
const | |
DB_HOST = 'host', | |
DB_USER = 'username', | |
DB_NAME = 'dbname', | |
DB_PORT = 'port', | |
DB_PASSWORD = 'password', | |
DB_ADAPTER = 'adapter', | |
DB_DRIVER = self::DB_ADAPTER, | |
DB_OPTION = 'options', | |
DB_SCHEMA = 'schema', | |
DB_PERSISTENT = 'persistent'; | |
const | |
ADAPTER_MYSQL = 'mysql', | |
ADAPTER_PGSQL = 'postgresql', | |
ADAPTER_SQLITE = 'sqlite'; | |
/** | |
* @var array | |
*/ | |
private static $databasePortDefault = [ | |
self::ADAPTER_MYSQL => 3306, | |
self::ADAPTER_PGSQL => 5432, | |
self::ADAPTER_SQLITE => null, | |
]; | |
/** | |
* @var Db\AdapterInterface | |
*/ | |
private $db; | |
/** | |
* Database constructor. | |
* | |
* @param array|Config $options | |
*/ | |
public function __construct($options) | |
{ | |
if ($options instanceof Config) { | |
$options = $options->toArray(); | |
} | |
if (!is_array($options)) { | |
throw new \InvalidArgumentException( | |
"Options must be as array or config", | |
E_WARNING | |
); | |
} | |
$this->db = $this->createFromOptions($options); | |
} | |
/** | |
* @return Db\AdapterInterface | |
*/ | |
public function getDb() : Db\AdapterInterface | |
{ | |
return $this->db; | |
} | |
/** | |
* @param array $options | |
* | |
* @return Db\AdapterInterface | |
*/ | |
public static function createFromOptions(array $options) : Db\AdapterInterface | |
{ | |
return Db\Adapter\Pdo\Factory::load( | |
static::configureForOptions($options) | |
); | |
} | |
/** | |
* @param array $options | |
* | |
* @return array | |
*/ | |
public static function configureForOptions(array $options) : array | |
{ | |
$configDefaults = [ | |
self::DB_HOST => 'string', | |
self::DB_USER => 'string', | |
self::DB_NAME => 'string', | |
self::DB_PORT => 'numeric', | |
self::DB_PASSWORD => false, | |
self::DB_DRIVER => 'string', | |
self::DB_OPTION => 'array', | |
self::DB_SCHEMA => 'string', | |
self::DB_PERSISTENT => 'bool', | |
]; | |
// parse password | |
if (!isset($options[self::DB_PASSWORD])) { | |
$array = [ | |
"pass", | |
"dbpass", | |
"dbPass", | |
"dbpassword", | |
"dbPassword", | |
"databasepass", | |
"databasePass", | |
"databasepassword", | |
"databasePassword" | |
]; | |
foreach ($array as $selection) { | |
if (array_key_exists($selection, $options)) { | |
$options[self::DB_PASSWORD] = $options[$selection]; | |
unset($options[$selection]); | |
break; | |
} | |
} | |
} | |
// parse persistent | |
if (!isset($options[self::DB_PERSISTENT])) { | |
$array = [ | |
"dbpersistent", | |
"db.persistent", | |
"databasepersistent", | |
"database.persistent", | |
]; | |
foreach ($array as $selection) { | |
if (array_key_exists($selection, $options)) { | |
$options[self::DB_PERSISTENT] = (bool) $options[$selection]; | |
unset($options[$selection]); | |
break; | |
} | |
} | |
} | |
if (array_key_exists(self::DB_PERSISTENT, $options)) { | |
$options[self::DB_PERSISTENT] = (bool) $options[self::DB_PERSISTENT]; | |
} | |
// parse database name | |
if (!isset($options[self::DB_NAME])) { | |
$array = [ | |
"dbName", | |
"name", | |
"databaseName", | |
"databasename", | |
"database.name", | |
"database", | |
"path", | |
"dbPath", | |
"dbpath", | |
"db.path", | |
"databasePath", | |
"databasepath", | |
"database.path" | |
]; | |
foreach ($array as $selection) { | |
if (array_key_exists($selection, $options)) { | |
$options[self::DB_NAME] = $options[$selection]; | |
unset($options[$selection]); | |
break; | |
} | |
} | |
} | |
if (!isset($options[self::DB_DRIVER])) { | |
$array = [ | |
"driver", | |
"dbAdapter", | |
"dbadapter", | |
"dbDriver", | |
"dbdriver", | |
"databaseAdapter", | |
"databaseadapter", | |
"databaseDriver", | |
"databasedriver", | |
]; | |
foreach ($array as $selection) { | |
if (array_key_exists($selection, $options)) { | |
$options[self::DB_DRIVER] = $options[$selection]; | |
unset($options[$selection]); | |
break; | |
} | |
} | |
} | |
if (!isset($options[self::DB_PORT])) { | |
$array = [ | |
"port", | |
"dbport", | |
"dbPort", | |
"databasePort", | |
"databaseport", | |
]; | |
foreach ($array as $selection) { | |
if (array_key_exists($selection, $options)) { | |
$options[self::DB_DRIVER] = $options[$selection]; | |
unset($options[$selection]); | |
break; | |
} | |
} | |
} | |
if (!isset($options[self::DB_DRIVER]) || !$options[self::DB_DRIVER]) { | |
$options[self::DB_DRIVER] = self::ADAPTER_DEFAULT; | |
} | |
$options[self::DB_DRIVER] = self::sanityAdapter($options[self::DB_DRIVER]); | |
if (!isset($options[self::DB_PORT]) || ! $options[self::DB_PORT]) { | |
$options[self::DB_PORT] = self::$databasePortDefault[$options[self::DB_DRIVER]]; | |
} | |
$options[self::DB_PORT] = $options[self::DB_PORT] === null ? null : abs($options[self::DB_PORT]); | |
if (!is_null($options[self::DB_PORT]) && (!is_int(abs($options[self::DB_PORT])) || $options[self::DB_PORT] < 0)) { | |
throw new \InvalidArgumentException( | |
'Database port is not valid. Database port could not contain float number or negative value' | |
); | |
} | |
$currentUserParams = []; | |
foreach($options as $key => $value) { | |
if ($key === self::DB_PASSWORD) { | |
unset($configDefaults[$key]); | |
$currentUserParams[$key] = ""; | |
if (!$value) { | |
continue; | |
} | |
if (is_bool($value) || is_string($value)) { | |
$currentUserParams[$key] = (string) $value; | |
continue; | |
} | |
throw new \InvalidArgumentException( | |
sprintf( | |
"Config for password is invalid. Password must be as a string %s given", | |
gettype($value) | |
) | |
); | |
continue; | |
} | |
if (isset($configDefaults[$key])) { | |
$fn = "is_{$configDefaults[$key]}"; | |
unset($configDefaults[$key]); | |
if (!$fn($value)) { | |
throw new \InvalidArgumentException( | |
sprintf( | |
"Config for password is invalid. Password must be as a {$fn} %s given", | |
gettype($value) | |
) | |
); | |
} | |
$currentUserParams[$key] = $value; | |
} | |
} | |
if (!isset($currentUserParams[self::DB_PASSWORD])) { | |
$currentUserParams[self::DB_PASSWORD] = ""; | |
} | |
if (isset($currentUserParams[self::DB_OPTION])) { | |
foreach ($currentUserParams[self::DB_OPTION] as $key => $value) { | |
if (is_int($key)) { | |
continue; | |
} | |
unset($currentUserParams[self::DB_OPTION][$key]); | |
if (is_string($key)) { | |
if (defined($key)) { | |
$key = constant($key); | |
if (is_int($key)) { | |
$currentUserParams[self::DB_OPTION][] = $value; | |
} | |
} | |
continue; | |
} | |
} | |
} | |
if (!isset($currentUserParams[self::DB_NAME])) { | |
throw new \InvalidArgumentException( | |
"Db Name has not been declared yet.", | |
E_USER_WARNING | |
); | |
} | |
return $currentUserParams; | |
} | |
/** | |
* @param string $adapterName | |
* | |
* @return string | |
*/ | |
public static function sanityAdapter(string $adapterName) : string | |
{ | |
$selectedAdapter = static::ADAPTER_DEFAULT; | |
$default = [ | |
'mysql' => self::ADAPTER_MYSQL, | |
'postgresql' => self::ADAPTER_PGSQL, | |
'sqlite' => self::ADAPTER_SQLITE | |
]; | |
preg_match('~ | |
(?P<sqlite>s?q?li?te) | |
| (?P<postgresql>po?s?t?g) | |
|(?P<mysql>my(?:sql)?) | |
~ix', $adapterName, $match); | |
foreach ((array) $match as $key => $value) { | |
if (is_string($key) && ! empty($value)) { | |
$selectedAdapter = $default[$key]; | |
break; | |
} | |
} | |
return $selectedAdapter; | |
} | |
/** | |
* @param string $name | |
* @param array $arguments | |
* | |
* @return mixed | |
*/ | |
public function __call(string $name, array $arguments) | |
{ | |
return call_user_func_array([$this->db, $name], $arguments); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment