Completed
Push — dev-1.6.x ( e86a88...4ab371 )
by Boudry
03:36
created

PdoHandlerDriver::initPrepareQuery()   B

Complexity

Conditions 3
Paths 2

Size

Total Lines 46
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 46
ccs 23
cts 23
cp 1
rs 8.9411
c 0
b 0
f 0
cc 3
eloc 23
nc 2
nop 0
crap 3
1
<?php
1 ignored issue
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 16 and the first side effect is on line 219.

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.

Loading history...
2
/*
3
    Condorcet PHP Class, with Schulze Methods and others !
4
5
    By Julien Boudry - MIT LICENSE (Please read LICENSE.txt)
6
    https://github.com/julien-boudry/Condorcet
7
*/
8
declare(strict_types=1);
9
10
namespace Condorcet\DataManager\DataHandlerDrivers;
11
12
use Condorcet\DataManager\DataHandlerDrivers\DataHandlerDriverInterface;
13
use Condorcet\CondorcetException;
14
use Condorcet\CondorcetVersion;
15
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 4
    public function __construct (\PDO $bdd, bool $tryCreateTable = false, array $struct = ['tableName' => 'Entitys', 'primaryColumnName' => 'id', 'dataColumnName' => 'data'])
35
    {
36 4
        if (!$this->checkStructureTemplate($struct)) :
37
            throw new CondorcetException;
38
        endif;
39
40 4
        $this->_struct = $struct;
41
42 4
        $this->_handler = $bdd;
43
44 4
        $this->_handler->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
45
46 4
        if ($tryCreateTable) :
47 4
            $this->createTable();
48
        endif;
49
50 4
        $this->initPrepareQuery();
51 4
    }
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 4
    protected function checkStructureTemplate (array &$struct) : bool
67
    {
68 4
        if (    !empty($struct['tableName']) && !empty($struct['primaryColumnName']) && !empty($struct['dataColumnName']) &&
69 4
                is_string($struct['tableName']) && is_string($struct['primaryColumnName']) && is_string($struct['dataColumnName'])
70
         ) :
71 4
            return true;
72
        else :
73
            return false;
74
        endif;
75
    }
76
77 4
    public function createTable () : void
