Completed
Push — master ( e86a88...9f06ff )
by Boudry
04:59 queued 02:04
created

PdoHandlerDriver   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 298
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 79.19%

Importance

Changes 0
Metric Value
wmc 50
lcom 1
cbo 2
dl 0
loc 298
ccs 118
cts 149
cp 0.7919
rs 8.6206
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A initTransaction() 0 6 2
A closeTransaction() 0 10 3
B insertEntitys() 0 35 5
B sliceInput() 0 18 5
A deleteOneEntity() 0 20 4
A selectMaxKey() 0 16 3
A selectMinKey() 0 12 2
A countEntitys() 0 12 2
A selectOneEntity() 0 17 3
B selectRangeEntitys() 0 23 4
A __construct() 0 18 3
A __destruct() 0 9 2
B checkStructureTemplate() 0 10 7
A createTable() 0 8 2
B initPrepareQuery() 0 43 3

How to fix   Complexity   

Complex Class

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
2
/*
3
    PDO DataHandler Module - From the original Condorcet PHP
4
5
    Condorcet PHP - Election manager and results calculator.
6
    Designed for the Condorcet method. Integrating a large number of algorithms extending Condorcet. Expandable for all types of voting systems.
7
8
    By Julien Boudry and contributors - MIT LICENSE (Please read LICENSE.txt)
9
    https://github.com/julien-boudry/Condorcet
10
*/
11
declare(strict_types=1);
12
13
namespace Condorcet\DataManager\DataHandlerDrivers;
14
15
use Condorcet\DataManager\DataHandlerDrivers\DataHandlerDriverInterface;
16
use Condorcet\CondorcetException;
17
use Condorcet\CondorcetVersion;
18
19
class PdoHandlerDriver implements DataHandlerDriverInterface
20
{
21
    use CondorcetVersion;
22
23
    protected const SEGMENT = [300,100,50,10,1];
24
25
    protected $_handler;
26
    protected $_transaction = false;
27
    protected $_queryError = false;
28
29
    // Database structure
30
    protected $_struct;
31
    // Prepare Query
32
    protected $_prepare = [];
33
    // Data CallBack function
34
    public $_dataContextObject;
35
36
37 5
    public function __construct (\PDO $bdd, bool $tryCreateTable = false, array $struct = ['tableName' => 'Entitys', 'primaryColumnName' => 'id', 'dataColumnName' => 'data'])
38
    {
39 5
        if (!$this->checkStructureTemplate($struct)) :
40
            throw new CondorcetException;
41
        endif;
42
43 5
        $this->_struct = $struct;
44
45 5
        $this->_handler = $bdd;
46
47 5
        $this->_handler->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
48
49 5
        if ($tryCreateTable) :
50 5
            $this->createTable();
51
        endif;
52
53 5
        $this->initPrepareQuery();
54 5
    }
55
56 1
    public function __destruct ()
57
    {
58 1
        if ($this->_queryError) :
59
            $this->_handler->rollback();
60
            $this->_transaction = false;
61
        else :
62 1
            $this->closeTransaction();
63
        endif;
64 1
    }
65
66
67
    // INTERNAL
68
69 5
    protected function checkStructureTemplate (array &$struct) : bool
70
    {
71 5
        if (    !empty($struct['tableName']) && !empty($struct['primaryColumnName']) && !empty($struct['dataColumnName']) &&
72 5
                is_string($struct['tableName']) && is_string($struct['primaryColumnName']) && is_string($struct['dataColumnName'])
73
         ) :
74 5
            return true;
75
        else :
76
            return false;
77
        endif;
78
    }
79
80 5
    public function createTable () : void
81
    {
82
        try {
83 5
            $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 )');
84
        } catch (\Exception $e) {
85
            throw $e;
86
        }  
87 5
    }
88
89 5
    protected function initPrepareQuery () : void
