DbDiff::compareRowMode()   B
last analyzed

Complexity

Conditions 11
Paths 20

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
nc 20
nop 3
dl 0
loc 31
rs 7.3166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace Fwlib\Db;
3
4
use Fwlib\Bridge\Adodb;
5
use Fwlib\Util\UtilContainerAwareTrait;
6
7
/**
8
 * Compare db data before and after write
9
 *
10
 * Diff data array format:
11
 * {table: [{mode, 'pk': pk, 'column': column}]}
12
 *
13
 * mode is one of INSERT, DELETE, UPDATE.
14
 *
15
 * pk is array of primary key and their new/old value, format:
16
 * {pk: {new, old}}.
17
 *
18
 * column is array of other columns changed, format:
19
 * {column: {new, old}}.
20
 *
21
 * @deprecated
22
 *
23
 * @copyright   Copyright 2012-2015 Fwolf
24
 * @license     http://www.gnu.org/licenses/lgpl.html LGPL-3.0+
25
 */
26
class DbDiff
27
{
28
    use UtilContainerAwareTrait;
29
30
31
    /**
32
     * Counter of DbDiff changed rows
33
     *
34
     * @var int
35
     */
36
    protected $rowCount = 0;
37
38
    /**
39
     * @var Adodb
40
     */
41
    protected $db = null;
42
43
    /**
44
     * Diff data array
45
     *
46
     * @var array
47
     */
48
    protected $diff = [];
49
50
    /**
51
     * DbDiff execute status
52
     *
53
     * 0    not executed
54
     * 100  committed
55
     * -100 rollbacked
56
     *
57
     * @var int
58
     */
59
    protected $executeStatus = 0;
60
61
62
    /**
63
     * Constructor
64
     *
65
     * @param   Adodb   $db
66
     */
67
    public function __construct($db)
68
    {
69
        $this->db = $db;
70
    }
71
72
73
    /**
74
     * Check PK array is valid or throw exception
75
     *
76
     * @param   string  $table
77
     * @param   array   $pkArray
78
     * @param   array   &$rowArray
79
     */
80
    protected function checkPkArray($table, array $pkArray, array &$rowArray)
81
    {
82
        if (empty($pkArray)) {
83
            throw new \Exception(
84
                "Table $table must have PK defined"
85
            );
86
        }
87
88
        // array_intersect() is less loop than array_key_exist() check.
89
        // Can't use isset when do array_key_exist(), bcs isset(null) == false
90
        foreach ($rowArray as $index => &$row) {
91
            if (count($pkArray) !=
92
                count(array_intersect($pkArray, array_keys($row)))
93
            ) {
94
                throw new \Exception(
95
                    "PK not all assigned in new array," .
96
                    " table $table index $index"
97
                );
98
            }
99
        }
100
        unset($row);
101
    }
102
103
104
    /**
105
     * Commit diff result, change db
106
     *
107
     * @return  DbDiff
108
     */
109 View Code Duplication
    public function commit()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
110
    {
111
        if (empty($this->diff)) {
112
            throw new \Exception('No diff data');
113
        }
114
115
        if ($this->isCommitted()) {
116
            throw new \Exception(
117
                'Committed DbDiff can\'t commit again'
118
            );
119
        }
120
121
        $sqlArray = $this->generateCommitSql();
122
123
        $this->db->BeginTrans();
0 ignored issues
show
Documentation Bug introduced by
The method BeginTrans does not exist on object<Fwlib\Bridge\Adodb>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
124
125
        try {
126
            foreach ((array)$sqlArray as $sql) {
127
                $this->db->execute($sql);
128
129
                if (0 != $this->db->getErrorCode()) {
130
                    throw new \Exception($this->db->getErrorMessage());
131
                }
132
            }
133
134
            $this->db->CommitTrans();
0 ignored issues
show
Documentation Bug introduced by
The method CommitTrans does not exist on object<Fwlib\Bridge\Adodb>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
135
            $this->rowCount = count($sqlArray);
136
            $this->executeStatus = 100;
137
138
        } catch (\Exception $e) {
139
            $this->db->RollbackTrans();
0 ignored issues
show
Documentation Bug introduced by
The method RollbackTrans does not exist on object<Fwlib\Bridge\Adodb>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
140
141
            throw new \Exception($e->getMessage());
142
        }
143
144
        return $this;
145
    }
146
147
148
    /**
149
     * Compare new data with old data in db
150
     *
151
     * New/old array are all assoc, index by table column.  PK column must
152
     * included in new array, but its value can be null.
153
     *
154
     * In new array, null PK value means DELETE operate.
155
     * In old array, null PK value means INSERT operate.
156
     *
157
     * Multi table and row supported.
158
     *
159
     * New/old array format:
160
     * {table: [{column: value}]}
161
     * If only need to change a single row, can use simple format:
162
     * {table: {column: value}}
163
     *
164
     * If old array is null, will read its value from db by Pk in new array.
165
     *
166
     * Row index in new/old array must match, it is used to connect same row
167
     * in new and old data, so either use a meaningful row index, or use default
168
     * integer index and keep same data order in new and old.
169
     *
170
     * @param   array   $dataNew
171
     * @param   array   $dataOld
172
     * @return  DbDiff
173
     */
174
    public function compare(array $dataNew, array $dataOld = null)
175
    {
176
        if (empty($dataNew)) {
177
            throw new \Exception('New data array can\'t be empty');
178
        }
179
180
181
        $diff = [];
182
        foreach ($dataNew as $table => &$rowArrayNew) {
183
            // Convert row array to 2-dim array
184
            if (!is_array(current($rowArrayNew))) {
185
                $rowArrayNew = [$rowArrayNew];
186
            }
187
188
            $pkArray = (array)$this->db->getMetaPrimaryKey($table);
189
            $this->checkPkArray($table, $pkArray, $rowArrayNew);
190
191
            $diffOfTable = $this->compareTable(
192
                $table,
193
                $pkArray,
194
                $rowArrayNew,
195
                $dataOld
196
            );
197
198
            if (!empty($diffOfTable)) {
199
                $diff[$table] = $diffOfTable;
200
            }
201
        }
202
        unset($rowArrayNew);
203
204
        $this->diff = $diff;
205
206
        return $this;
207
    }
208
209
210
    /**
211
     * Compare different of a single row
212
     *
213
     * $rowNew MUST contain all PK columns.
214
     *
215
     * @param   array   &$rowNew
216
     * @param   array   $pkArray
217
     * @param   array   &$rowOld
218
     * @return  array
219
     */
220
    protected function compareRow(
221
        array &$rowNew,
222
        array $pkArray,
223
        array &$rowOld = null
224
    ) {
225
        $mode = $this->compareRowMode($rowNew, $pkArray, $rowOld);
226
227
        $pkDiff = $this->compareRowPk($rowNew, $pkArray, $rowOld);
228
229
        $columnArray = array_keys($rowNew);
230
        if (!is_null($rowOld)) {
231
            $columnArray = array_merge(array_keys($rowOld));
232
        }
233
        $columnDiff = $this->compareRowColumn(
234
            $mode,
235
            $rowNew,
236
            $columnArray,
237
            $rowOld
238
        );
239
240
        // UPDATE with no column change will be skipped
241
        if ('UPDATE' == $mode && empty($columnDiff)) {
242
            return null;
243
244
        } else {
245
            return [
246
                'mode'   => $mode,
247
                'pk'     => $pkDiff,
248
                'column' => $columnDiff,
249
            ];
250
        }
251
    }
252
253
254
    /**
255
     * Compare column values, return diff array
256
     *
257
     * Pk column should be removed already.
258
     *
259
     * @param   string  $mode
260
     * @param   array   &$rowNew
261
     * @param   array   $columnArray
262
     * @param   array   &$rowOld
263
     * @return  array
264
     */
265
    protected function compareRowColumn(
266
        $mode,
267
        array &$rowNew,
268
        array $columnArray,
269
        array &$rowOld = null
270
    ) {
271
        $diff = [];
272
273
        foreach ((array)$columnArray as $column) {
274
            $valueNew = isset($rowNew[$column]) ? $rowNew[$column] : null;
275
            $valueOld = isset($rowOld[$column]) ? $rowOld[$column] : null;
276
277
            // Set useless column data to null. New value in DELETE mode is
278
            // useless, and old value in INSERT mode is useless too.
279
            if ('DELETE' == $mode) {
280
                $valueNew = null;
281
            }
282
            if ('INSERT' == $mode) {
283
                $valueOld = null;
284
            }
285
286
            // Skip equal value, they are not included in result diff array.
287
            // Change between null and non-null value (include '' and 0,
288
            // although they == null) will be kept. But 1 == '1' will be
289
            // skipped, so not using === and check equal only if both value
290
            // are not null.
291
            if ((is_null($valueNew) && is_null($valueOld)) ||
292
                (!is_null($valueNew) && !is_null($valueOld) &&
293
                    $valueNew == $valueOld)
294
            ) {
295
                continue;
296
            }
297
298
            $diff[$column] = [
299
                'new'   => $valueNew,
300
                'old'   => $valueOld,
301
            ];
302
        }
303
304
        return $diff;
305
    }
306
307
308
309
310
    /**
311
     * Get compare mode of a single row
312
     *
313
     * Mode: INSERT/UPDATE/DELETE
314
     *
315
     * Empty PK value are allowed, but null PK value will change mode flag and
316
     * ignore other non-null pk column values.
317
     *
318
     * @param   array   &$rowNew
319
     * @param   array   $pkArray
320
     * @param   array   &$rowOld
321
     * @return  string
322
     */
323
    protected function compareRowMode(
324
        array &$rowNew,
325
        array $pkArray,
326
        array &$rowOld = null
327
    ) {
328
        $nullPkInNew = false;
329
        $nullPkInOld = false;
330
331
        foreach ($pkArray as $pk) {
332
            if (is_null($rowNew[$pk])) {
333
                $nullPkInNew = true;
334
            }
335
            if (!isset($rowOld[$pk]) || is_null($rowOld[$pk])) {
336
                $nullPkInOld = true;
337
            }
338
        }
339
340
        if ($nullPkInNew && !$nullPkInOld) {
341
            $mode = 'DELETE';
342
        } elseif (!$nullPkInNew && $nullPkInOld) {
343
            $mode = 'INSERT';
344
        } elseif (!$nullPkInNew && !$nullPkInOld) {
345
            $mode = 'UPDATE';
346
        } else {
347
            throw new \Exception(
348
                'Pk in new and old array are all null'
349
            );
350
        }
351
352
        return $mode;
353
    }
354
355
356
    /**
357
     * Compare and extract PK values, return diff array
358
     *
359
     * Pk column are removed from new and old row columns.
360
     *
361
     * @param   array   &$rowNew
362
     * @param   array   $pkArray
363
     * @param   array   &$rowOld
364
     * @return  array
365
     */
366
    protected function compareRowPk(
367
        array &$rowNew,
368
        array $pkArray,
369
        array &$rowOld = null
370
    ) {
371
        $diff = [];
372
373
        foreach ($pkArray as $pk) {
374
            $diff[$pk] = [
375
                'new'   => $rowNew[$pk],
376
                'old'   => isset($rowOld[$pk]) ? $rowOld[$pk] : null,
377
            ];
378
379
            unset($rowNew[$pk]);
380
            unset($rowOld[$pk]);
381
        }
382
383
        return $diff;
384
    }
385
386
387
    /**
388
     * Compare different for a single table
389
     *
390
     * @param   string  $table
391
     * @param   array   $pkArray
392
     * @param   array   &$rowArrayNew
393
     * @param   array   &$dataOld
394
     * @return  array
395
     */
396
    protected function compareTable(
397
        $table,
398
        array $pkArray,
399
        array &$rowArrayNew,
400
        array &$dataOld = null
401
    ) {
402
        $diff = [];
403
        foreach ($rowArrayNew as $index => &$rowNew) {
404
            $columnArray = array_keys($rowNew);
405
            $pkValueArray = array_intersect_key(
406
                $rowNew,
407
                array_fill_keys($pkArray, null)
408
            );
409
410
            $rowOld = $this->prepareRowOld(
411
                $table,
412
                $index,
413
                $pkValueArray,
414
                $columnArray,
415
                $pkArray,
416
                $dataOld
417
            );
418
419
            $diffOfRow = $this->compareRow($rowNew, $pkArray, $rowOld);
420
            if (!empty($diffOfRow)) {
421
                $diff[] = $diffOfRow;
422
            }
423
        }
424
        unset($rowOld);
425
426
        return $diff;
427
    }
428
429
430
    /**
431
     * Compare and commit diff result
432
     *
433
     * If $dataNew is null, will use internal stored $diff.
434
     *
435
     * @param   array   $dataNew
436
     * @param   array   $dataOld
437
     * @return  DbDiff
438
     */
439
    public function execute(array $dataNew = null, array $dataOld = null)
440
    {
441
        if (!is_null($dataNew)) {
442
            $this->reset();
443
            $this->compare($dataNew, $dataOld);
444
        }
445
446
        if (!$this->isExecuted()) {
447
            $this->commit();
448
449
        } else {
450
            throw new \Exception(
451
                'Committed or rollbacked DbDiff can\'t execute again'
452
            );
453
        }
454
455
        return $this;
456
    }
457
458
459
    /**
460
     * Export to json string
461
     *
462
     * @return  string
463
     */
464
    public function export()
465
    {
466
        $json = $this->getUtilContainer()->getJson();
467
468
        return $json->encodeUnicode(
469
            [
470
                'rowCount'  => $this->rowCount,
471
                'executeStatus' => $this->executeStatus,
472
                'diff'          => $this->diff,
473
            ]
474
        );
475
    }
476
477
478
    /**
479
     * Generate commit sql array from diff result
480
     *
481
     * @return  array
482
     */
483 View Code Duplication
    protected function generateCommitSql()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
484
    {
485
        $sqlArray = [];
486
        $db = $this->db;
487
488
        foreach ($this->diff as $table => $rowArray) {
489
            foreach ((array)$rowArray as $index => $row) {
490
                $sqlConfig = [];
491
492
                switch ($row['mode']) {
493
                    case 'INSERT':
494
                        $sqlConfig['INSERT'] = $table;
495
496
                        $columnArray = $row['pk'] + $row['column'];
497
                        foreach ($columnArray as $k => $v) {
498
                            $sqlConfig['VALUES'][$k] = $v['new'];
499
                        }
500
501
                        break;
502
503
                    case 'DELETE':
504
                        $sqlConfig['DELETE'] = $table;
505
                        // Limit row count to 1 for safety
506
                        $sqlConfig['LIMIT'] = 1;
507
508
                        foreach ($row['pk'] as $k => $v) {
509
                            $sqlConfig['WHERE'][] = $k . ' = ' .
510
                                $db->quoteValue($table, $k, $v['old']);
511
                        }
512
513
                        break;
514
515
                    case 'UPDATE':
516
                        $sqlConfig['UPDATE'] = $table;
517
                        // Limit row count to 1 for safety
518
                        $sqlConfig['LIMIT'] = 1;
519
520
                        foreach ($row['column'] as $k => $v) {
521
                            $sqlConfig['SET'][$k] = $v['new'];
522
                        }
523
524
                        foreach ($row['pk'] as $k => $v) {
525
                            $sqlConfig['WHERE'][] = $k . ' = ' .
526
                                $db->quoteValue($table, $k, $v['new']);
527
                        }
528
529
                        break;
530
531
                    default:
532
                        throw new \Exception("Invalid mode {$row['mode']}");
533
                }
534
535
                $sqlArray[] = $db->generateSql($sqlConfig);
536
            }
537
        }
538
539
        return $sqlArray;
540
    }
541
542
543
    /**
544
     * Generate rollback sql array from diff result
545
     *
546
     * @return  array
547
     */
548 View Code Duplication
    protected function generateRollbackSql()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
549
    {
550
        $sqlArray = [];
551
        $db = $this->db;
552
553
        foreach ($this->diff as $table => $rowArray) {
554
            foreach ((array)$rowArray as $index => $row) {
555
                $sqlConfig = [];
556
557
                switch ($row['mode']) {
558
                    case 'INSERT':
559
                        $sqlConfig['DELETE'] = $table;
560
                        // Limit row count to 1 for safety
561
                        $sqlConfig['LIMIT'] = 1;
562
563
                        foreach ($row['pk'] as $k => $v) {
564
                            $sqlConfig['WHERE'][] = $k . ' = ' .
565
                                $db->quoteValue($table, $k, $v['new']);
566
                        }
567
568
                        break;
569
570
                    case 'DELETE':
571
                        $sqlConfig['INSERT'] = $table;
572
573
                        $columnArray = $row['pk'] + $row['column'];
574
                        foreach ($columnArray as $k => $v) {
575
                            $sqlConfig['VALUES'][$k] = $v['old'];
576
                        }
577
578
                        break;
579
580
                    case 'UPDATE':
581
                        $sqlConfig['UPDATE'] = $table;
582
                        // Limit row count to 1 for safety
583
                        $sqlConfig['LIMIT'] = 1;
584
585
                        foreach ($row['column'] as $k => $v) {
586
                            $sqlConfig['SET'][$k] = $v['old'];
587
                        }
588
589
                        foreach ($row['pk'] as $k => $v) {
590
                            $sqlConfig['WHERE'][] = $k . ' = ' .
591
                                $db->quoteValue($table, $k, $v['old']);
592
                        }
593
594
                        break;
595
596
                    default:
597
                        throw new \Exception("Invalid mode {$row['mode']}");
598
                }
599
600
                $sqlArray[] = $db->generateSql($sqlConfig);
601
            }
602
        }
603
604
        return $sqlArray;
605
    }
606
607
608
    /**
609
     * Getter of $diff
610
     *
611
     * @return  array
612
     */
613
    public function getDiff()
614
    {
615
        return $this->diff;
616
    }
617
618
619
    /**
620
     * Getter of $rowCount
621
     *
622
     * @return  int
623
     */
624
    public function getRowCount()
625
    {
626
        return $this->rowCount;
627
    }
628
629
630
    /**
631
     * Import from a json string
632
     *
633
     * Notice: Import empty string will report error.
634
     *
635
     * @param   string  $json
636
     * @return  DbDiff
637
     */
638
    public function import($json)
639
    {
640
        $this->reset();
641
642
        $info = $this->getUtilContainer()->getJson()
643
            ->decode($json, true);
644
645
        try {
646
            $this->rowCount = $info['rowCount'];
647
            $this->executeStatus = $info['executeStatus'];
648
            $this->diff = $info['diff'];
649
650
        } catch (\Exception $e) {
651
            throw new \Exception(
652
                'Invalid json string to import: ' . $e->getMessage()
653
            );
654
        }
655
656
        return $this;
657
    }
658
659
660
    /**
661
     * Is DbDiff executed/committed ?
662
     *
663
     * @return  bool
664
     */
665
    public function isCommitted()
666
    {
667
        return 100 == $this->executeStatus;
668
    }
669
670
671
    /**
672
     * Is DbDiff executed ?
673
     *
674
     * Return true when committed or rollbacked.
675
     *
676
     * @return  bool
677
     */
678
    public function isExecuted()
679
    {
680
        return 0 != $this->executeStatus;
681
    }
682
683
684
    /**
685
     * Is DbDiff rollbacked ?
686
     *
687
     * @return  bool
688
     */
689
    public function isRollbacked()
690
    {
691
        return -100 == $this->executeStatus;
692
    }
693
694
695
    /**
696
     * Prepare a single old row for compare
697
     *
698
     * If old row are not set, will query db using pk value from new row,
699
     * return null for not exists(INSERT mode).
700
     *
701
     * Also convert old row array to 2-dim.
702
     *
703
     * @param   string      $table
704
     * @param   int|string  $index
705
     * @param   array       $pkValueArray
0 ignored issues
show
Bug introduced by
There is no parameter named $pkValueArray. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
706
     * @param   array       $columnArray
707
     * @param   array       $pkArray
0 ignored issues
show
Bug introduced by
There is no parameter named $pkArray. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
708
     * @param   array       &$dataOld
709
     * @return  array
710
     */
711
    protected function prepareRowOld(
712
        $table,
713
        $index,
714
        array $keyValueArray,
715
        array $columnArray,
716
        array $keyArray,
717
        array &$dataOld = null
718
    ) {
719
        // Convert to 2-dim array
720
        if (isset($dataOld[$table]) && !is_array(current($dataOld[$table]))) {
721
            $dataOld[$table] = [$dataOld[$table]];
722
        }
723
724
        if (isset($dataOld[$table][$index])) {
725
            return $dataOld[$table][$index];
726
        }
727
728
        // Need query from db
729
        $rs = $this->db->getByKey(
730
            $table,
731
            $keyValueArray,
0 ignored issues
show
Documentation introduced by
$keyValueArray is of type array, but the function expects a integer|string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
732
            $columnArray,
733
            $keyArray
734
        );
735
736
        // If row only have one column, convert back to array
737
        $rs = is_null($rs) ? $rs : (array)$rs;
738
739
        return $rs;
740
    }
741
742
743
    /**
744
     * Reset code, message and flag
745
     *
746
     * @return  DbDiff
747
     */
748
    public function reset()
749
    {
750
        $this->rowCount = 0;
751
        $this->executeStatus = 0;
752
        $this->diff = [];
753
754
        return $this;
755
    }
756
757
758
    /**
759
     * Rollback committed diff result
760
     *
761
     * @return  DbDiff
762
     */
763 View Code Duplication
    public function rollback()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
764
    {
765
        if (empty($this->diff)) {
766
            throw new \Exception('No diff data');
767
        }
768
769
        if ($this->isRollbacked()) {
770
            throw new \Exception(
771
                'Rollbacked DbDiff can\'t rollback again'
772
            );
773
        }
774
775
        $sqlArray = $this->generateRollbackSql();
776
777
        $this->db->BeginTrans();
0 ignored issues
show
Documentation Bug introduced by
The method BeginTrans does not exist on object<Fwlib\Bridge\Adodb>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
778
779
        try {
780
            foreach ((array)$sqlArray as $sql) {
781
                $this->db->execute($sql);
782
783
                if (0 != $this->db->getErrorCode()) {
784
                    throw new \Exception($this->db->getErrorMessage());
785
                }
786
            }
787
788
            $this->db->CommitTrans();
0 ignored issues
show
Documentation Bug introduced by
The method CommitTrans does not exist on object<Fwlib\Bridge\Adodb>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
789
            // Rollback operate doesn't change $rowCount
790
            $this->executeStatus = -100;
791
792
        } catch (\Exception $e) {
793
            $this->db->RollbackTrans();
0 ignored issues
show
Documentation Bug introduced by
The method RollbackTrans does not exist on object<Fwlib\Bridge\Adodb>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
794
795
            throw new \Exception($e->getMessage());
796
        }
797
798
        return $this;
799
    }
800
}
801