Skip to content

Commit e00f871

Browse files
committed
init
0 parents  commit e00f871

File tree

7 files changed

+332
-0
lines changed

7 files changed

+332
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.idea/
2+
Tests/
3+
vendor/
4+
composer.phar
5+
composer.lock

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2019 DigitalStars, Kirill Minovsky <vk.com/runnin4ik>, Anton Kolobov <vk.com/l_zerox_l>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

autoload.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
namespace DigitalStars\DataBase;
3+
$path_dir = __DIR__.'/src';
4+
require_once($path_dir.'/Exception.php');
5+
require_once($path_dir.'/Parser.php');
6+
require_once($path_dir.'/DataBase.php');

composer.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "digitalstars/database",
3+
"description": "Library for easy work with databases",
4+
"license": "MIT",
5+
"minimum-stability": "stable",
6+
"authors": [
7+
{
8+
"name": "ZeRoX",
9+
"email": "as234zx15@yandex.ru"
10+
},
11+
{
12+
"name": "Runnin",
13+
"email": "mr.kirilll12@mail.ru"
14+
}
15+
],
16+
"require": {
17+
"php": ">=7.0",
18+
"ext-pdo": "*"
19+
},
20+
"autoload": {
21+
"psr-4": {
22+
"DigitalStars\\database\\": "src/"
23+
}
24+
}
25+
}

src/DataBase.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
namespace DigitalStars\DataBase;
4+
5+
use PDO;
6+
7+
class DataBase extends \PDO {
8+
use Parser;
9+
10+
public function __construct($dsn, $username = null, $passwd = null, $options = null) {
11+
parent::__construct($dsn, $username, $passwd, $options);
12+
}
13+
14+
public function exec($statement, $args = []) {
15+
return parent::exec(count($args) == 0 ? $statement : $this->parse($statement, $args));
16+
}
17+
18+
public function query($statement, $args = [], $mode = null, $arg3 = null, $ctorargs = null) {
19+
$statement = (count($args) == 0 ? $statement : $this->parse($statement, $args));
20+
if (!is_null($ctorargs))
21+
return parent::query($statement, $mode, $arg3, $ctorargs);
22+
else if (!is_null($arg3))
23+
return parent::query($statement, $mode, $arg3);
24+
else if (!is_null($mode))
25+
return parent::query($statement, $mode);
26+
return parent::query($statement);
27+
}
28+
29+
public function prepare($statement, $args = [], array $driver_options = array()) {
30+
return parent::prepare(count($args) == 0 ? $statement : $this->parse($statement, $args), $driver_options);
31+
}
32+
33+
public function rows($sql, $args = [], $fetchMode = PDO::FETCH_OBJ) {
34+
return $this->query($sql, $args)->fetchAll($fetchMode);
35+
}
36+
37+
public function row($sql, $args = [], $fetchMode = PDO::FETCH_OBJ) {
38+
return $this->query($sql, $args)->fetch($fetchMode);
39+
}
40+
41+
public function getById($table, $id, $fetchMode = PDO::FETCH_OBJ) {
42+
return $this->query("SELECT * FROM ?f WHERE id = ?i", [$table, $id])->fetch($fetchMode);
43+
}
44+
45+
public function count($sql, $args = []) {
46+
return $this->query($sql, $args)->rowCount();
47+
}
48+
49+
public function insert($table, $data) {
50+
$this->query("INSERT INTO ?f (?af) VALUES (?as)", [$table, array_keys($data), array_values($data)]);
51+
return $this->lastInsertId();
52+
}
53+
54+
public function update($table, $data, $where) {
55+
return $this->exec("UPDATE ?f SET ?As WHERE ?ws", [$table, $data, $where]);
56+
}
57+
58+
public function delete($table, $where, $limit = 1) {
59+
return $this->exec("DELETE FROM ?f WHERE ?ws LIMIT ?i", [$table, $where, $limit]);
60+
}
61+
62+
public function deleteAll($table) {
63+
return $this->exec("DELETE FROM ?f", [$table]);
64+
}
65+
66+
public function deleteById($table, $id) {
67+
return $this->exec("DELETE FROM ?f WHERE id = ?i", [$table, $id]);
68+
}
69+
70+
public function deleteByIds($table, $column, $ids) {
71+
return $this->exec("DELETE FROM ?f WHERE ?f IN (?as)", [$table, $column, $ids]);
72+
}
73+
74+
public function truncate($table) {
75+
return $this->exec("TRUNCATE TABLE ?f", [$table]);
76+
}
77+
}

src/Exception.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
/**
3+
* @author Vasiliy Makogon, makogon-vs@yandex.ru
4+
* @link https://github.com/Vasiliy-Makogon/Database/
5+
*/
6+
7+
namespace DigitalStars\DataBase;
8+
9+
class Exception extends \Exception {
10+
11+
}

