Skip to content

Instantly share code, notes, and snippets.

@pentagonal
Created December 1, 2017 05:27
Show Gist options
  • Save pentagonal/f57994f4568813caf05ba56d7ddf6bee to your computer and use it in GitHub Desktop.
Save pentagonal/f57994f4568813caf05ba56d7ddf6bee to your computer and use it in GitHub Desktop.
Phalcon Database Class Setup for confusing configuration
<?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