90
    {
91 5
        $template = [];
92
93
        // Base - Small query ends
94 5
        $template['end_template'] = ';';
95 5
        $template['insert_template'] = 'INSERT INTO '.$this->_struct['tableName'].' ('.$this->_struct['primaryColumnName'].', '.$this->_struct['dataColumnName'].') VALUES ';
96 5
        $template['delete_template'] = 'DELETE FROM '.$this->_struct['tableName'].' WHERE '.$this->_struct['primaryColumnName'];
97 5
        $template['select_template'] = 'SELECT '.$this->_struct['primaryColumnName'].','.$this->_struct['dataColumnName'].' FROM '.$this->_struct['tableName'].' WHERE '.$this->_struct['primaryColumnName'];
98
99
        // Select the max / min key value. Usefull if array cursor is lost on DataManager.
100 5
        $this->_prepare['selectMaxKey'] = $this->_handler->prepare('SELECT max('.$this->_struct['primaryColumnName'].') FROM '.$this->_struct['tableName'] . $template['end_template']);
101 5
        $this->_prepare['selectMinKey'] = $this->_handler->prepare('SELECT min('.$this->_struct['primaryColumnName'].') FROM '.$this->_struct['tableName'] . $template['end_template']);
102
103
        // Insert many Entitys
104 5
            $makeMany = function ($how) use (&$template) {
105 5
                $query = $template['insert_template'];
106
                
107 5
                for ($i=1; $i < $how; $i++) :
108 5
                    $query .= '(:key'.$i.', :data'.$i.'),';
109
                endfor;
110
111 5
                $query .= '(:key'.$how.', :data'.$how.')' . $template['end_template'];
112
113 5
                return $query;
114 5
            };
115
116 5
            foreach (self::SEGMENT as $value) :
117 5
                $this->_prepare['insert'.$value.'Entitys'] = $this->_handler->prepare($makeMany($value));
118
            endforeach;
119
120
        // Delete one Entity
121 5
        $this->_prepare['deleteOneEntity'] = $this->_handler->prepare($template['delete_template'] . ' = ?' . $template['end_template']);
122
123
        // Get a Entity
124 5
        $this->_prepare['selectOneEntity'] = $this->_handler->prepare($template['select_template'] . ' = ?' . $template['end_template']);
125
126
        // Get a range of Entity
127 5
        $this->_prepare['selectRangeEntitys'] = $this->_handler->prepare($template['select_template'] . ' >= :startKey order by '.$this->_struct['primaryColumnName'].' asc LIMIT :limit' . $template['end_template']);
128
129
        // Count Entitys
130 5
        $this->_prepare['countEntitys'] = $this->_handler->prepare('SELECT count('.$this->_struct['primaryColumnName'].') FROM '. $this->_struct['tableName'] . $template['end_template']);
131 5
    }
132
133 5
    protected function initTransaction () : void
134
    {
135 5
        if (!$this->_transaction) :
136 5
            $this->_transaction = $this->_handler->beginTransaction();
137
        endif;
138 5
    }
139
140 5
    public function closeTransaction () : void
141
    {
142 5
        if ($this->_transaction === true) :
143 5
            if ($this->_queryError) :
144
                throw new CondorcetException;
145
            endif;
146
147 5
            $this->_transaction = !$this->_handler->commit();
148
        endif;
149 5
    }
150
151
152
    // DATA MANAGER
153 5
    public function insertEntitys (array $input) : void
154
    {
155 5
        $this->sliceInput($input);
156
157
        try {
158 5
            $this->initTransaction();
159
160 5
            foreach ($input as $group) :
161 5
                $param = [];
162 5
                $i = 1;
163 5
                $group_count = count($group);
164
165 5
                foreach ($group as $key => &$Entity) :
166 5
                    $param['key'.$i] = $key;
167 5
                    $param['data'.$i++] = $this->_dataContextObject->dataPrepareStoringAndFormat($Entity);
168
                endforeach;
169 5
                unset($Entity);
170
171 5
                $this->_prepare['insert'.$group_count.'Entitys']->execute(
172 5
                    $param
173
                );
174
175 5
                if ($this->_prepare['insert'.$group_count.'Entitys']->rowCount() !== $group_count) :
176
                    throw new CondorcetException (0,'Tous les Entitys n\'ont pas été insérés');
177
                endif;
178
179 5
                $this->_prepare['insert'.$group_count.'Entitys']->closeCursor();
180
            endforeach;
181
182 5
            $this->closeTransaction();
183
        } catch (\Exception $e) {
184
            $this->_queryError = true;
185
            throw $e;
186
        }
187 5
    }
188
189 5
        protected function sliceInput (array &$input) : void