78
    {
79
        try {
80 4
            $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 4
    }
85
86 4
    protected function initPrepareQuery () : void
87
    {
88 4
        $template = [];
89
90
        // Base - Small query ends
91 4
        $template['end_template'] = ';';
92 4
        $template['insert_template'] = 'INSERT INTO '.$this->_struct['tableName'].' ('.$this->_struct['primaryColumnName'].', '.$this->_struct['dataColumnName'].') VALUES ';
93 4
        $template['delete_template'] = 'DELETE FROM '.$this->_struct['tableName'].' WHERE '.$this->_struct['primaryColumnName'];
94 4
        $template['select_template'] = 'SELECT '.$this->_struct['primaryColumnName'].','.$this->_struct['dataColumnName'].' FROM '.$this->_struct['tableName'].' WHERE '.$this->_struct['primaryColumnName'];
95
96
        // Select the max / min key value. Usefull if array cursor is lost on DataManager.
97 4
        $this->_prepare['selectMaxKey'] = $this->_handler->prepare('SELECT max('.$this->_struct['primaryColumnName'].') FROM '.$this->_struct['tableName'] . $template['end_template']);
98 4
        $this->_prepare['selectMinKey'] = $this->_handler->prepare('SELECT min('.$this->_struct['primaryColumnName'].') FROM '.$this->_struct['tableName'] . $template['end_template']);
99
100
        // Insert many Entitys
101 4
            $makeMany = function ($how) use (&$template) {
102 4
                $query = $template['insert_template'];
103
                
104 4
                for ($i=1; $i < $how; $i++) :
105 4
                    $query .= '(:key'.$i.', :data'.$i.'),';
106
                endfor;
107
108 4
                $query .= '(:key'.$how.', :data'.$how.')' . $template['end_template'];
109
110 4
                return $query;
111 4
            };
112
113 4
            foreach (self::SEGMENT as $value) :
114 4
                $this->_prepare['insert'.$value.'Entitys'] = $this->_handler->prepare($makeMany($value));
115
            endforeach;
116
117
        // Delete one Entity
118 4
        $this->_prepare['deleteOneEntity'] = $this->_handler->prepare($template['delete_template'] . ' = ?' . $template['end_template']);
119
120
        // Get a Entity
121 4
        $this->_prepare['selectOneEntity'] = $this->_handler->prepare($template['select_template'] . ' = ?' . $template['end_template']);
122
123
        // Get a range of Entity
124 4
        $this->_prepare['selectRangeEntitys'] = $this->_handler->prepare($template['select_template'] . ' >= :startKey order by '.$this->_struct['primaryColumnName'].' asc LIMIT :limit' . $template['end_template']);
125
126
        // Count Entitys
127 4
        $this->_prepare['countEntitys'] = $this->_handler->prepare('SELECT count('.$this->_struct['primaryColumnName'].') FROM '. $this->_struct['tableName'] . $template['end_template']);
128
129
        // Flush All
130 4
        $this->_prepare['flushAll'] = $this->_handler->prepare($template['delete_template'] . ' is not null' . $template['end_template']);
131 4
    }
132
133 4
    protected function initTransaction () : void
134
    {
135 4
        if (!$this->_transaction) :
136 4
            $this->_transaction = $this->_handler->beginTransaction();
137
        endif;
138 4
    }
139
140 4
    public function closeTransaction () : void
141
    {
142 4
        if ($this->_transaction === true) :
143 4
            if ($this->_queryError) :
144
                throw new CondorcetException;
145
            endif;
146
147 4
            $this->_transaction = !$this->_handler->commit();
148
        endif;
149 4
    }
150
151
152
    // DATA MANAGER
153 4
    public function insertEntitys (array $input) : void
154
    {
155 4
        $this->sliceInput($input);
156
157
        try {
158 4
            $this->initTransaction();
159
160 4
            foreach ($input as $group) :
161 4
                $param = [];
162 4
                $i = 1;
163 4
                $group_count = count($group);
164
165 4
                foreach ($group as $key => &$Entity) :
166 4
                    $param['key'.$i] = $key;
167 4
                    $param['data'.$i++] = $this->_dataContextObject->dataPrepareStoringAndFormat($Entity);
168
                endforeach;
169 4
                unset($Entity);
170
171 4
                $this->_prepare['insert'.$group_count.'Entitys']->execute(
172 4
                    $param
173
                );
174
175 4
                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 4
                $this->_prepare['insert'.$group_count.'Entitys']->closeCursor();
180
            endforeach;
181
182 4
            $this->closeTransaction();
183
        } catch (\Exception $e) {
184
            $this->_queryError = true;
185
            throw $e;
186
        }
187 4
    }
188
189 4
        protected function sliceInput (array &$input) : void
190
        {
191 4
            $count = count($input);
192
193 4
            foreach (self::SEGMENT as $value) :
194 4
                if ($count >= $value) :
195 4
                    $input = array_chunk($input, $value, true);
196
197 4
                    $end = end($input);
198 4
                    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 4
                    break;
204
                endif;
205
            endforeach;
206 4
        }
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 3
    public function selectMinKey () : int
248
    {
249
        try {
250 3
            $this->_prepare['selectMinKey']->execute();
251 3
            $r = (int) $this->_prepare['selectMinKey']->fetch(\PDO::FETCH_NUM)[0];
252 3
            $this->_prepare['selectMinKey']->closeCursor();
253
254 3
            return $r;
255
        } catch (\Exception $e) {
256
            throw $e;
257
        }
258
    }
259
260 4
    public function countEntitys () : int
261
    {
262
        try {
263 4
            $this->_prepare['countEntitys']->execute();
264 4
            $r = (int) $this->_prepare['countEntitys']->fetch(\PDO::FETCH_NUM)[0];
265 4
            $this->_prepare['countEntitys']->closeCursor();
266
267 4
            return $r;
268
        } catch (\Exception $e) {
269
            throw $e;
270
        }
271
    }
272
273
    // return false if Entity does not exist.
274 3
    public function selectOneEntity (int $key)
275
    {
276
        try {
277 3
            $this->_prepare['selectOneEntity']->bindParam(1, $key, \PDO::PARAM_INT);
278 3
            $this->_prepare['selectOneEntity']->execute();
279
            
280 3
            $r = $this->_prepare['selectOneEntity']->fetchAll(\PDO::FETCH_NUM);
281 3
            $this->_prepare['selectOneEntity']->closeCursor();
282 3
            if (!empty($r)) :
283 3
                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 4
    public function selectRangeEntitys (int $key, int $limit) : array
293
    {
294
        try {
295 4
            $this->_prepare['selectRangeEntitys']->bindParam(':startKey', $key, \PDO::PARAM_INT);
296 4
            $this->_prepare['selectRangeEntitys']->bindParam(':limit', $limit, \PDO::PARAM_INT);
297 4
            $this->_prepare['selectRangeEntitys']->execute();
298
            
299 4
            $r = $this->_prepare['selectRangeEntitys']->fetchAll(\PDO::FETCH_NUM);
300 4
            $this->_prepare['selectRangeEntitys']->closeCursor();
301 4
            if (!empty($r)) :
302 4
                $result = [];
303 4
                foreach ($r as $value) :
304 4
                    $result[(int) $value[0]] = $this->_dataContextObject->dataCallBack( $value[1] );
305
                endforeach ;
306
307 4
                return $result;
308
            else :
309
                return [];
310
            endif;
311
        } catch (\Exception $e) {
312
            throw $e;
313
        }
314
    }
315
316
    public function flushAll () : ?int
317
    {
318
        try {
319
            $this->_prepare['flushAll']->execute();
320
            $r = $this->_prepare['flushAll']->rowCount();
321
322
            $this->_prepare['flushAll']->closeCursor();
323
324
            return $r;
325
        } catch (\Exception $e) {
326
            $this->_queryError = true;
327
            throw $e;
328
        }      
329
    }
330
331
}