src/Parser.php

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
<?php
2+
3+
4+
namespace DigitalStars\DataBase;
5+
6+
7+
trait Parser {
8+
private $args;
9+
private $original_query;
10+
private $is_inner = false;
11+
12+
public function parse($query, array $args) {
13+
$this->is_inner = false;
14+
$this->original_query = $query;
15+
$this->args = $args;
16+
$anon = function ($v) {
17+
return $this->parse_part($v);
18+
};
19+
return preg_replace_callback("!(\?[avw]\[.*?\])|(\?[avw]?[sidnf])!i", $anon, $query);
20+
}
21+
22+
private function parse_part($symbol, $value = null) {
23+
if (is_array($symbol))
24+
$symbol = $symbol[0];
25+
if ($symbol == '?')
26+
return $symbol;
27+
$symbol = trim($symbol);
28+
if (!$this->is_inner and $symbol != '?n')
29+
if (count($this->args) == 0)
30+
throw new Exception('Несовпадение количества аргументов и заполнителей в массиве, запрос ' . $this->original_query);
31+
else
32+
$value = array_shift($this->args);
33+
switch ($symbol[1]) {
34+
case "S":
35+
$is_like_escaping = true;
36+
case 's':
37+
$value = $this->getValueStringType($value);
38+
return isset($is_like_escaping) ? $this->escapeLike($value) : $this->realEscapeString($value);
39+
case 'i':
40+
return $this->getValueIntType($value);
41+
case 'd':
42+
return $this->getValueFloatType($value);
43+
case 'n':
44+
return "NULL";
45+
case 'f':
46+
return $this->escapeFieldName($value);
47+
case 'A':
48+
$is_associative_array = true;
49+
case 'a':
50+
$value = $this->parseArray($symbol, $value);
51+
if (isset($is_associative_array)) {
52+
foreach ($value as $key => $val)
53+
$result[] = $this->escapeFieldName($key) . "=" . $val;
54+
return join(',', $result);
55+
} else
56+
return join(',', $value);
57+
case "v":
58+
if (!is_array($value))
59+
throw new Exception($this->createErrorMessage('array', $value));
60+
foreach ($value as $key => $val)
61+
$value[$key] = join(',', $this->parseArray($symbol, $value[$key]));
62+
return "(".join("),(", $value).")";
63+
case "w":
64+
$value = $this->parseArray($symbol, $value);
65+
foreach ($value as $key => $val)
66+
$result[] = $this->escapeFieldName($key) . "=" . $val;
67+
return join(' AND ', $result);
68+
default:
69+
throw new Exception("Неизвестный заполнитель {$symbol[2]}");
70+
71+
}
72+
}
73+
74+
private function parseArray($symbol, $value) {
75+
if (!is_array($value))
76+
throw new Exception($this->createErrorMessage('array', $value));
77+
if ($symbol[2] == 'i')
78+
foreach ($value as $key => $val)
79+
$value[$key] = $this->getValueIntType($val);
80+
else if ($symbol[2] == 'd')
81+
foreach ($value as $key => $val)
82+
$value[$key] = $this->getValueFloatType($val);
83+
else if ($symbol[2] == 's')
84+
foreach ($value as $key => $val)
85+
$value[$key] = $this->realEscapeString($this->getValueStringType($val));
86+
else if ($symbol[2] == 'f')
87+
foreach ($value as $key => $val)
88+
$value[$key] = $this->escapeFieldName($val);
89+
else if ($symbol[2] == '[') {
90+
$selectors = explode(',',
91+
substr($symbol, 3, strlen($symbol) - 4));
92+
if (count($selectors) != count($value))
93+
throw new Exception('Несовпадение количества аргументов и заполнителей в массиве, запрос ' . $this->original_query);
94+
$this->is_inner = true;
95+
$index = 0;
96+
foreach ($value as $key => $val)
97+
$value[$key] = $this->parse_part($selectors[$index++], $val);
98+
$this->is_inner = false;
99+
} else
100+
throw new Exception("Неизвестный заполнитель {$symbol[2]}");
101+
return $value;
102+
}
103+
104+
private function escapeFieldName($value) {
105+
if (!is_string($value)) {
106+
throw new Exception($this->createErrorMessage('field', $value));
107+
}
108+
109+
$new_value = '';
110+
111+
$replace = function ($value) {
112+
return '`' . str_replace("`", "``", $value) . '`';
113+
};
114+
115+
$dot = false;
116+
117+
if ($values = explode('.', $value)) {
118+
foreach ($values as $value) {
119+
if ($value === '') {
120+
if (!$dot) {
121+
$dot = true;
122+
$new_value .= '.';
123+
} else {
124+
throw new Exception('Два символа `.` идущие подряд в имени столбца или таблицы');
125+
}
126+
} else {
127+
$new_value .= $replace($value) . '.';
128+
}
129+
}
130+
131+
return rtrim($new_value, '.');
132+
} else {
133+
return $replace($value);
134+
}
135+
}
136+
137+
private function getValueIntType($value) {
138+
if (is_integer($value))
139+
return $value;
140+
if (is_numeric($value) || is_null($value) || is_bool($value)) {
141+
return (int)$value;
142+
}
143+
throw new Exception($this->createErrorMessage('integer', $value));
144+
}
145+
146+
private function getValueFloatType($value) {
147+
if (is_float($value)) {
148+
return $value;
149+
}
150+
if (is_numeric($value) || is_null($value) || is_bool($value)) {
151+
return (float)$value;
152+
}
153+
throw new Exception($this->createErrorMessage('double', $value));
154+
}
155+
156+
private function getValueStringType($value) {
157+
// меняем поведение PHP в отношении приведения bool к string
158+
if (is_bool($value)) {
159+
return (string)(int)$value;
160+
}
161+
162+
if (!is_string($value) && !(is_numeric($value) || is_null($value))) {
163+
throw new Exception($this->createErrorMessage('string', $value));
164+
}
165+
166+
return (string)$value;
167+
}
168+
169+
private function escapeLike($var, $chars = "%_") {
170+
$var = str_replace('\\', '\\\\', $var);
171+
$var = $this->realEscapeString($var);
172+
173+
if ($chars) {
174+
$var = addCslashes($var, $chars);
175+
}
176+
177+
return $var;
178+
}
179+
180+
private function realEscapeString($value) {
181+
return $this->quote($value);
182+
}
183+
184+
private function createErrorMessage($type, $value) {
185+
return "Попытка указать для заполнителя типа $type значение типа " . gettype($value) . " в шаблоне запроса $this->original_query";
186+
}
187+
}

0 commit comments

Comments
 (0)