190
        {
191 5
            $count = count($input);
192
193 5
            foreach (self::SEGMENT as $value) :
194 5
                if ($count >= $value) :
195 5
                    $input = array_chunk($input, $value, true);
196
197 5
                    $end = end($input);
198 5
                    if (count($input) > 1 && count($end) < $value) :
199
                        $this->sliceInput($end);
200
                        unset($input[key($input)]);
201
                        $input = array_merge($input,$end);
202
                    endif;
203 5
                    break;
204
                endif;
205
            endforeach;
206 5
        }
207
208
209 2
    public function deleteOneEntity (int $key, bool $justTry) : ?int
210
    {
211
        try {
212 2
            $this->_prepare['deleteOneEntity']->bindParam(1, $key, \PDO::PARAM_INT);
213 2
            $this->_prepare['deleteOneEntity']->execute();
214
215 2
            $deleteCount = $this->_prepare['deleteOneEntity']->rowCount();
216
217 2
            if (!$justTry && $deleteCount !== 1) :
218
                throw new CondorcetException (30);
219
            endif;
220
221 2
            $this->_prepare['deleteOneEntity']->closeCursor();
222
223 2
            return $deleteCount;
224
        } catch (\Exception $e) {
225
            $this->_queryError = true;
226
            throw $e;
227
        }
228
    }
229
230 1
    public function selectMaxKey () : ?int
231
    {
232 1
        if ($this->countEntitys() === 0) :
233
            return null;
234
        endif;
235
236
        try {
237 1
            $this->_prepare['selectMaxKey']->execute();
238 1
            $r = (int) $this->_prepare['selectMaxKey']->fetch(\PDO::FETCH_NUM)[0];
239 1
            $this->_prepare['selectMaxKey']->closeCursor();
240
241 1
            return $r;
242
        } catch (\Exception $e) {
243
            throw $e;
244
        }
245
    }
246
247 4
    public function selectMinKey () : int
248
    {
249
        try {
250 4
            $this->_prepare['selectMinKey']->execute();
251 4
            $r = (int) $this->_prepare['selectMinKey']->fetch(\PDO::FETCH_NUM)[0];
252 4
            $this->_prepare['selectMinKey']->closeCursor();
253
254 4
            return $r;
255
        } catch (\Exception $e) {
256
            throw $e;
257
        }
258
    }
259
260 5
    public function countEntitys () : int
261
    {
262
        try {
263 5
            $this->_prepare['countEntitys']->execute();
264 5
            $r = (int) $this->_prepare['countEntitys']->fetch(\PDO::FETCH_NUM)[0];
265 5
            $this->_prepare['countEntitys']->closeCursor();
266
267 5
            return $r;
268
        } catch (\Exception $e) {
269
            throw $e;
270
        }
271
    }
272
273
    // return false if Entity does not exist.
274 4
    public function selectOneEntity (int $key)
275
    {
276
        try {
277 4
            $this->_prepare['selectOneEntity']->bindParam(1, $key, \PDO::PARAM_INT);
278 4
            $this->_prepare['selectOneEntity']->execute();
279
            
280 4
            $r = $this->_prepare['selectOneEntity']->fetchAll(\PDO::FETCH_NUM);
281 4
            $this->_prepare['selectOneEntity']->closeCursor();
282 4
            if (!empty($r)) :
283 4
                return $this->_dataContextObject->dataCallBack( $r[0][1] );
284
            else :
285
                return false;
286
            endif;
287
        } catch (\Exception $e) {
288
            throw $e;
289
        }
290
    }
291
292 5
    public function selectRangeEntitys (int $key, int $limit) : array
293
    {
294
        try {
295 5
            $this->_prepare['selectRangeEntitys']->bindParam(':startKey', $key, \PDO::PARAM_INT);
296 5
            $this->_prepare['selectRangeEntitys']->bindParam(':limit', $limit, \PDO::PARAM_INT);
297 5
            $this->_prepare['selectRangeEntitys']->execute();
298
            
299 5
            $r = $this->_prepare['selectRangeEntitys']->fetchAll(\PDO::FETCH_NUM);
300 5
            $this->_prepare['selectRangeEntitys']->closeCursor();
301 5
            if (!empty($r)) :
302 5
                $result = [];
303 5
                foreach ($r as $value) :
304 5
                    $result[(int) $value[0]] = $this->_dataContextObject->dataCallBack( $value[1] );
305
                endforeach ;
306
307 5
                return $result;
308
            else :
309
                return [];
310
            endif;
311
        } catch (\Exception $e) {
312
            throw $e;
313
        }
314
    }
315
316
}