Completed
Push — ezp-26146_location_swap_incons... ( 268337 )
by
unknown
82:52 queued 48:18
created

DoctrineDatabase::swap()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 73
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 4
eloc 53
c 1
b 1
f 0
nc 4
nop 2
dl 0
loc 73
rs 8.6829

How to fix   Long Method   

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
3
/**
4
 * File containing the DoctrineDatabase UrlAlias Gateway class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 *
9
 * @version //autogentag//
10
 */
11
namespace eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\Gateway;
12
13
use eZ\Publish\Core\Persistence\Legacy\Content\UrlAlias\Gateway;
14
use eZ\Publish\Core\Persistence\Database\DatabaseHandler;
15
use eZ\Publish\Core\Persistence\Legacy\Content\Language\MaskGenerator as LanguageMaskGenerator;
16
use eZ\Publish\Core\Persistence\Database\Query;
17
18
/**
19
 * UrlAlias Gateway.
20
 */
21
class DoctrineDatabase extends Gateway
22
{
23
    /**
24
     * 2^30, since PHP_INT_MAX can cause overflows in DB systems, if PHP is run
25
     * on 64 bit systems.
26
     */
27
    const MAX_LIMIT = 1073741824;
28
29
    /**
30
     * Columns of database tables.
31
     *
32
     * @var array
33
     *
34
     * @todo remove after testing
35
     */
36
    protected $columns = array(
37
        'ezurlalias_ml' => array(
38
            'action',
39
            'action_type',
40
            'alias_redirects',
41
            'id',
42
            'is_alias',
43
            'is_original',
44
            'lang_mask',
45
            'link',
46
            'parent',
47
            'text',
48
            'text_md5',
49
        ),
50
    );
51
52
    /**
53
     * Doctrine database handler.
54
     *
55
     * @var \eZ\Publish\Core\Persistence\Database\DatabaseHandler
56
     */
57
    protected $dbHandler;
58
59
    /**
60
     * Language mask generator.
61
     *
62
     * @var \eZ\Publish\Core\Persistence\Legacy\Content\Language\MaskGenerator
63
     */
64
    protected $languageMaskGenerator;
65
66
    /**
67
     * Creates a new DoctrineDatabase UrlAlias Gateway.
68
     *
69
     * @param \eZ\Publish\Core\Persistence\Database\DatabaseHandler $dbHandler
70
     * @param \eZ\Publish\Core\Persistence\Legacy\Content\Language\MaskGenerator $languageMaskGenerator
71
     */
72
    public function __construct(
73
        DatabaseHandler $dbHandler,
74
        LanguageMaskGenerator $languageMaskGenerator
75
    ) {
76
        $this->dbHandler = $dbHandler;
77
        $this->languageMaskGenerator = $languageMaskGenerator;
78
    }
79
80
    /**
81
     * Loads list of aliases by given $locationId.
82
     *
83
     * @param mixed $locationId
84
     * @param bool $custom
85
     * @param mixed $languageId
86
     *
87
     * @return array
88
     */
89
    public function loadLocationEntries($locationId, $custom = false, $languageId = false)
90
    {
91
        /** @var $query \eZ\Publish\Core\Persistence\Database\SelectQuery */
92
        $query = $this->dbHandler->createSelectQuery();
93
        $query->select(
94
            $this->dbHandler->quoteColumn('id'),
95
            $this->dbHandler->quoteColumn('link'),
96
            $this->dbHandler->quoteColumn('is_alias'),
97
            $this->dbHandler->quoteColumn('alias_redirects'),
98
            $this->dbHandler->quoteColumn('lang_mask'),
99
            $this->dbHandler->quoteColumn('is_original'),
100
            $this->dbHandler->quoteColumn('parent'),
101
            $this->dbHandler->quoteColumn('text'),
102
            $this->dbHandler->quoteColumn('text_md5'),
103
            $this->dbHandler->quoteColumn('action')
104
        )->from(
105
            $this->dbHandler->quoteTable('ezurlalias_ml')
106
        )->where(
107
            $query->expr->lAnd(
108
                $query->expr->eq(
109
                    $this->dbHandler->quoteColumn('action'),
110
                    $query->bindValue("eznode:{$locationId}", null, \PDO::PARAM_STR)
111
                ),
112
                $query->expr->eq(
113
                    $this->dbHandler->quoteColumn('is_original'),
114
                    $query->bindValue(1, null, \PDO::PARAM_INT)
115
                ),
116
                $query->expr->eq(
117
                    $this->dbHandler->quoteColumn('is_alias'),
118
                    $query->bindValue(
119
                        $custom ? 1 : 0,
120
                        null,
121
                        \PDO::PARAM_INT
122
                    )
123
                )
124
            )
125
        );
126
127 View Code Duplication
        if ($languageId !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
128
            $query->where(
129
                $query->expr->gt(
130
                    $query->expr->bitAnd(
131
                        $this->dbHandler->quoteColumn('lang_mask'),
132
                        $query->bindValue($languageId, null, \PDO::PARAM_INT)
133
                    ),
134
                    0
135
                )
136
            );
137
        }
138
139
        $statement = $query->prepare();
140
        $statement->execute();
141
142
        return $statement->fetchAll(\PDO::FETCH_ASSOC);
143
    }
144
145
    /**
146
     * Loads paged list of global aliases.
147
     *
148
     * @param string|null $languageCode
149
     * @param int $offset
150
     * @param int $limit
151
     *
152
     * @return array
153
     */
154
    public function listGlobalEntries($languageCode = null, $offset = 0, $limit = -1)
155
    {
156
        $limit = $limit === -1 ? self::MAX_LIMIT : $limit;
157
158
        /** @var $query \eZ\Publish\Core\Persistence\Database\SelectQuery */
159
        $query = $this->dbHandler->createSelectQuery();
160
        $query->select(
161
            $this->dbHandler->quoteColumn('action'),
162
            $this->dbHandler->quoteColumn('id'),
163
            $this->dbHandler->quoteColumn('link'),
164
            $this->dbHandler->quoteColumn('is_alias'),
165
            $this->dbHandler->quoteColumn('alias_redirects'),
166
            $this->dbHandler->quoteColumn('lang_mask'),
167
            $this->dbHandler->quoteColumn('is_original'),
168
            $this->dbHandler->quoteColumn('parent'),
169
            $this->dbHandler->quoteColumn('text_md5')
170
        )->from(
171
            $this->dbHandler->quoteTable('ezurlalias_ml')
172
        )->where(
173
            $query->expr->lAnd(
174
                $query->expr->eq(
175
                    $this->dbHandler->quoteColumn('action_type'),
176
                    $query->bindValue('module', null, \PDO::PARAM_STR)
177
                ),
178
                $query->expr->eq(
179
                    $this->dbHandler->quoteColumn('is_original'),
180
                    $query->bindValue(1, null, \PDO::PARAM_INT)
181
                ),
182
                $query->expr->eq(
183
                    $this->dbHandler->quoteColumn('is_alias'),
184
                    $query->bindValue(1, null, \PDO::PARAM_INT)
185
                )
186
            )
187
        )->limit(
188
            $limit,
189
            $offset
190
        );
191 View Code Duplication
        if (isset($languageCode)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
192
            $query->where(
193
                $query->expr->gt(
194
                    $query->expr->bitAnd(
195
                        $this->dbHandler->quoteColumn('lang_mask'),
196
                        $query->bindValue(
197
                            $this->languageMaskGenerator->generateLanguageIndicator($languageCode, false),
198
                            null,
199
                            \PDO::PARAM_INT
200
                        )
201
                    ),
202
                    0
203
                )
204
            );
205
        }
206
        $statement = $query->prepare();
207
        $statement->execute();
208
209
        return $statement->fetchAll(\PDO::FETCH_ASSOC);
210
    }
211
212
    /**
213
     * Returns boolean indicating if the row with given $id is special root entry.
214
     *
215
     * Special root entry entry will have parentId=0 and text=''.
216
     * In standard installation this entry will point to location with id=2.
217
     *
218
     * @param mixed $id
219
     *
220
     * @return bool
221
     */
222
    public function isRootEntry($id)
223
    {
224
        /** @var $query \eZ\Publish\Core\Persistence\Database\SelectQuery */
225
        $query = $this->dbHandler->createSelectQuery();
226
        $query->select(
227
            $this->dbHandler->quoteColumn('text'),
228
            $this->dbHandler->quoteColumn('parent')
229
        )->from(
230
            $this->dbHandler->quoteTable('ezurlalias_ml')
231
        )->where(
232
            $query->expr->eq(
233
                $this->dbHandler->quoteColumn('id'),
234
                $query->bindValue($id, null, \PDO::PARAM_INT)
235
            )
236
        );
237
        $statement = $query->prepare();
238
        $statement->execute();
239
        $row = $statement->fetch(\PDO::FETCH_ASSOC);
240
241
        return strlen($row['text']) == 0 && $row['parent'] == 0;
242
    }
243
244
    /**
245
     * Downgrades autogenerated entry matched by given $action and $languageId and negatively matched by
246
     * composite primary key.
247
     *
248
     * If language mask of the found entry is composite (meaning it consists of multiple language ids) given
249
     * $languageId will be removed from mask. Otherwise entry will be marked as history.
250
     *
251
     * @param string $action
252
     * @param mixed $languageId
253
     * @param mixed $newId
254
     * @param mixed $parentId
255
     * @param string $textMD5
256
     */
257
    public function cleanupAfterPublish($action, $languageId, $newId, $parentId, $textMD5)
258
    {
259
        /** @var $query \eZ\Publish\Core\Persistence\Database\SelectQuery */
260
        $query = $this->dbHandler->createSelectQuery();
261
        $query->select(
262
            $this->dbHandler->quoteColumn('parent'),
263
            $this->dbHandler->quoteColumn('text_md5'),
264
            $this->dbHandler->quoteColumn('lang_mask')
265
        )->from(
266
            $this->dbHandler->quoteTable('ezurlalias_ml')
267
        )->where(
268
            $query->expr->lAnd(
269
                // 1) Autogenerated aliases that match action and language...
270
                $query->expr->eq(
271
                    $this->dbHandler->quoteColumn('action'),
272
                    $query->bindValue($action, null, \PDO::PARAM_STR)
273
                ),
274
                $query->expr->eq(
275
                    $this->dbHandler->quoteColumn('is_original'),
276
                    $query->bindValue(1, null, \PDO::PARAM_INT)
277
                ),
278
                $query->expr->eq(
279
                    $this->dbHandler->quoteColumn('is_alias'),
280
                    $query->bindValue(0, null, \PDO::PARAM_INT)
281
                ),
282
                $query->expr->gt(
283
                    $query->expr->bitAnd(
284
                        $this->dbHandler->quoteColumn('lang_mask'),
285
                        $query->bindValue($languageId, null, \PDO::PARAM_INT)
286
                    ),
287
                    0
288
                ),
289
                // 2) ...but not newly published entry
290
                $query->expr->not(
291
                    $query->expr->lAnd(
292
                        $query->expr->eq(
293
                            $this->dbHandler->quoteColumn('parent'),
294
                            $query->bindValue($parentId, null, \PDO::PARAM_INT)
295
                        ),
296
                        $query->expr->eq(
297
                            $this->dbHandler->quoteColumn('text_md5'),
298
                            $query->bindValue($textMD5, null, \PDO::PARAM_STR)
299
                        )
300
                    )
301
                )
302
            )
303
        );
304
305
        $statement = $query->prepare();
306
        $statement->execute();
307
        $row = $statement->fetch(\PDO::FETCH_ASSOC);
308
309
        if (!empty($row)) {
310
            // If language mask is composite (consists of multiple languages) then remove given language from entry
311
            if ($row['lang_mask'] & ~($languageId | 1)) {
312
                $this->removeTranslation($row['parent'], $row['text_md5'], $languageId);
313
            } else { // Otherwise mark entry as history
314
                $this->historize($row['parent'], $row['text_md5'], $newId);
315
            }
316
        }
317
    }
318
319
    /**
320
     * Updates single row matched by composite primary key.
321
     *
322
     * Sets "is_original" to 0 thus marking entry as history.
323
     *
324
     * Re-links history entries.
325
     *
326
     * When location alias is published we need to check for new history entries created with self::downgrade()
327
     * with the same action and language, update their "link" column with id of the published entry.
328
     * History entry "id" column is moved to next id value so that all active (non-history) entries are kept
329
     * under the same id.
330
     *
331
     * @param mixed $parentId
332
     * @param string $textMD5
333
     */
334 View Code Duplication
    protected function historize($parentId, $textMD5, $newId)
335
    {
336
        /** @var $query \eZ\Publish\Core\Persistence\Database\UpdateQuery */
337
        $query = $this->dbHandler->createUpdateQuery();
338
        $query->update(
339
            $this->dbHandler->quoteTable('ezurlalias_ml')
340
        )->set(
341
            $this->dbHandler->quoteColumn('is_original'),
342
            $query->bindValue(0, null, \PDO::PARAM_INT)
343
        )->set(
344
            $this->dbHandler->quoteColumn('link'),
345
            $query->bindValue($newId, null, \PDO::PARAM_INT)
346
        )->set(
347
            $this->dbHandler->quoteColumn('id'),
348
            $query->bindValue(
349
                $this->getNextId(),
350
                null,
351
                \PDO::PARAM_INT
352
            )
353
        )->where(
354
            $query->expr->lAnd(
355
                $query->expr->eq(
356
                    $this->dbHandler->quoteColumn('parent'),
357
                    $query->bindValue($parentId, null, \PDO::PARAM_INT)
358
                ),
359
                $query->expr->eq(
360
                    $this->dbHandler->quoteColumn('text_md5'),
361
                    $query->bindValue($textMD5, null, \PDO::PARAM_STR)
362
                )
363
            )
364
        );
365
        $query->prepare()->execute();
366
    }
367
368
    /**
369
     * Updates single row data matched by composite primary key.
370
     *
371
     * Removes given $languageId from entry's language mask
372
     *
373
     * @param mixed $parentId
374
     * @param string $textMD5
375
     * @param mixed $languageId
376
     */
377 View Code Duplication
    protected function removeTranslation($parentId, $textMD5, $languageId)
378
    {
379
        /** @var $query \eZ\Publish\Core\Persistence\Database\UpdateQuery */
380
        $query = $this->dbHandler->createUpdateQuery();
381
        $query->update(
382
            $this->dbHandler->quoteTable('ezurlalias_ml')
383
        )->set(
384
            $this->dbHandler->quoteColumn('lang_mask'),
385
            $query->expr->bitAnd(
386
                $this->dbHandler->quoteColumn('lang_mask'),
387
                $query->bindValue(~$languageId, null, \PDO::PARAM_INT)
388
            )
389
        )->where(
390
            $query->expr->lAnd(
391
                $query->expr->eq(
392
                    $this->dbHandler->quoteColumn('parent'),
393
                    $query->bindValue($parentId, null, \PDO::PARAM_INT)
394
                ),
395
                $query->expr->eq(
396
                    $this->dbHandler->quoteColumn('text_md5'),
397
                    $query->bindValue($textMD5, null, \PDO::PARAM_STR)
398
                )
399
            )
400
        );
401
        $query->prepare()->execute();
402
    }
403
404
    /**
405
     * Marks all entries with given $id as history entries.
406
     *
407
     * This method is used by Handler::locationMoved(). For this reason rows are not updated with next id value as
408
     * all entries with given id are being marked as history and there is no need for id separation.
409
     * Thus only "link" and "is_original" columns are updated.
410
     *
411
     * @param mixed $id
412
     * @param mixed $link
413
     */
414 View Code Duplication
    public function historizeId($id, $link)
415
    {
416
        /** @var $query \eZ\Publish\Core\Persistence\Database\UpdateQuery */
417
        $query = $this->dbHandler->createUpdateQuery();
418
        $query->update(
419
            $this->dbHandler->quoteTable('ezurlalias_ml')
420
        )->set(
421
            $this->dbHandler->quoteColumn('is_original'),
422
            $query->bindValue(0, null, \PDO::PARAM_INT)
423
        )->set(
424
            $this->dbHandler->quoteColumn('link'),
425
            $query->bindValue($link, null, \PDO::PARAM_INT)
426
        )->where(
427
            $query->expr->lAnd(
428
                $query->expr->eq(
429
                    $this->dbHandler->quoteColumn('is_alias'),
430
                    $query->bindValue(0, null, \PDO::PARAM_INT)
431
                ),
432
                $query->expr->eq(
433
                    $this->dbHandler->quoteColumn('action_type'),
434
                    $query->bindValue('eznode', null, \PDO::PARAM_STR)
435
                ),
436
                $query->expr->eq(
437
                    $this->dbHandler->quoteColumn('link'),
438
                    $query->bindValue($id, null, \PDO::PARAM_INT)
439
                )
440
            )
441
        );
442
        $query->prepare()->execute();
443
    }
444
445
    /**
446
     * Updates parent id of autogenerated entries.
447
     *
448
     * Update includes history entries.
449
     *
450
     * @param mixed $oldParentId
451
     * @param mixed $newParentId
452
     */
453 View Code Duplication
    public function reparent($oldParentId, $newParentId)
454
    {
455
        /** @var $query \eZ\Publish\Core\Persistence\Database\UpdateQuery */
456
        $query = $this->dbHandler->createUpdateQuery();
457
        $query->update(
458
            $this->dbHandler->quoteTable('ezurlalias_ml')
459
        )->set(
460
            $this->dbHandler->quoteColumn('parent'),
461
            $query->bindValue($newParentId, null, \PDO::PARAM_INT)
462
        )->where(
463
            $query->expr->lAnd(
464
                $query->expr->eq(
465
                    $this->dbHandler->quoteColumn('is_alias'),
466
                    $query->bindValue(0, null, \PDO::PARAM_INT)
467
                ),
468
                $query->expr->eq(
469
                    $this->dbHandler->quoteColumn('parent'),
470
                    $query->bindValue($oldParentId, null, \PDO::PARAM_INT)
471
                )
472
            )
473
        );
474
475
        $query->prepare()->execute();
476
    }
477
478
    /**
479
     * Updates single row data matched by composite primary key.
480
     *
481
     * Use optional parameter $languageMaskMatch to additionally limit the query match with languages.
482
     *
483
     * @param mixed $parentId
484
     * @param string $textMD5
485
     * @param array $values associative array with column names as keys and column values as values
486
     */
487 View Code Duplication
    public function updateRow($parentId, $textMD5, array $values)
488
    {
489
        /** @var $query \eZ\Publish\Core\Persistence\Database\UpdateQuery */
490
        $query = $this->dbHandler->createUpdateQuery();
491
        $query->update($this->dbHandler->quoteTable('ezurlalias_ml'));
492
        $this->setQueryValues($query, $values);
493
        $query->where(
494
            $query->expr->lAnd(
495
                $query->expr->eq(
496
                    $this->dbHandler->quoteColumn('parent'),
497
                    $query->bindValue($parentId, null, \PDO::PARAM_INT)
498
                ),
499
                $query->expr->eq(
500
                    $this->dbHandler->quoteColumn('text_md5'),
501
                    $query->bindValue($textMD5, null, \PDO::PARAM_STR)
502
                )
503
            )
504
        );
505
        $query->prepare()->execute();
506
    }
507
508
    /**
509
     * Inserts new row in urlalias_ml table.
510
     *
511
     * @param array $values
512
     *
513
     * @return mixed
514
     */
515
    public function insertRow(array $values)
516
    {
517
        // @todo remove after testing
518
        if (
519
            !isset($values['text']) ||
520
            !isset($values['text_md5']) ||
521
            !isset($values['action']) ||
522
            !isset($values['parent']) ||
523
            !isset($values['lang_mask'])) {
524
            throw new \Exception('value set is incomplete: ' . var_export($values, true) . ", can't execute insert");
525
        }
526
        if (!isset($values['id'])) {
527
            $values['id'] = $this->getNextId();
528
        }
529
        if (!isset($values['link'])) {
530
            $values['link'] = $values['id'];
531
        }
532
        if (!isset($values['is_original'])) {
533
            $values['is_original'] = ($values['id'] == $values['link'] ? 1 : 0);
534
        }
535
        if (!isset($values['is_alias'])) {
536
            $values['is_alias'] = 0;
537
        }
538
        if (!isset($values['alias_redirects'])) {
539
            $values['alias_redirects'] = 0;
540
        }
541
        if (!isset($values['action_type'])) {
542
            if (preg_match('#^(.+):.*#', $values['action'], $matches)) {
543
                $values['action_type'] = $matches[1];
544
            }
545
        }
546
        if ($values['is_alias']) {
547
            $values['is_original'] = 1;
548
        }
549
        if ($values['action'] === 'nop:') {
550
            $values['is_original'] = 0;
551
        }
552
553
        /** @var $query \eZ\Publish\Core\Persistence\Database\InsertQuery */
554
        $query = $this->dbHandler->createInsertQuery();
555
        $query->insertInto($this->dbHandler->quoteTable('ezurlalias_ml'));
556
        $this->setQueryValues($query, $values);
557
        $query->prepare()->execute();
558
559
        return $values['id'];
560
    }
561
562
    /**
563
     * Sets value for insert or update query.
564
     *
565
     * @param \eZ\Publish\Core\Persistence\Database\Query|\eZ\Publish\Core\Persistence\Database\InsertQuery|\eZ\Publish\Core\Persistence\Database\UpdateQuery $query
566
     * @param array $values
567
     *
568
     * @throws \Exception
569
     */
570
    protected function setQueryValues(Query $query, $values)
571
    {
572
        foreach ($values as $column => $value) {
573
            // @todo remove after testing
574
            if (!in_array($column, $this->columns['ezurlalias_ml'])) {
575
                throw new \Exception("unknown column '$column' for table 'ezurlalias_ml'");
576
            }
577
            switch ($column) {
578
                case 'text':
579
                case 'action':
580
                case 'text_md5':
581
                case 'action_type':
582
                    $pdoDataType = \PDO::PARAM_STR;
583
                    break;
584
                default:
585
                    $pdoDataType = \PDO::PARAM_INT;
586
            }
587
            $query->set(
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface eZ\Publish\Core\Persistence\Database\Query as the method set() does only exist in the following implementations of said interface: eZ\Publish\Core\Persiste...ine\InsertDoctrineQuery, eZ\Publish\Core\Persiste...ine\UpdateDoctrineQuery.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
588
                $this->dbHandler->quoteColumn($column),
589
                $query->bindValue($value, null, $pdoDataType)
590
            );
591
        }
592
    }
593
594
    /**
595
     * Returns next value for "id" column.
596
     *
597
     * @return mixed
598
     */
599 View Code Duplication
    public function getNextId()
600
    {
601
        $sequence = $this->dbHandler->getSequenceName('ezurlalias_ml_incr', 'id');
602
        /** @var $query \eZ\Publish\Core\Persistence\Database\InsertQuery */
603
        $query = $this->dbHandler->createInsertQuery();
604
        $query->insertInto(
605
            $this->dbHandler->quoteTable('ezurlalias_ml_incr')
606
        );
607
        // ezcDatabase does not abstract the "auto increment id"
608
        // INSERT INTO ezurlalias_ml_incr VALUES(DEFAULT) is not an option due
609
        // to this mysql bug: http://bugs.mysql.com/bug.php?id=42270
610
        // as a result we are forced to check which database is currently used
611
        // to generate the correct SQL query
612
        // see https://jira.ez.no/browse/EZP-20652
613
        if ($this->dbHandler->useSequences()) {
614
            $query->set(
615
                $this->dbHandler->quoteColumn('id'),
616
                "nextval('{$sequence}')"
617
            );
618
        } else {
619
            $query->set(
620
                $this->dbHandler->quoteColumn('id'),
621
                $query->bindValue(null, null, \PDO::PARAM_NULL)
622
            );
623
        }
624
        $query->prepare()->execute();
625
626
        return $this->dbHandler->lastInsertId($sequence);
627
    }
628
629
    /**
630
     * Loads single row data matched by composite primary key.
631
     *
632
     * @param mixed $parentId
633
     * @param string $textMD5
634
     *
635
     * @return array
636
     */
637 View Code Duplication
    public function loadRow($parentId, $textMD5)
638
    {
639
        /** @var $query \eZ\Publish\Core\Persistence\Database\SelectQuery */
640
        $query = $this->dbHandler->createSelectQuery();
641
        $query->select('*')->from(
642
            $this->dbHandler->quoteTable('ezurlalias_ml')
643
        )->where(
644
            $query->expr->lAnd(
645
                $query->expr->eq(
646
                    $this->dbHandler->quoteColumn('parent'),
647
                    $query->bindValue($parentId, null, \PDO::PARAM_INT)
648
                ),
649
                $query->expr->eq(
650
                    $this->dbHandler->quoteColumn('text_md5'),
651
                    $query->bindValue($textMD5, null, \PDO::PARAM_STR)
652
                )
653
            )
654
        );
655
656
        $statement = $query->prepare();
657
        $statement->execute();
658
659
        return $statement->fetch(\PDO::FETCH_ASSOC);
660
    }
661
662
    /**
663
     * Loads complete URL alias data by given array of path hashes.
664
     *
665
     * @param string[] $urlHashes URL string hashes
666
     *
667
     * @return array
668
     */
669
    public function loadUrlAliasData(array $urlHashes)
670
    {
671
        /** @var $query \eZ\Publish\Core\Persistence\Database\SelectQuery */
672
        $query = $this->dbHandler->createSelectQuery();
673
674
        $count = count($urlHashes);
675
        foreach ($urlHashes as $level => $urlPartHash) {
676
            $tableName = 'ezurlalias_ml' . ($level === $count - 1 ? '' : $level);
677
678
            if ($level === $count - 1) {
679
                $query->select(
680
                    $this->dbHandler->quoteColumn('id', $tableName),
681
                    $this->dbHandler->quoteColumn('link', $tableName),
682
                    $this->dbHandler->quoteColumn('is_alias', $tableName),
683
                    $this->dbHandler->quoteColumn('alias_redirects', $tableName),
684
                    $this->dbHandler->quoteColumn('is_original', $tableName),
685
                    $this->dbHandler->quoteColumn('action', $tableName),
686
                    $this->dbHandler->quoteColumn('action_type', $tableName),
687
                    $this->dbHandler->quoteColumn('lang_mask', $tableName),
688
                    $this->dbHandler->quoteColumn('text', $tableName),
689
                    $this->dbHandler->quoteColumn('parent', $tableName),
690
                    $this->dbHandler->quoteColumn('text_md5', $tableName)
691
                )->from(
692
                    $this->dbHandler->quoteTable('ezurlalias_ml')
693
                );
694
            } else {
695
                $query->select(
696
                    $this->dbHandler->aliasedColumn($query, 'id', $tableName),
697
                    $this->dbHandler->aliasedColumn($query, 'link', $tableName),
698
                    $this->dbHandler->aliasedColumn($query, 'is_alias', $tableName),
699
                    $this->dbHandler->aliasedColumn($query, 'alias_redirects', $tableName),
700
                    $this->dbHandler->aliasedColumn($query, 'is_original', $tableName),
701
                    $this->dbHandler->aliasedColumn($query, 'action', $tableName),
702
                    $this->dbHandler->aliasedColumn($query, 'action_type', $tableName),
703
                    $this->dbHandler->aliasedColumn($query, 'lang_mask', $tableName),
704
                    $this->dbHandler->aliasedColumn($query, 'text', $tableName),
705
                    $this->dbHandler->aliasedColumn($query, 'parent', $tableName),
706
                    $this->dbHandler->aliasedColumn($query, 'text_md5', $tableName)
707
                )->from(
708
                    $query->alias('ezurlalias_ml', $tableName)
709
                );
710
            }
711
712
            $query->where(
713
                $query->expr->lAnd(
714
                    $query->expr->eq(
715
                        $this->dbHandler->quoteColumn('text_md5', $tableName),
716
                        $query->bindValue($urlPartHash, null, \PDO::PARAM_STR)
717
                    ),
718
                    $query->expr->eq(
719
                        $this->dbHandler->quoteColumn('parent', $tableName),
720
                        // root entry has parent column set to 0
721
                        isset($previousTableName) ? $this->dbHandler->quoteColumn('link', $previousTableName) : $query->bindValue(0, null, \PDO::PARAM_INT)
722
                    )
723
                )
724
            );
725
726
            $previousTableName = $tableName;
727
        }
728
        $query->limit(1);
729
730
        $statement = $query->prepare();
731
        $statement->execute();
732
733
        return $statement->fetch(\PDO::FETCH_ASSOC);
734
    }
735
736
    /**
737
     * Loads autogenerated entry id by given $action and optionally $parentId.
738
     *
739
     * @param string $action
740
     * @param mixed|null $parentId
741
     *
742
     * @return array
743
     */
744 View Code Duplication
    public function loadAutogeneratedEntry($action, $parentId = null)
745
    {
746
        /** @var $query \eZ\Publish\Core\Persistence\Database\SelectQuery */
747
        $query = $this->dbHandler->createSelectQuery();
748
        $query->select(
749
            '*'
750
        )->from(
751
            $this->dbHandler->quoteTable('ezurlalias_ml')
752
        )->where(
753
            $query->expr->lAnd(
754
                $query->expr->eq(
755
                    $this->dbHandler->quoteColumn('action'),
756
                    $query->bindValue($action, null, \PDO::PARAM_STR)
757
                ),
758
                $query->expr->eq(
759
                    $this->dbHandler->quoteColumn('is_original'),
760
                    $query->bindValue(1, null, \PDO::PARAM_INT)
761
                ),
762
                $query->expr->eq(
763
                    $this->dbHandler->quoteColumn('is_alias'),
764
                    $query->bindValue(0, null, \PDO::PARAM_INT)
765
                )
766
            )
767
        );
768
769
        if (isset($parentId)) {
770
            $query->where(
771
                $query->expr->eq(
772
                    $this->dbHandler->quoteColumn('parent'),
773
                    $query->bindValue($parentId, null, \PDO::PARAM_INT)
774
                )
775
            );
776
        }
777
778
        $statement = $query->prepare();
779
        $statement->execute();
780
781
        return $statement->fetch(\PDO::FETCH_ASSOC);
782
    }
783
784
    /**
785
     * Loads all data for the path identified by given $id.
786
     *
787
     * @throws \RuntimeException
788
     *
789
     * @param mixed $id
790
     *
791
     * @return array
792
     */
793
    public function loadPathData($id)
794
    {
795
        $pathData = array();
796
797
        while ($id != 0) {
798
            /** @var $query \eZ\Publish\Core\Persistence\Database\SelectQuery */
799
            $query = $this->dbHandler->createSelectQuery();
800
            $query->select(
801
                $this->dbHandler->quoteColumn('parent'),
802
                $this->dbHandler->quoteColumn('lang_mask'),
803
                $this->dbHandler->quoteColumn('text')
804
            )->from(
805
                $this->dbHandler->quoteTable('ezurlalias_ml')
806
            )->where(
807
                $query->expr->eq(
808
                    $this->dbHandler->quoteColumn('id'),
809
                    $query->bindValue($id, null, \PDO::PARAM_INT)
810
                )
811
            );
812
813
            $statement = $query->prepare();
814
            $statement->execute();
815
816
            $rows = $statement->fetchAll(\PDO::FETCH_ASSOC);
817
            if (empty($rows)) {
818
                // Normally this should never happen
819
                // @todo remove throw when tested
820
                $path = implode('/', $pathData);
821
                throw new \RuntimeException("Path ({$path}...) is broken, last id is '{$id}': " . __METHOD__);
822
            }
823
824
            $id = $rows[0]['parent'];
825
            array_unshift($pathData, $rows);
826
        }
827
828
        return $pathData;
829
    }
830
831
    /**
832
     * Loads path data identified by given ordered array of hierarchy data.
833
     *
834
     * The first entry in $hierarchyData corresponds to the top-most path element in the path, the second entry the
835
     * child of the first path element and so on.
836
     * This method is faster than self::getPath() since it can fetch all elements using only one query, but can be used
837
     * only for autogenerated paths.
838
     *
839
     * @param array $hierarchyData
840
     *
841
     * @return array
842
     */
843
    public function loadPathDataByHierarchy(array $hierarchyData)
844
    {
845
        /** @var $query \eZ\Publish\Core\Persistence\Database\SelectQuery */
846
        $query = $this->dbHandler->createSelectQuery();
847
848
        $hierarchyConditions = array();
849
        foreach ($hierarchyData as $levelData) {
850
            $hierarchyConditions[] = $query->expr->lAnd(
851
                $query->expr->eq(
852
                    $this->dbHandler->quoteColumn('parent'),
853
                    $query->bindValue(
854
                        $levelData['parent'],
855
                        null,
856
                        \PDO::PARAM_INT
857
                    )
858
                ),
859
                $query->expr->eq(
860
                    $this->dbHandler->quoteColumn('action'),
861
                    $query->bindValue(
862
                        $levelData['action'],
863
                        null,
864
                        \PDO::PARAM_STR
865
                    )
866
                ),
867
                $query->expr->eq(
868
                    $this->dbHandler->quoteColumn('id'),
869
                    $query->bindValue(
870
                        $levelData['id'],
871
                        null,
872
                        \PDO::PARAM_INT
873
                    )
874
                )
875
            );
876
        }
877
878
        $query->select(
879
            $this->dbHandler->quoteColumn('action'),
880
            $this->dbHandler->quoteColumn('lang_mask'),
881
            $this->dbHandler->quoteColumn('text')
882
        )->from(
883
            $this->dbHandler->quoteTable('ezurlalias_ml')
884
        )->where(
885
            $query->expr->lOr($hierarchyConditions)
886
        );
887
888
        $statement = $query->prepare();
889
        $statement->execute();
890
891
        $rows = $statement->fetchAll(\PDO::FETCH_ASSOC);
892
        $rowsMap = array();
893
        foreach ($rows as $row) {
894
            $rowsMap[$row['action']][] = $row;
895
        }
896
897
        if (count($rowsMap) !== count($hierarchyData)) {
898
            throw new \RuntimeException('The path is corrupted.');
899
        }
900
901
        $data = array();
902
        foreach ($hierarchyData as $levelData) {
903
            $data[] = $rowsMap[$levelData['action']];
904
        }
905
906
        return $data;
907
    }
908
909
    /**
910
     * Deletes single custom alias row matched by composite primary key.
911
     *
912
     * @param mixed $parentId
913
     * @param string $textMD5
914
     *
915
     * @return bool
916
     */
917
    public function removeCustomAlias($parentId, $textMD5)
918
    {
919
        /** @var $query \eZ\Publish\Core\Persistence\Database\DeleteQuery */
920
        $query = $this->dbHandler->createDeleteQuery();
921
        $query->deleteFrom(
922
            $this->dbHandler->quoteTable('ezurlalias_ml')
923
        )->where(
924
            $query->expr->lAnd(
925
                $query->expr->eq(
926
                    $this->dbHandler->quoteColumn('parent'),
927
                    $query->bindValue($parentId, null, \PDO::PARAM_INT)
928
                ),
929
                $query->expr->eq(
930
                    $this->dbHandler->quoteColumn('text_md5'),
931
                    $query->bindValue($textMD5, null, \PDO::PARAM_STR)
932
                ),
933
                $query->expr->eq(
934
                    $this->dbHandler->quoteColumn('is_alias'),
935
                    $query->bindValue(1, null, \PDO::PARAM_INT)
936
                )
937
            )
938
        );
939
        $statement = $query->prepare();
940
        $statement->execute();
941
942
        return $statement->rowCount() === 1 ?: false;
943
    }
944
945
    /**
946
     * Deletes all rows with given $action and optionally $id.
947
     *
948
     * If $id is set only autogenerated entries will be removed.
949
     *
950
     * @param mixed $action
951
     * @param mixed|null $id
952
     *
953
     * @return bool
954
     */
955 View Code Duplication
    public function remove($action, $id = null)
956
    {
957
        /** @var $query \eZ\Publish\Core\Persistence\Database\DeleteQuery */
958
        $query = $this->dbHandler->createDeleteQuery();
959
        $query->deleteFrom(
960
            $this->dbHandler->quoteTable('ezurlalias_ml')
961
        )->where(
962
            $query->expr->eq(
963
                $this->dbHandler->quoteColumn('action'),
964
                $query->bindValue($action, null, \PDO::PARAM_STR)
965
            )
966
        );
967
968
        if ($id !== null) {
969
            $query->where(
970
                $query->expr->lAnd(
971
                    $query->expr->eq(
972
                        $this->dbHandler->quoteColumn('is_alias'),
973
                        $query->bindValue(0, null, \PDO::PARAM_INT)
974
                    ),
975
                    $query->expr->eq(
976
                        $this->dbHandler->quoteColumn('id'),
977
                        $query->bindValue($id, null, \PDO::PARAM_INT)
978
                    )
979
                )
980
            );
981
        }
982
983
        $query->prepare()->execute();
984
    }
985
986
    /**
987
     * Loads all autogenerated entries with given $parentId with optionally included history entries.
988
     *
989
     * @param mixed $parentId
990
     * @param bool $includeHistory
991
     *
992
     * @return array
993
     */
994 View Code Duplication
    public function loadAutogeneratedEntries($parentId, $includeHistory = false)
995
    {
996
        /** @var $query \eZ\Publish\Core\Persistence\Database\SelectQuery */
997
        $query = $this->dbHandler->createSelectQuery();
998
        $query->select(
999
            '*'
1000
        )->from(
1001
            $this->dbHandler->quoteTable('ezurlalias_ml')
1002
        )->where(
1003
            $query->expr->lAnd(
1004
                $query->expr->eq(
1005
                    $this->dbHandler->quoteColumn('parent'),
1006
                    $query->bindValue($parentId, null, \PDO::PARAM_INT)
1007
                ),
1008
                $query->expr->eq(
1009
                    $this->dbHandler->quoteColumn('action_type'),
1010
                    $query->bindValue('eznode', null, \PDO::PARAM_STR)
1011
                ),
1012
                $query->expr->eq(
1013
                    $this->dbHandler->quoteColumn('is_alias'),
1014
                    $query->bindValue(0, null, \PDO::PARAM_INT)
1015
                )
1016
            )
1017
        );
1018
1019
        if (!$includeHistory) {
1020
            $query->where(
1021
                $query->expr->eq(
1022
                    $this->dbHandler->quoteColumn('is_original'),
1023
                    $query->bindValue(1, null, \PDO::PARAM_INT)
1024
                )
1025
            );
1026
        }
1027
1028
        $statement = $query->prepare();
1029
        $statement->execute();
1030
1031
        return $statement->fetchAll(\PDO::FETCH_ASSOC);
1032
    }
1033
1034
    /**
1035
     * Swaps the content object being pointed to by a location object.
1036
     *
1037
     * Make the location identified by $locationId1 refer to the Content
1038
     * referred to by $locationId2 and vice versa.
1039
     *
1040
     * @param mixed $locationId1
1041
     * @param mixed $locationId2
1042
     *
1043
     * @return bool
1044
     */
1045
    public function swap($locationId1, $locationId2)
1046
    {
1047
        $query = $this->dbHandler->createSelectQuery();
1048
        $query
1049
            ->select(
1050
                $this->dbHandler->quoteColumn('action'),
1051
                $this->dbHandler->quoteColumn('text'),
1052
                $this->dbHandler->quoteColumn('text_md5'),
1053
                $this->dbHandler->quoteColumn('lang_mask')
1054
            )
1055
            ->from($this->dbHandler->quoteTable('ezurlalias_ml'))
1056
            ->where(
1057
                $query->expr->in(
1058
                    $this->dbHandler->quoteColumn('action'),
1059
                    array("eznode:{$locationId1}", "eznode:{$locationId2}")
1060
                )
1061
            );
1062
        $statement = $query->prepare();
1063
        $statement->execute();
1064
        foreach ($statement->fetchAll() as $row) {
1065
            $urlAliases[$row['action']] = $row;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$urlAliases was never initialized. Although not strictly required by PHP, it is generally a good practice to add $urlAliases = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1066
        }
1067
1068
        if (!isset($urlAliases) || count($urlAliases) === 0) {
1069
            return false;
1070
        }
1071
1072
        $query = $this->dbHandler->createUpdateQuery();
1073
        $query
1074
            ->update($this->dbHandler->quoteTable('ezurlalias_ml'))
1075
            ->set(
1076
                $this->dbHandler->quoteColumn('text'),
1077
                $query->bindValue($urlAliases["eznode:{$locationId2}"]['text'])
1078
            )
1079
            ->set(
1080
                $this->dbHandler->quoteColumn('text_md5'),
1081
                $query->bindValue($urlAliases["eznode:{$locationId2}"]['text_md5'])
1082
            )
1083
            ->set(
1084
                $this->dbHandler->quoteColumn('lang_mask'),
1085
                $query->bindValue($urlAliases["eznode:{$locationId2}"]['lang_mask'])
1086
            )
1087
            ->where(
1088
                $query->expr->eq(
1089
                    $this->dbHandler->quoteColumn('action'),
1090
                    $query->bindValue("eznode:{$locationId1}")
1091
                )
1092
            );
1093
        $query->prepare()->execute();
1094
1095
        $query = $this->dbHandler->createUpdateQuery();
1096
        $query
1097
            ->update($this->dbHandler->quoteTable('ezurlalias_ml'))
1098
            ->set(
1099
                $this->dbHandler->quoteColumn('text'),
1100
                $query->bindValue($urlAliases["eznode:{$locationId1}"]['text'])
1101
            )
1102
            ->set(
1103
                $this->dbHandler->quoteColumn('text_md5'),
1104
                $query->bindValue($urlAliases["eznode:{$locationId1}"]['text_md5'])
1105
            )
1106
            ->set(
1107
                $this->dbHandler->quoteColumn('lang_mask'),
1108
                $query->bindValue($urlAliases["eznode:{$locationId1}"]['lang_mask'])
1109
            )
1110
            ->where(
1111
                $query->expr->eq(
1112
                    $this->dbHandler->quoteColumn('action'),
1113
                    $query->bindValue("eznode:{$locationId2}")
1114
                )
1115
            );
1116
        $query->prepare()->execute();
1117
    }
1118
}
1119