Complex classes like PdoHandlerDriver often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use PdoHandlerDriver, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
16 | class PdoHandlerDriver implements DataHandlerDriverInterface |
||
17 | { |
||
18 | use CondorcetVersion; |
||
19 | |||
20 | protected const SEGMENT = [300,100,50,10,1]; |
||
21 | |||
22 | protected $_handler; |
||
23 | protected $_transaction = false; |
||
24 | protected $_queryError = false; |
||
25 | |||
26 | // Database structure |
||
27 | protected $_struct; |
||
28 | // Prepare Query |
||
29 | protected $_prepare = []; |
||
30 | // Data CallBack function |
||
31 | public $_dataContextObject; |
||
32 | |||
33 | |||
34 | 3 | public function __construct (\PDO $bdd, bool $tryCreateTable = false, array $struct = ['tableName' => 'Entitys', 'primaryColumnName' => 'id', 'dataColumnName' => 'data']) |
|
35 | { |
||
36 | 3 | if (!$this->checkStructureTemplate($struct)) : |
|
37 | throw new CondorcetException; |
||
38 | endif; |
||
39 | |||
40 | 3 | $this->_struct = $struct; |
|
41 | |||
42 | 3 | $this->_handler = $bdd; |
|
43 | |||
44 | 3 | $this->_handler->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); |
|
45 | |||
46 | 3 | if ($tryCreateTable) : |
|
47 | 3 | $this->createTable(); |
|
48 | endif; |
||
49 | |||
50 | 3 | $this->initPrepareQuery(); |
|
51 | 3 | } |
|
52 | |||
53 | 1 | public function __destruct () |
|
54 | { |
||
55 | 1 | if ($this->_queryError) : |
|
56 | $this->_handler->rollback(); |
||
57 | $this->_transaction = false; |
||
58 | else : |
||
59 | 1 | $this->closeTransaction(); |
|
60 | endif; |
||
61 | 1 | } |
|
62 | |||
63 | |||
64 | // INTERNAL |
||
65 | |||
66 | 3 | protected function checkStructureTemplate (array &$struct) : bool |
|
67 | { |
||
68 | 3 | if ( !empty($struct['tableName']) && !empty($struct['primaryColumnName']) && !empty($struct['dataColumnName']) && |
|
69 | 3 | is_string($struct['tableName']) && is_string($struct['primaryColumnName']) && is_string($struct['dataColumnName']) |
|
70 | ) : |
||
71 | 3 | return true; |
|
72 | else : |
||
73 | return false; |
||
74 | endif; |
||
75 | } |
||
76 | |||
77 | 3 | public function createTable () : void |
|
78 | { |
||
79 | try { |
||
80 | 3 | $this->_handler->exec('CREATE TABLE IF NOT EXISTS '.$this->_struct['tableName'].' ('.$this->_struct['primaryColumnName'].' INTEGER PRIMARY KEY NOT NULL , '.$this->_struct['dataColumnName'].' BLOB NOT NULL )'); |
|
81 | } catch (\Exception $e) { |
||
82 | throw $e; |
||
83 | } |
||
84 | 3 | } |
|
85 | |||
86 | 3 | protected function initPrepareQuery () : void |
|
87 | { |
||
88 | 3 | $template = []; |
|
89 | |||
90 | // Base - Small query ends |
||
91 | 3 | $template['end_template'] = ';'; |
|
92 | 3 | $template['insert_template'] = 'INSERT INTO '.$this->_struct['tableName'].' ('.$this->_struct['primaryColumnName'].', '.$this->_struct['dataColumnName'].') VALUES '; |
|
93 | 3 | $template['delete_template'] = 'DELETE FROM '.$this->_struct['tableName'].' WHERE '.$this->_struct['primaryColumnName']; |
|
94 | 3 | $template['select_template'] = 'SELECT '.$this->_struct['primaryColumnName'].','.$this->_struct['dataColumnName'].' FROM '.$this->_struct['tableName'].' WHERE '.$this->_struct['primaryColumnName']; |
|
95 | 3 | $template['update_template'] = 'UPDATE '.$this->_struct['tableName'].' SET '.$this->_struct['dataColumnName'].' = :data WHERE '.$this->_struct['primaryColumnName']; |
|
96 | |||
97 | // Select the max / min key value. Usefull if array cursor is lost on DataManager. |
||
98 | 3 | $this->_prepare['selectMaxKey'] = $this->_handler->prepare('SELECT max('.$this->_struct['primaryColumnName'].') FROM '.$this->_struct['tableName'] . $template['end_template']); |
|
99 | 3 | $this->_prepare['selectMinKey'] = $this->_handler->prepare('SELECT min('.$this->_struct['primaryColumnName'].') FROM '.$this->_struct['tableName'] . $template['end_template']); |
|
100 | |||
101 | // Insert many Entitys |
||
102 | 3 | $makeMany = function ($how) use (&$template) { |
|
103 | 3 | $query = $template['insert_template']; |
|
104 | |||
105 | 3 | for ($i=1; $i < $how; $i++) : |
|
106 | 3 | $query .= '(:key'.$i.', :data'.$i.'),'; |
|
107 | endfor; |
||
108 | |||
109 | 3 | $query .= '(:key'.$how.', :data'.$how.')' . $template['end_template']; |
|
110 | |||
111 | 3 | return $query; |
|
112 | 3 | }; |
|
113 | |||
114 | 3 | foreach (self::SEGMENT as $value) : |
|
115 | 3 | $this->_prepare['insert'.$value.'Entitys'] = $this->_handler->prepare($makeMany($value)); |
|
116 | endforeach; |
||
117 | |||
118 | // Delete one Entity |
||
119 | 3 | $this->_prepare['deleteOneEntity'] = $this->_handler->prepare($template['delete_template'] . ' = ?' . $template['end_template']); |
|
120 | |||
121 | // Get a Entity |
||
122 | 3 | $this->_prepare['selectOneEntity'] = $this->_handler->prepare($template['select_template'] . ' = ?' . $template['end_template']); |
|
123 | |||
124 | // Get a range of Entity |
||
125 | 3 | $this->_prepare['selectRangeEntitys'] = $this->_handler->prepare($template['select_template'] . ' >= :startKey order by '.$this->_struct['primaryColumnName'].' asc LIMIT :limit' . $template['end_template']); |
|
126 | |||
127 | // Count Entitys |
||
128 | 3 | $this->_prepare['countEntitys'] = $this->_handler->prepare('SELECT count('.$this->_struct['primaryColumnName'].') FROM '. $this->_struct['tableName'] . $template['end_template']); |
|
129 | |||
130 | // Update Entity |
||
131 | 3 | $this->_prepare['updateOneEntity'] = $this->_handler->prepare($template['update_template'] . ' = :key' . $template['end_template']); |
|
132 | |||
133 | // Flush All |
||
134 | 3 | $this->_prepare['flushAll'] = $this->_handler->prepare($template['delete_template'] . ' is not null' . $template['end_template']); |
|
135 | 3 | } |
|
136 | |||
137 | 3 | protected function initTransaction () : void |
|
138 | { |
||
139 | 3 | if (!$this->_transaction) : |
|
140 | 3 | $this->_transaction = $this->_handler->beginTransaction(); |
|
141 | endif; |
||
142 | 3 | } |
|
143 | |||
144 | 3 | public function closeTransaction () : void |
|
145 | { |
||
146 | 3 | if ($this->_transaction === true) : |
|
147 | 3 | if ($this->_queryError) : |
|
148 | throw new CondorcetException; |
||
149 | endif; |
||
150 | |||
151 | 3 | $this->_transaction = !$this->_handler->commit(); |
|
152 | endif; |
||
153 | 3 | } |
|
154 | |||
155 | |||
156 | // DATA MANAGER |
||
157 | 3 | public function insertEntitys (array $input) : void |
|
158 | { |
||
159 | 3 | $this->sliceInput($input); |
|
160 | |||
161 | try { |
||
162 | 3 | $this->initTransaction(); |
|
163 | |||
164 | 3 | foreach ($input as $group) : |
|
165 | 3 | $param = []; |
|
166 | 3 | $i = 1; |
|
167 | 3 | $group_count = count($group); |
|
168 | |||
169 | 3 | foreach ($group as $key => &$Entity) : |
|
170 | 3 | $param['key'.$i] = $key; |
|
171 | 3 | $param['data'.$i++] = $this->_dataContextObject->dataPrepareStoringAndFormat($Entity); |
|
172 | endforeach; |
||
173 | 3 | unset($Entity); |
|
174 | |||
175 | 3 | $this->_prepare['insert'.$group_count.'Entitys']->execute( |
|
176 | 3 | $param |
|
177 | ); |
||
178 | |||
179 | 3 | if ($this->_prepare['insert'.$group_count.'Entitys']->rowCount() !== $group_count) : |
|
180 | throw new CondorcetException (0,'Tous les Entitys n\'ont pas été insérés'); |
||
181 | endif; |
||
182 | |||
183 | 3 | $this->_prepare['insert'.$group_count.'Entitys']->closeCursor(); |
|
184 | endforeach; |
||
185 | |||
186 | 3 | $this->closeTransaction(); |
|
187 | } catch (\Exception $e) { |
||
188 | $this->_queryError = true; |
||
189 | throw $e; |
||
190 | } |
||
191 | 3 | } |
|
192 | |||
193 | 3 | protected function sliceInput (array &$input) : void |
|
194 | { |
||
195 | 3 | $count = count($input); |
|
196 | |||
197 | 3 | foreach (self::SEGMENT as $value) : |
|
198 | 3 | if ($count >= $value) : |
|
199 | 3 | $input = array_chunk($input, $value, true); |
|
200 | |||
201 | 3 | $end = end($input); |
|
202 | 3 | if (count($input) > 1 && count($end) < $value) : |
|
203 | $this->sliceInput($end); |
||
204 | unset($input[key($input)]); |
||
205 | $input = array_merge($input,$end); |
||
206 | endif; |
||
207 | 3 | break; |
|
208 | endif; |
||
209 | endforeach; |
||
210 | 3 | } |
|
211 | |||
212 | public function updateOneEntity (int $key,$data) : void |
||
230 | |||
231 | 1 | public function deleteOneEntity (int $key, bool $justTry) : ?int |
|
232 | { |
||
233 | try { |
||
234 | 1 | $this->_prepare['deleteOneEntity']->bindParam(1, $key, \PDO::PARAM_INT); |
|
235 | 1 | $this->_prepare['deleteOneEntity']->execute(); |
|
236 | |||
237 | 1 | $deleteCount = $this->_prepare['deleteOneEntity']->rowCount(); |
|
238 | |||
239 | 1 | if (!$justTry && $deleteCount !== 1) : |
|
240 | throw new CondorcetException (30); |
||
241 | endif; |
||
242 | |||
243 | 1 | $this->_prepare['deleteOneEntity']->closeCursor(); |
|
244 | |||
245 | 1 | return $deleteCount; |
|
246 | } catch (\Exception $e) { |
||
247 | $this->_queryError = true; |
||
248 | throw $e; |
||
249 | } |
||
250 | } |
||
251 | |||
252 | 1 | public function selectMaxKey () : ?int |
|
253 | { |
||
254 | 1 | if ($this->countEntitys() === 0) : |
|
255 | return null; |
||
256 | endif; |
||
257 | |||
258 | try { |
||
259 | 1 | $this->_prepare['selectMaxKey']->execute(); |
|
260 | 1 | $r = (int) $this->_prepare['selectMaxKey']->fetch(\PDO::FETCH_NUM)[0]; |
|
261 | 1 | $this->_prepare['selectMaxKey']->closeCursor(); |
|
262 | |||
263 | 1 | return $r; |
|
264 | } catch (\Exception $e) { |
||
265 | throw $e; |
||
266 | } |
||
267 | } |
||
268 | |||
269 | 2 | public function selectMinKey () : int |
|
270 | { |
||
271 | try { |
||
272 | 2 | $this->_prepare['selectMinKey']->execute(); |
|
273 | 2 | $r = (int) $this->_prepare['selectMinKey']->fetch(\PDO::FETCH_NUM)[0]; |
|
274 | 2 | $this->_prepare['selectMinKey']->closeCursor(); |
|
275 | |||
276 | 2 | return $r; |
|
277 | } catch (\Exception $e) { |
||
278 | throw $e; |
||
279 | } |
||
280 | } |
||
281 | |||
282 | 3 | public function countEntitys () : int |
|
283 | { |
||
284 | try { |
||
285 | 3 | $this->_prepare['countEntitys']->execute(); |
|
286 | 3 | $r = (int) $this->_prepare['countEntitys']->fetch(\PDO::FETCH_NUM)[0]; |
|
287 | 3 | $this->_prepare['countEntitys']->closeCursor(); |
|
288 | |||
289 | 3 | return $r; |
|
290 | } catch (\Exception $e) { |
||
291 | throw $e; |
||
292 | } |
||
293 | } |
||
294 | |||
295 | // return false if Entity does not exist. |
||
296 | 2 | public function selectOneEntity (int $key) |
|
297 | { |
||
298 | try { |
||
299 | 2 | $this->_prepare['selectOneEntity']->bindParam(1, $key, \PDO::PARAM_INT); |
|
300 | 2 | $this->_prepare['selectOneEntity']->execute(); |
|
301 | |||
302 | 2 | $r = $this->_prepare['selectOneEntity']->fetchAll(\PDO::FETCH_NUM); |
|
303 | 2 | $this->_prepare['selectOneEntity']->closeCursor(); |
|
304 | 2 | if (!empty($r)) : |
|
305 | 2 | return $this->_dataContextObject->dataCallBack( $r[0][1] ); |
|
306 | else : |
||
307 | return false; |
||
308 | endif; |
||
309 | } catch (\Exception $e) { |
||
310 | throw $e; |
||
311 | } |
||
312 | } |
||
313 | |||
314 | 3 | public function selectRangeEntitys (int $key, int $limit) : array |
|
315 | { |
||
316 | try { |
||
317 | 3 | $this->_prepare['selectRangeEntitys']->bindParam(':startKey', $key, \PDO::PARAM_INT); |
|
318 | 3 | $this->_prepare['selectRangeEntitys']->bindParam(':limit', $limit, \PDO::PARAM_INT); |
|
319 | 3 | $this->_prepare['selectRangeEntitys']->execute(); |
|
320 | |||
321 | 3 | $r = $this->_prepare['selectRangeEntitys']->fetchAll(\PDO::FETCH_NUM); |
|
322 | 3 | $this->_prepare['selectRangeEntitys']->closeCursor(); |
|
323 | 3 | if (!empty($r)) : |
|
324 | 3 | $result = []; |
|
325 | 3 | foreach ($r as $value) : |
|
326 | 3 | $result[(int) $value[0]] = $this->_dataContextObject->dataCallBack( $value[1] ); |
|
327 | endforeach ; |
||
328 | |||
329 | 3 | return $result; |
|
330 | else : |
||
331 | return []; |
||
332 | endif; |
||
333 | } catch (\Exception $e) { |
||
334 | throw $e; |
||
335 | } |
||
336 | } |
||
337 | |||
338 | public function flushAll () : ?int |
||
352 | |||
353 | } |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.