1
+ <?php
2
+
3
+ declare (strict_types = 1 );
4
+
5
+ namespace mepihindeveloper \components ;
6
+
7
+ use PDO ;
8
+ use PDOException ;
9
+ use PDOStatement ;
10
+ use RuntimeException ;
11
+
12
+ /**
13
+ * Класс Database
14
+ * Класс реализует подключение и управление запросами к базе данных
15
+ *
16
+ * @package mepihindeveloper\components
17
+ */
18
+ class Database implements interfaces \DatabaseInterface {
19
+
20
+ /**
21
+ * @var PDOStatement[] Список подготовленных запросов
22
+ */
23
+ public array $ executeList = [];
24
+ /**
25
+ * @var bool Статус активности транзакции
26
+ */
27
+ public bool $ isTransaction = false ;
28
+ /**
29
+ * @var PDO|null Соединение с базой данных
30
+ */
31
+ protected ?PDO $ pdo ;
32
+ /**
33
+ * @var PDOStatement Подготовленный запрос
34
+ */
35
+ protected PDOStatement $ pdoStatement ;
36
+
37
+ /**
38
+ * @inheritDoc
39
+ */
40
+ public function connect (array $ databaseConnectionParams = []): void {
41
+ $ dsn = "{$ databaseConnectionParams ['dbms ' ]}: " ;
42
+
43
+ foreach (['host ' , 'dbname ' ] as $ key ) {
44
+ $ dsn .= "{$ key }= {$ databaseConnectionParams [$ key ]}; " ;
45
+ }
46
+
47
+ $ charset = array_key_exists ('charset ' , $ databaseConnectionParams ) ? strtoupper ($ databaseConnectionParams ['charset ' ]) : 'UTF8 ' ;
48
+ $ this ->pdo = new PDO (
49
+ $ dsn ,
50
+ $ databaseConnectionParams ['user ' ],
51
+ $ databaseConnectionParams ['password ' ]
52
+ );
53
+ $ this ->pdo ->setAttribute (PDO ::ATTR_ERRMODE , PDO ::ERRMODE_EXCEPTION );
54
+ $ this ->pdo ->setAttribute (PDO ::ATTR_EMULATE_PREPARES , true );
55
+ $ this ->pdo ->exec ("SET NAMES ' {$ charset }' " );
56
+ }
57
+
58
+ /**
59
+ * @inheritDoc
60
+ */
61
+ public function closeConnection (): void {
62
+ $ this ->pdo = null ;
63
+ }
64
+
65
+ /**
66
+ * @inheritDoc
67
+ */
68
+ public function beginTransaction (): void {
69
+ if ($ this ->isTransaction ) {
70
+ throw new RuntimeException ('Ошибка. Невозможно повторно инициализировать транзакцию. ' );
71
+ }
72
+
73
+ $ this ->pdo ->beginTransaction ();
74
+ $ this ->isTransaction = true ;
75
+ }
76
+
77
+ /**
78
+ * @inheritDoc
79
+ */
80
+ public function commit (): void {
81
+ try {
82
+ if (!empty ($ this ->executeList )) {
83
+ foreach ($ this ->executeList as $ executeQuery ) {
84
+ $ executeQuery ->execute ();
85
+ }
86
+ }
87
+
88
+ $ this ->pdo ->commit ();
89
+ } catch (PDOException $ exception ) {
90
+ $ this ->pdo ->rollBack ();
91
+
92
+ throw new PDOException (500 , $ exception ->getMessage (), $ exception ->getCode ());
93
+ } finally {
94
+ $ this ->isTransaction = false ;
95
+ $ this ->executeList = [];
96
+ }
97
+ }
98
+
99
+ /**
100
+ * @inheritDoc
101
+ */
102
+ public function queryAll (string $ query , array $ attributes = [], $ fetchStyle = PDO ::FETCH_ASSOC ): array {
103
+ $ this ->execute ($ query , $ attributes );
104
+
105
+ return $ this ->pdoStatement ->fetchAll ($ fetchStyle );
106
+ }
107
+
108
+ /**
109
+ * @inheritDoc
110
+ */
111
+ public function execute (string $ query , array $ attributes = []): bool {
112
+ $ this ->beforeQuery ($ query , $ attributes );
113
+
114
+ return $ this ->pdoStatement ->execute ();
115
+ }
116
+
117
+ /**
118
+ * Обрабатывает запрос перед выполнением
119
+ *
120
+ * @param string $query Запрос
121
+ * @param array $attributes Атрибуты запроса
122
+ *
123
+ * @return void
124
+ * @throws PDOException
125
+ */
126
+ protected function beforeQuery (string $ query , array $ attributes = []): void {
127
+ try {
128
+ $ this ->pdoStatement = $ this ->pdo ->prepare ($ query );
129
+
130
+ if (!empty ($ attributes )) {
131
+ $ preparedAttributes = $ this ->bindAttributes ($ attributes );
132
+
133
+ foreach ($ preparedAttributes as $ preparedAttribute ) {
134
+ $ attributesPart = explode ("\x7F" , $ preparedAttribute );
135
+ $ this ->pdoStatement ->bindParam ($ attributesPart [0 ], $ attributesPart [1 ]);
136
+ }
137
+ }
138
+
139
+ if ($ this ->isTransaction ) {
140
+ $ this ->executeList [] = $ this ->pdoStatement ;
141
+ }
142
+ } catch (PDOException $ exception ) {
143
+ throw new PDOException (500 , $ exception ->getMessage (), $ exception ->getCode ());
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Назначает атрибуты
149
+ *
150
+ * @param array $attributes Атрибуты
151
+ *
152
+ * @return array
153
+ */
154
+ protected function bindAttributes (array $ attributes ): array {
155
+ $ preparedAttributes = [];
156
+
157
+ foreach ($ attributes as $ key => $ value ) {
158
+ $ preparedAttributes [] = ': ' . $ key . "\x7F" . $ value ;
159
+ }
160
+
161
+ return $ preparedAttributes ;
162
+ }
163
+
164
+ /**
165
+ * @inheritDoc
166
+ */
167
+ public function queryRow (string $ query , array $ attributes = [], $ fetchStyle = PDO ::FETCH_ASSOC ) {
168
+ $ this ->execute ($ query , $ attributes );
169
+
170
+ return $ this ->pdoStatement ->fetch ($ fetchStyle );
171
+ }
172
+
173
+ /**
174
+ * @inheritDoc
175
+ */
176
+ public function queryColumn (string $ query , array $ attributes = []): array {
177
+ $ this ->execute ($ query , $ attributes );
178
+ $ queryCells = $ this ->pdoStatement ->fetchAll (PDO ::FETCH_NUM );
179
+ $ cells = [];
180
+
181
+ foreach ($ queryCells as $ queryCell ) {
182
+ $ cells [] = $ queryCell [0 ];
183
+ }
184
+
185
+ return $ cells ;
186
+ }
187
+
188
+ /**
189
+ * @inheritDoc
190
+ */
191
+ public function queryOne (string $ query , array $ attributes = []) {
192
+ $ this ->execute ($ query , $ attributes );
193
+
194
+ return $ this ->pdoStatement ->fetchColumn ();
195
+ }
196
+
197
+ /**
198
+ * @inheritDoc
199
+ */
200
+ public function getLastInsertId (): string {
201
+ return $ this ->pdo ->lastInsertId ();
202
+ }
203
+ }
0 commit comments