Completed
Push — dev-1.6.x ( f43552...3412fc )
by Boudry
16:50
created

PdoHandlerDriver::__destruct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.1481

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 4
cts 6
cp 0.6667
rs 9.6666
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 0
crap 2.1481
1
<?php
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 4
    }
129
130 4
    protected function initTransaction () : void
131
    {
132 4
        if (!$this->_transaction) :
133 4
            $this->_transaction = $this->_handler->beginTransaction();
134
        endif;
135 4
    }
136
137 4
    public function closeTransaction () : void
138
    {
139 4
        if ($this->_transaction === true) :
140 4
            if ($this->_queryError) :
141
                throw new CondorcetException;
142
            endif;
143
144 4
            $this->_transaction = !$this->_handler->commit();
145
        endif;
146 4
    }
147
148
149
    // DATA MANAGER
150 4
    public function insertEntitys (array $input) : void
151
    {
152 4
        $this->sliceInput($input);
153
154
        try {
155 4
            $this->initTransaction();
156
157 4
            foreach ($input as $group) :
158 4
                $param = [];
159 4
                $i = 1;
160 4
                $group_count = count($group);
161
162 4
                foreach ($group as $key => &$Entity) :
163 4
                    $param['key'.$i] = $key;
164 4
                    $param['data'.$i++] = $this->_dataContextObject->dataPrepareStoringAndFormat($Entity);
165
                endforeach;
166 4
                unset($Entity);
167
168 4
                $this->_prepare['insert'.$group_count.'Entitys']->execute(
169 4
                    $param
170
                );
171
172 4
                if ($this->_prepare['insert'.$group_count.'Entitys']->rowCount() !== $group_count) :
173
                    throw new CondorcetException (0,'Tous les Entitys n\'ont pas été insérés');
174
                endif;
175
176 4
                $this->_prepare['insert'.$group_count.'Entitys']->closeCursor();
177
            endforeach;
178
179 4
            $this->closeTransaction();
180
        } catch (\Exception $e) {
181
            $this->_queryError = true;
182
            throw $e;
183
        }
184 4
    }
185
186 4
        protected function sliceInput (array &$input) : void
187
        {
188 4
            $count = count($input);
189
190 4
            foreach (self::SEGMENT as $value) :
191 4
                if ($count >= $value) :
192 4
                    $input = array_chunk($input, $value, true);
193
194 4
                    $end = end($input);
195 4
                    if (count($input) > 1 && count($end) < $value) :
196
                        $this->sliceInput($end);
197
                        unset($input[key($input)]);
198
                        $input = array_merge($input,$end);
199
                    endif;
200 4
                    break;
201
                endif;
202
            endforeach;
203 4
        }
204
205
206 2
    public function deleteOneEntity (int $key, bool $justTry) : ?int
207
    {
208
        try {
209 2
            $this->_prepare['deleteOneEntity']->bindParam(1, $key, \PDO::PARAM_INT);
210 2
            $this->_prepare['deleteOneEntity']->execute();
211
212 2
            $deleteCount = $this->_prepare['deleteOneEntity']->rowCount();
213
214 2
            if (!$justTry && $deleteCount !== 1) :
215
                throw new CondorcetException (30);
216
            endif;
217
218 2
            $this->_prepare['deleteOneEntity']->closeCursor();
219
220 2
            return $deleteCount;
221
        } catch (\Exception $e) {
222
            $this->_queryError = true;
223
            throw $e;
224
        }
225
    }
226
227 1
    public function selectMaxKey () : ?int
228
    {
229 1
        if ($this->countEntitys() === 0) :
230
            return null;
231
        endif;
232
233
        try {
234 1
            $this->_prepare['selectMaxKey']->execute();
235 1
            $r = (int) $this->_prepare['selectMaxKey']->fetch(\PDO::FETCH_NUM)[0];
236 1
            $this->_prepare['selectMaxKey']->closeCursor();
237
238 1
            return $r;
239
        } catch (\Exception $e) {
240
            throw $e;
241
        }
242
    }
243
244 3
    public function selectMinKey () : int
245
    {
246
        try {
247 3
            $this->_prepare['selectMinKey']->execute();
248 3
            $r = (int) $this->_prepare['selectMinKey']->fetch(\PDO::FETCH_NUM)[0];
249 3
            $this->_prepare['selectMinKey']->closeCursor();
250
251 3
            return $r;
252
        } catch (\Exception $e) {
253
            throw $e;
254
        }
255
    }
256
257 4
    public function countEntitys () : int
258
    {
259
        try {
260 4
            $this->_prepare['countEntitys']->execute();
261 4
            $r = (int) $this->_prepare['countEntitys']->fetch(\PDO::FETCH_NUM)[0];
262 4
            $this->_prepare['countEntitys']->closeCursor();
263
264 4
            return $r;
265
        } catch (\Exception $e) {
266
            throw $e;
267
        }
268
    }
269
270
    // return false if Entity does not exist.
271 3
    public function selectOneEntity (int $key)
272
    {
273
        try {
274 3
            $this->_prepare['selectOneEntity']->bindParam(1, $key, \PDO::PARAM_INT);
275 3
            $this->_prepare['selectOneEntity']->execute();
276
            
277 3
            $r = $this->_prepare['selectOneEntity']->fetchAll(\PDO::FETCH_NUM);
278 3
            $this->_prepare['selectOneEntity']->closeCursor();
279 3
            if (!empty($r)) :
280 3
                return $this->_dataContextObject->dataCallBack( $r[0][1] );
281
            else :
282
                return false;
283
            endif;
284
        } catch (\Exception $e) {
285
            throw $e;
286
        }
287
    }
288
289 4
    public function selectRangeEntitys (int $key, int $limit) : array
290
    {
291
        try {
292 4
            $this->_prepare['selectRangeEntitys']->bindParam(':startKey', $key, \PDO::PARAM_INT);
293 4
            $this->_prepare['selectRangeEntitys']->bindParam(':limit', $limit, \PDO::PARAM_INT);
294 4
            $this->_prepare['selectRangeEntitys']->execute();
295
            
296 4
            $r = $this->_prepare['selectRangeEntitys']->fetchAll(\PDO::FETCH_NUM);
297 4
            $this->_prepare['selectRangeEntitys']->closeCursor();
298 4
            if (!empty($r)) :
299 4
                $result = [];
300 4
                foreach ($r as $value) :
301 4
                    $result[(int) $value[0]] = $this->_dataContextObject->dataCallBack( $value[1] );
302
                endforeach ;
303
304 4
                return $result;
305
            else :
306
                return [];
307
            endif;
308
        } catch (\Exception $e) {
309
            throw $e;
310
        }
311
    }
312
313
}