Base   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 368
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 2

Importance

Changes 0
Metric Value
dl 0
loc 368
rs 9.6
c 0
b 0
f 0
wmc 32
lcom 3
cbo 2

24 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A __destruct() 0 8 2
buildQuery() 0 1 ?
bindValues() 0 1 ?
B add() 0 19 5
B execute() 0 22 4
A finish() 0 15 3
A getAffectedCount() 0 4 1
A getItemsPerQuery() 0 4 1
A setItemsPerQuery() 0 6 1
A isIgnoreUsed() 0 4 1
A useIgnore() 0 6 1
A isIndexesDisabled() 0 4 1
A disableIndexes() 0 6 1
A getPreparedItems() 0 4 1
A getTotalItemsCount() 0 4 1
A getIgnoredColumn() 0 4 1
A addIgnoredColumn() 0 6 1
A purgeIgnoredColumns() 0 6 1
A getFields() 0 4 1
A getTable() 0 4 1
A getDbConnection() 0 4 1
A resetFields() 0 4 1
A resetPreparedItems() 0 4 1
1
<?php
2
3
namespace League\Database\BulkSql;
4
5
use PDOStatement;
6
use League\Database\Driver\TransactionPDO;
7
use League\Database\Exceptions\LogicException;
8
use League\Database\Interfaces\IGeneralSql;
9
use League\Database\Interfaces\IBulkSql;
10
11
abstract class Base implements IBulkSql, IGeneralSql
12
{
13
    /**
14
     * @var TransactionPDO  Connection to database
15
     */
16
    private $dbConnection;
17
18
    /**
19
     * @var string
20
     */
21
    private $table;
22
23
    /**
24
     * @var array   Column names
25
     */
26
    private $fields;
27
28
    /**
29
     * @var int     Items to be executed per query. Zero if executed once with finish()
30
     */
31
    private $itemsPerQuery = 0;
32
33
    /**
34
     * @var bool    Flag to use IGNORE in query
35
     */
36
    private $useIgnore = false;
37
38
    /**
39
     * @var bool    Flag to disable indexes during execution
40
     */
41
    private $disableIndexes = false;
42
43
    /**
44
     * @var array   Items data to be executed with query
45
     */
46
    private $preparedItems = [];
47
48
    /**
49
     * @var int     Total item count that were used in queries
50
     */
51
    private $totalItemsCount = 0;
52
53
    /**
54
     * @var int     Count of rows, that were affected by query execution
55
     */
56
    private $affectedCount = 0;
57
58
    /**
59
     * @var bool    Flag used to know if finish() method was called
60
     */
61
    private $isFinished = false;
62
63
    /**
64
     * @var array   Column which will not be bind via bindValue()
65
     */
66
    private $ignoreColumnBinding = [];
67
68
    /**
69
     * Base constructor.
70
     *
71
     * @param TransactionPDO $db
72
     * @param string         $table
73
     * @param array          $fields
74
     */
75
    public function __construct(TransactionPDO $db, string $table, array $fields = [])
76
    {
77
        $this->dbConnection = $db;
78
        $this->table = $table;
79
        $this->fields = $fields;
80
    }
81
82
    /**
83
     * Base destructor
84
     * Forcibly call finish() method, if queries wasn't executed
85
     *
86
     * @throws \League\Database\Exceptions\LogicException
87
     */
88
    public function __destruct()
89
    {
90
        if (!$this->isFinished) {
91
            $this->finish();
92
93
            throw new LogicException('You have to call finish() at the end of a BulkSql');
94
        }
95
    }
96
97
    /**
98
     * Build query line to be used for PDO prepare() method
99
     *
100
     * @return string
101
     */
102
    abstract protected function buildQuery() : string;
103
104
    /**
105
     * Bind params to PDO statement
106
     *
107
     * @param PDOStatement $statement
108
     *
109
     * @return mixed
110
     */
111
    abstract protected function bindValues(PDOStatement $statement);
112
113
    /**
114
     * Add new data to be executed
115
     *
116
     * @param array             $item
117
     *
118
     * @throws LogicException
119
     * @return bool             Return if it was executed
120
     */
121
    final public function add(array $item) : bool
122
    {
123
        if (count($this->fields) == 0) {
124
            $this->fields = array_keys($item);
125
        }
126
127
        if (count($item) !== count($this->fields)) {
128
            throw new LogicException('Number of columns doesn\'t match to number of columns names');
129
        }
130
131
        $this->preparedItems[] = $item;
132
133
        if ($this->itemsPerQuery !== 0 && count($this->preparedItems) % $this->itemsPerQuery == 0) {
134
            $this->execute();
135
            return true;
136
        } else {
137
            return false;
138
        }
139
    }
140
141
    /**
142
     * Execute query with prepared items
143
     *
144
     * @return void
145
     */
146
    final public function execute()
147
    {
148
        if (count($this->preparedItems) == 0) {
149
            return;
150
        }
151
152
        // On first query check disable indeces
153
        if ($this->isIndexesDisabled() && $this->affectedCount === 0) {
154
            $this->getDbConnection()->exec("ALTER TABLE {$this->getTable()} DISABLE KEYS");
155
        }
156
157
        $query = $this->buildQuery();
158
159
        // Run Query
160
        $statement = $this->getDbConnection()->prepare($query);
161
        $this->bindValues($statement);
162
        $statement->execute();
163
164
        $this->totalItemsCount += count($this->preparedItems);
165
        $this->affectedCount += $statement->rowCount();
166
        $this->preparedItems = [];
167
    }
168
169
    /**
170
     * Finish query execution
171
     *
172
     * @throws LogicException
173
     * @return void
174
     */
175
    final public function finish()
176
    {
177
        if ($this->isFinished) {
178
            throw new LogicException('Query cannot be executed any more in current instance of '.get_class($this));
179
        }
180
181
        $this->execute();
182
183
        // Re-enable indexes
184
        if ($this->isIndexesDisabled()) {
185
            $this->getDbConnection()->exec("ALTER TABLE {$this->getTable()} ENABLE KEYS");
186
        }
187
188
        $this->isFinished = true;
189
    }
190
191
    /**
192
     * Get count affected rows
193
     *
194
     * @return int
195
     */
196
    final public function getAffectedCount() : int
197
    {
198
        return $this->affectedCount;
199
    }
200
201
    /**
202
     * Get count of items that will be executed per one query
203
     *
204
     * @return int
205
     */
206
    final public function getItemsPerQuery() : int
207
    {
208
        return $this->itemsPerQuery;
209
    }
210
211
    /**
212
     * Set count of items that will be executed per one query
213
     *
214
     * @param int $itemsPerQuery
215
     *
216
     * @return $this
217
     */
218
    final public function setItemsPerQuery(int $itemsPerQuery) : self
219
    {
220
        $this->itemsPerQuery = $itemsPerQuery;
221
222
        return $this;
223
    }
224
225
    /**
226
     * Check if IGNORE will be used in query
227
     *
228
     * @return bool
229
     */
230
    final public function isIgnoreUsed(): bool
231
    {
232
        return $this->useIgnore;
233
    }
234
235
    /**
236
     * Set usage of IGNORE in query
237
     *
238
     * @param bool $useIgnore
239
     *
240
     * @return $this
241
     */
242
    final public function useIgnore(bool $useIgnore) : self
243
    {
244
        $this->useIgnore = $useIgnore;
245
246
        return $this;
247
    }
248
249
    /**
250
     * Check if indexes will be disabled while query execution
251
     *
252
     * @return bool
253
     */
254
    final public function isIndexesDisabled(): bool
255
    {
256
        return $this->disableIndexes;
257
    }
258
259
    /**
260
     * Set disabling indexes while query execution
261
     *
262
     * @param bool $disableIndexes
263
     *
264
     * @return $this
265
     */
266
    final public function disableIndexes(bool $disableIndexes) : self
267
    {
268
        $this->disableIndexes = $disableIndexes;
269
270
        return $this;
271
    }
272
273
    /**
274
     * Get prepared items to be executed
275
     *
276
     * @return array
277
     */
278
    public function getPreparedItems() : array
279
    {
280
        return $this->preparedItems;
281
    }
282
283
    /**
284
     * Get count of items used in query
285
     *
286
     * @return int
287
     */
288
    public function getTotalItemsCount() : int
289
    {
290
        return $this->totalItemsCount;
291
    }
292
293
    /**
294
     * Get column which will not be bind via bindValue()
295
     *
296
     * @return array
297
     */
298
    public function getIgnoredColumn() : array
299
    {
300
        return $this->ignoreColumnBinding;
301
    }
302
303
    /**
304
     * Set column which will not be bind via bindValue()
305
     *
306
     * @param string $ignoredColumn
307
     *
308
     * @return $this
309
     */
310
    public function addIgnoredColumn(string $ignoredColumn) : self
311
    {
312
        $this->ignoreColumnBinding[] = $ignoredColumn;
313
314
        return $this;
315
    }
316
317
    /**
318
     * Reset column which will be ignored via bindValue()
319
     *
320
     * @return $this
321
     */
322
    public function purgeIgnoredColumns() : self
323
    {
324
        $this->ignoreColumnBinding = [];
325
326
        return $this;
327
    }
328
329
    /**
330
     * Get column names
331
     *
332
     * @return array
333
     */
334
    final protected function getFields(): array
335
    {
336
        return $this->fields;
337
    }
338
339
    /**
340
     * Get table name
341
     *
342
     * @return string
343
     */
344
    final protected function getTable() : string
345
    {
346
        return $this->table;
347
    }
348
349
    /**
350
     * Get Database connection
351
     *
352
     * @return TransactionPDO
353
     */
354
    final protected function getDbConnection(): TransactionPDO
355
    {
356
        return $this->dbConnection;
357
    }
358
359
    /**
360
     * Reset fields array
361
     *
362
     * @return void
363
     */
364
    final protected function resetFields() : void
365
    {
366
        reset($this->fields);
367
    }
368
369
    /**
370
     * Reset items array
371
     *
372
     * @return void
373
     */
374
    final protected function resetPreparedItems() : void
375
    {
376
        reset($this->preparedItems);
377
    }
378
}
379