Commit 7615a393 authored by Alex Ne's avatar Alex Ne

PDO MySQL Driver

parent d08d9af8
<?php
namespace X\Database;
use \X\ETrace\System as ESys;
class Credetional_ConfigurationArgumentsError extends ESys {}
class Credetional {
/**
* @var string
*/
protected $hostname = "localhost";
/**
* @var string
*/
protected $username = "root";
/**
* @var string
*/
protected $password = "";
/**
* @var string
*/
protected $database = "test";
/**
* @var string
*/
protected $charset = "utf8";
/**
* @var string
*/
protected $port = "3306";
# new Credetional(<database>)
# new Credetional(<username>,<password>,<database>)
# new Credetional(<hostname>,<username>,<password>,<database>)
# new Credetional(<hostname>,<username>,<password>,<database>,<charset>)
public function __construct() {
$data = func_get_args();
switch (count($data)) {
case 1:
$this->database = $data[0];
break;
case 3:
$this->username = $data[0];
$this->password = $data[1];
$this->database = $data[2];
break;
case 4:
$this->hostname = $data[0];
$this->username = $data[1];
$this->password = $data[2];
$this->database = $data[3];
break;
case 5:
$this->hostname = $data[0];
$this->username = $data[1];
$this->password = $data[2];
$this->database = $data[3];
$this->charset = $data[4];
break;
case 6:
$this->hostname = $data[0];
$this->username = $data[1];
$this->password = $data[2];
$this->database = $data[3];
$this->charset = $data[4];
$this->port = $data[5];
break;
default:
throw new Credetional_ConfigurationArgumentsError("Configuration Arguments Error", 1, ["args" => $data]);
break;
}
}
public function get_PDO_MySQL_DSN() {
return "mysql:host={$this->hostname};port={$this->port};dbname={$this->database}";
}
public function get_model() {
return [
"hostname" => $this->hostname,
"username" => $this->username,
"password" => $this->password,
"database" => $this->database,
"charset" => $this->charset,
"port" => $this->port,
];
}
/**
* @return mixed
*/
public function get_hostname() {
return $this->hostname;
}
/**
* @return mixed
*/
public function get_username() {
return $this->username;
}
/**
* @return mixed
*/
public function get_password() {
return $this->password;
}
/**
* @return mixed
*/
public function get_database() {
return $this->database;
}
/**
* @return mixed
*/
public function get_charset() {
return $this->charset;
}
/**
* @return mixed
*/
public function get_port() {
return $this->port;
}
}
?>
\ No newline at end of file
<?php
/**
* new PDO(\X\Database\Credetional)
*
* Functions:
* PDO() - PDO Driver
* query(string $SQL[,int $option = \PDO::FETCH_ASSOC]) - Simple query
* query_num(string $SQL) - alias to query() width $option = \PDO::FETCH_NUM
* insert(string $table, array $data[, bool $replace=false]) - insert Data
* replace(string $table, array $data) - alias to insert width $replace=true
* update(string $table, array $data, array $where) - update row or rows
*
*
* Where Examples:
* ["name1" => 1, "name2" => "data2"] --- WHERE name1 = 1 AND name2 = 'data2'
* ["[and]" => ["name1" => 1, "name2" => "data2"]] --- WHERE name1 = 1 AND name2 = 'data2'
* ["[or]" => ["name1" => 1, "name2" => "data2"]] --- WHERE name1 = 1 OR name2 = 'data2'
* ["[or]" => ["name||1" => 1, "name||2" => "data2"]] --- WHERE name = 1 OR name = 'data2'
* ["name" => 1] --- WHERE name = 1)
* ["name" => [1,2,3,5]] --- WHERE name IN ( 1, 2, 3, 5)
* ["name|in" => [1,2,3,5]] --- WHERE name IN ( 1, 2, 3, 5)
* ["name|!" => [1,2,3,5]] --- WHERE name NOT IN ( 1, 2, 3, 5)
* ["name|!=" => [1,2,3,5]] --- WHERE name NOT IN ( 1, 2, 3, 5)
* ["name|not" => [1,2,3,5]] --- WHERE name NOT IN ( 1, 2, 3, 5)
* ["name|not" => 1] --- WHERE name != 1)
* ["name|<>" => 1] --- WHERE name <> 1)
* ["name|>" => 1] --- WHERE name > 1)
* ["name|>=" => 1] --- WHERE name >= 1)
* ["name|like" => 1] --- WHERE name like 1)
*
*/
namespace X\Database\Driver;
use \X\Database\Credetional as Credetional;
use \X\ETrace\System as ESys;
class PDO_CredetionalError extends ESys {}
class PDO_ConnectionError extends ESys {}
class PDO_UnknownError extends ESys {}
class PDO {
/**
* @var mixed
*/
protected $Credetional;
/**
* @var mixed
*/
protected $PDO;
/**
* @var int
*/
protected $try_count = 0;
/**
* @param $Credetional
*/
public function __construct($Credetional) {
if ($Credetional instanceof Credetional) {
$this->Credetional = $Credetional;
$this->connect();
} else {
throw new PDO_CredetionalError("Object not valid Credetional", 1, ["Credetional" => $Credetional]);
}
}
protected function connect() {
try {
$this->PDO = new \PDO(
$this->Credetional->get_PDO_MySQL_DSN(),
$this->Credetional->get_username(),
$this->Credetional->get_password());
$this->PDO->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
} catch (\PDOException $e) {
throw new PDO_ConnectionError("Connection to database error", 1, [
"message" => $e->getMessage(),
"info" => $e->errorInfo,
]);
}
}
/**
* @return mixed
*/
public function PDO() {
return $this->PDO;
}
/**
* @param $SQL
* @return mixed
*/
public function query($SQL, $option = \PDO::FETCH_ASSOC) {
try {
$data = $this->PDO->query($SQL, $option);
$this->try_count--;
return $data;
} catch (\PDOException $e) {
if ($e->getCode() == "HY000" && $this->try_count < 1) {
# Механизм восстановления соединения
$this->connect();
$this->try_count++;
return $this->query($SQL, $option);
} else {
throw new PDO_UnknownError("PDO Database Error", 1, [
"SQL" => $SQL,
"error_message" => $e->getMessage(),
]);
}
}
}
/**
* @param $SQL
* @return mixed
*/
public function query_num($SQL) {
# Alias option
return $this->query($SQL, \PDO::FETCH_NUM);
}
/**
* @param $SQL
* @return mixed
*/
public function exec($SQL) {
try {
$data = $this->PDO->exec($SQL);
$this->try_count--;
return $data;
} catch (\PDOException $e) {
if ($e->getCode() == "HY000" && $this->try_count < 1) {
# Механизм восстановления соединения
$this->connect();
$this->try_count++;
return $this->exec($SQL);
# ##################################
} else {
throw new PDO_UnknownError("PDO Database Error", 1, [
"SQL" => $SQL,
"error_message" => $e->getMessage(),
]);
}
}
}
/**
* @param $table
* @param $data
*/
public function insert($table, $data, $replace) {
$keys = array_keys($data);
$pattern = array_map(function ($string) {return ":{$string}";}, $keys);
if ($replace) {
$type = "REPLACE";
} else {
$type = "INSERT";
}
$SQL = $type . " INTO `{$table}` (`" . implode('`,`', $keys) . "`) VALUES ( " . implode(", ", $keys) . " )";
$statement = $this->prepare($SQL);
foreach ($keys as $key) {
if (is_integer($data[$key])) {
$statement->bindValue(":{$key}", $data[$key], \PDO::PARAM_INT);
} else {
$statement->bindValue(":{$key}", $data[$key], \PDO::PARAM_STR);
}
}
return $statement->execute();
}
/**
* @param $table
* @param $data
*/
public function replace($table, $data) {
$this->insert($table, $data, true);
}
/**
* @param $SQL
*/
public function prepare($SQL) {
return $this->PDO->prepare($SQL);
}
/**
* @param $table
* @param $data
* @param $where
*/
public function update($table, $data, $where = []) {
$SQL = "UPDATE `{$table}` SET ";
$keys = array_keys($data);
$data_pattern = array_map(function ($key) {return " `{$key}`= :{$key}";}, $keys);
$SQL .= implode(", ", $data_pattern);
$SQL .= " ";
$whete_obj = new PDOWhereConstructor($where);
$SQL .= $whete_obj->get_sql();
$statement = $this->prepare($SQL);
foreach ($keys as $key) {
if (is_integer($data[$key])) {
$statement->bindValue(":{$key}", $data[$key], \PDO::PARAM_INT);
} else {
$statement->bindValue(":{$key}", $data[$key], \PDO::PARAM_STR);
}
}
foreach ($whete_obj->get_dataset() as $key => $data_item) {
if (is_integer($data_item)) {
$statement->bindValue($key, $data_item, \PDO::PARAM_INT);
} else {
$statement->bindValue($key, $data_item, \PDO::PARAM_STR);
}
}
return $statement->execute();
}
/**
* @param $table
* @param array $where
* @param $columns
*/
public function select($table, $where = [], $order = null, $limit = null, $columns = "*") {
$SQL = "SELECT {$columns} FROM `{$table}` ";
$whete_obj = new PDOWhereConstructor($where);
$SQL .= $whete_obj->get_sql();
if (is_array($order)) {
$SQL .= " ORDER BY `{$order[0]}` {$order[1]}";
}
if (is_integer($limit)) {
$SQL .= " LIMIT {$limit}";
} else if (is_array($order)) {
$SQL .= " LIMIT {$limit[0]},{$limit[1]}";
}
$statement = $this->prepare($SQL);
foreach ($whete_obj->get_dataset() as $key => $data_item) {
if (is_integer($data_item)) {
$statement->bindValue($key, $data_item, \PDO::PARAM_INT);
} else {
$statement->bindValue($key, $data_item, \PDO::PARAM_STR);
}
}
$statement->execute();
return $statement->fetchAll(\PDO::FETCH_ASSOC);
}
}
?>
\ No newline at end of file
<?php
/**
* new PDOWhereConstructor(array $data)
*
* Where Examples:
* ["name1" => 1, "name2" => "data2"] --- WHERE name1 = 1 AND name2 = 'data2'
* ["[and]" => ["name1" => 1, "name2" => "data2"]] --- WHERE name1 = 1 AND name2 = 'data2'
* ["[or]" => ["name||1" => 1, "name||2" => "data2"]] --- WHERE name = 1 OR name = 'data2'
* ["[or]" => ["name1" => 1, "name2" => "data2"]] --- WHERE name1 = 1 OR name2 = 'data2'
* ["name" => 1] --- WHERE name = 1)
* ["name" => [1,2,3,5]] --- WHERE name IN ( 1, 2, 3, 5)
* ["name|in" => [1,2,3,5]] --- WHERE name IN ( 1, 2, 3, 5)
* ["name|!" => [1,2,3,5]] --- WHERE name NOT IN ( 1, 2, 3, 5)
* ["name|!=" => [1,2,3,5]] --- WHERE name NOT IN ( 1, 2, 3, 5)
* ["name|not" => [1,2,3,5]] --- WHERE name NOT IN ( 1, 2, 3, 5)
* ["name|not" => 1] --- WHERE name != 1)
* ["name|<>" => 1] --- WHERE name <> 1)
* ["name|>" => 1] --- WHERE name > 1)
* ["name|>=" => 1] --- WHERE name >= 1)
* ["name|like" => 1] --- WHERE name like 1)
*
*/
namespace X\Database\Driver;
use \X\ETrace\System as ESys;
class PDOWhereConstructor_InputDataTypeError extends ESys {}
class PDOWhereConstructor_OperatorTypeError extends ESys {}
class PDOWhereConstructor {
/**
* @var mixed
*/
private $SQL;
/**
* @var mixed
*/
private $data_set;
/**
* @param $data
*/
public function __construct($data = []) {
$this->Parse($data);
}
/**
* @return mixed
*/
public function get_sql() {
return $this->SQL;
}
/**
* @return mixed
*/
public function get_dataset() {
return $this->data_set;
}
/**
* @param array $data
*/
public function Parse($data = []) {
if (is_array($data)) {
if (count($data > 0)) {
$this->SQL = "WHERE ";
$this->SQL .= $this->build_where_string($data);
} else {
$this->SQL = "";
}
} else {
throw new PDOWhereConstructor_InputDataTypeError("Where data must have array type", 1, [
"input_data" => $data,
]);
}
}
/**
* @param $data
*/
private function build_where_string($data, $inner_level = 0, $operator = "AND") {
$SQL_Fragment_Items = "";
$key_index = 0;
foreach ($data as $key => $value) {
$item_info = $this->check_data_item($key, $value, $inner_level, $operator);
if ($item_info["type"] == "column") {
if (is_array($value)) {
$key_id = 0;
$data_keys = [];
foreach ($value as $val) {
$data_keys[] = $data_key = ":wh_{$item_info["name"]}_{$inner_level}_{$key_index}_{$key_id}";
$key_id++;
$this->data_set[$data_key] = $val;
}
$data_keys_pat = implode(", ", $data_keys);
$SQL_Fragment_Items[] = "`{$item_info["name"]}` {$item_info["operator"]} ({$data_keys_pat})";
} else {
$data_key = ":wh_{$item_info["name"]}_{$inner_level}_{$key_index}";
$this->data_set[$data_key] = $value;
$SQL_Fragment_Items[] = "`{$item_info["name"]}` {$item_info["operator"]} {$data_key}";
}
} else {
$level_data = $this->build_where_string($value, ($inner_level + 1), $item_info["operator"]);
if ($inner_level > 0) {
$SQL_Fragment_Items[] = "({$level_data})";
} else {
$SQL_Fragment_Items[] = $level_data;
}
}
$key_index++;
}
return implode(" {$operator} ", $SQL_Fragment_Items);
}
/**
* @param $key
*/
private function check_data_item($key, $data, $level, $operator) {
if (is_integer($key)) {
$operator = strtolower($operator);
$key = "[{$operator}]";
}
if (in_array(strtolower($key), ["[or]", "[and]"])) {
$column_type = "set";
$operator = str_replace(["[", "]"], "", strtoupper($key));
$column_name = null;
} else {
$column_type = "column";
$key_info = explode("|", $key);
$column_name = $key_info[0];
if (isset($key_info[1])) {
switch (strtolower($key_info[1])) {
case '=':
case 'in':
$operator = $this->default_column_operator($data);
break;
case 'not':
case 'not in':
case '!':
case '!=':
case '<>':
$operator = $this->not_column_operator($data);
break;
case '>':
case '<':
case '>=':
case '<=':
case '<=>':
//case 'isnull':
case 'is null':
case 'is not null':
case 'between':
case 'not between':
case 'like':
//case 'coalesce':
if (is_array($data)) {
throw new PDOWhereConstructor_OperatorTypeError("For operator '{$key_info[1]} 'data' must have int or string value'", 1, [
"key" => $key,
"data" => $data,
]);
}
$operator = strtoupper($key_info[1]);
break;
default:
$operator = $this->default_column_operator($data);
break;
}
} else {
$operator = $this->default_column_operator($data);
}
}
return [
"type" => $column_type, // column,set
"operator" => $operator, // column = {=,>,<,IN},set= { OR, AND }
"name" => $column_name,
];
}
/**
* @param $data
*/
private function default_column_operator($data) {
if (is_array($data)) {return "IN";} else {return "=";}
}
/**
* @param $data
*/
private function not_column_operator($data) {
if (is_array($data)) {return "NOT IN";} else {return "!=";}
}
}
?>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment