Completed
Push — EZP-26064 ( 572bbb )
by André
23:52
created

DoctrineDatabase::insertContentObject()   B

Complexity

Conditions 4
Paths 2

Size

Total Lines 65
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 4
eloc 54
c 1
b 0
f 1
nc 2
nop 2
dl 0
loc 65
rs 8.8507

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 Content 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\Gateway;
12
13
use Doctrine\DBAL\Connection;
14
use eZ\Publish\Core\Persistence\Legacy\Content\Gateway;
15
use eZ\Publish\Core\Persistence\Legacy\Content\Gateway\DoctrineDatabase\QueryBuilder;
16
use eZ\Publish\Core\Persistence\Database\DatabaseHandler;
17
use eZ\Publish\Core\Persistence\Database\UpdateQuery;
18
use eZ\Publish\Core\Persistence\Database\InsertQuery;
19
use eZ\Publish\Core\Persistence\Database\SelectQuery;
20
use eZ\Publish\Core\Persistence\Legacy\Content\StorageFieldValue;
21
use eZ\Publish\Core\Persistence\Legacy\Content\Language\MaskGenerator as LanguageMaskGenerator;
22
use eZ\Publish\SPI\Persistence\Content;
23
use eZ\Publish\SPI\Persistence\Content\CreateStruct;
24
use eZ\Publish\SPI\Persistence\Content\UpdateStruct;
25
use eZ\Publish\SPI\Persistence\Content\MetadataUpdateStruct;
26
use eZ\Publish\SPI\Persistence\Content\ContentInfo;
27
use eZ\Publish\SPI\Persistence\Content\VersionInfo;
28
use eZ\Publish\SPI\Persistence\Content\Field;
29
use eZ\Publish\SPI\Persistence\Content\Relation\CreateStruct as RelationCreateStruct;
30
use eZ\Publish\SPI\Persistence\Content\Language\Handler as LanguageHandler;
31
use eZ\Publish\Core\Base\Exceptions\NotFoundException as NotFound;
32
use eZ\Publish\API\Repository\Values\Content\VersionInfo as APIVersionInfo;
33
use DOMXPath;
34
use DOMDocument;
35
use PDO;
36
37
/**
38
 * Doctrine database based content gateway.
39
 */
40
class DoctrineDatabase extends Gateway
41
{
42
    /**
43
     * eZ Doctrine database handler.
44
     *
45
     * @var \eZ\Publish\Core\Persistence\Database\DatabaseHandler
46
     */
47
    protected $dbHandler;
48
49
    /**
50
     * The native Doctrine connection.
51
     *
52
     * Meant to be used to transition from eZ/Zeta interface to Doctrine.
53
     *
54
     * @var \Doctrine\DBAL\Connection
55
     */
56
    protected $connection;
57
58
    /**
59
     * Query builder.
60
     *
61
     * @var \eZ\Publish\Core\Persistence\Legacy\Content\Gateway\DoctrineDatabase\QueryBuilder
62
     */
63
    protected $queryBuilder;
64
65
    /**
66
     * Caching language handler.
67
     *
68
     * @var \eZ\Publish\Core\Persistence\Legacy\Content\Language\CachingHandler
69
     */
70
    protected $languageHandler;
71
72
    /**
73
     * Language mask generator.
74
     *
75
     * @var \eZ\Publish\Core\Persistence\Legacy\Content\Language\MaskGenerator
76
     */
77
    protected $languageMaskGenerator;
78
79
    /**
80
     * Creates a new gateway based on $db.
81
     *
82
     * @param \eZ\Publish\Core\Persistence\Database\DatabaseHandler $db
83
     * @param \Doctrine\DBAL\Connection $connection
84
     * @param \eZ\Publish\Core\Persistence\Legacy\Content\Gateway\DoctrineDatabase\QueryBuilder $queryBuilder
85
     * @param \eZ\Publish\SPI\Persistence\Content\Language\Handler $languageHandler
86
     * @param \eZ\Publish\Core\Persistence\Legacy\Content\Language\MaskGenerator $languageMaskGenerator
87
     */
88
    public function __construct(
89
        DatabaseHandler $db,
90
        Connection $connection,
91
        QueryBuilder $queryBuilder,
92
        LanguageHandler $languageHandler,
93
        LanguageMaskGenerator $languageMaskGenerator
94
    ) {
95
        $this->dbHandler = $db;
96
        $this->connection = $connection;
97
        $this->queryBuilder = $queryBuilder;
98
        $this->languageHandler = $languageHandler;
0 ignored issues
show
Documentation Bug introduced by
$languageHandler is of type object<eZ\Publish\SPI\Pe...ntent\Language\Handler>, but the property $languageHandler was declared to be of type object<eZ\Publish\Core\P...anguage\CachingHandler>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
99
        $this->languageMaskGenerator = $languageMaskGenerator;
100
    }
101
102
    /**
103
     * Get context definition for external storage layers.
104
     *
105
     * @return array
106
     */
107
    public function getContext()
108
    {
109
        return array(
110
            'identifier' => 'LegacyStorage',
111
            'connection' => $this->dbHandler,
112
        );
113
    }
114
115
    /**
116
     * Inserts a new content object.
117
     *
118
     * @param \eZ\Publish\SPI\Persistence\Content\CreateStruct $struct
119
     * @param mixed $currentVersionNo
120
     *
121
     * @return int ID
122
     */
123
    public function insertContentObject(CreateStruct $struct, $currentVersionNo = 1)
124
    {
125
        $initialLanguageCode = $this->languageHandler->load($struct->initialLanguageId)->languageCode;
126
        if (isset($struct->name[$initialLanguageCode])) {
127
            $name = $struct->name[$initialLanguageCode];
128
        } else {
129
            $name = '';
130
        }
131
132
        $q = $this->dbHandler->createInsertQuery();
133
        $q->insertInto(
134
            $this->dbHandler->quoteTable('ezcontentobject')
135
        )->set(
136
            $this->dbHandler->quoteColumn('id'),
137
            $this->dbHandler->getAutoIncrementValue('ezcontentobject', 'id')
138
        )->set(
139
            $this->dbHandler->quoteColumn('current_version'),
140
            $q->bindValue($currentVersionNo, null, \PDO::PARAM_INT)
141
        )->set(
142
            $this->dbHandler->quoteColumn('name'),
143
            $q->bindValue($name, null, \PDO::PARAM_STR)
144
        )->set(
145
            $this->dbHandler->quoteColumn('contentclass_id'),
146
            $q->bindValue($struct->typeId, null, \PDO::PARAM_INT)
147
        )->set(
148
            $this->dbHandler->quoteColumn('section_id'),
149
            $q->bindValue($struct->sectionId, null, \PDO::PARAM_INT)
150
        )->set(
151
            $this->dbHandler->quoteColumn('owner_id'),
152
            $q->bindValue($struct->ownerId, null, \PDO::PARAM_INT)
153
        )->set(
154
            $this->dbHandler->quoteColumn('initial_language_id'),
155
            $q->bindValue($struct->initialLanguageId, null, \PDO::PARAM_INT)
156
        )->set(
157
            $this->dbHandler->quoteColumn('remote_id'),
158
            $q->bindValue($struct->remoteId, null, \PDO::PARAM_STR)
159
        )->set(
160
            $this->dbHandler->quoteColumn('modified'),
161
            $q->bindValue($struct->modified ?: 0, null, \PDO::PARAM_INT)
162
        )->set(
163
            $this->dbHandler->quoteColumn('published'),
164
            // @todo Schema can be changed to allow null so 0 does not have special meaning, however that would need API changes.
165
            $q->bindValue($struct->published ?: 0, null, \PDO::PARAM_INT)
166
        )->set(
167
            $this->dbHandler->quoteColumn('status'),
168
            $q->bindValue(ContentInfo::STATUS_DRAFT, null, \PDO::PARAM_INT)
169
        )->set(
170
            $this->dbHandler->quoteColumn('language_mask'),
171
            $q->bindValue(
172
                $this->generateLanguageMask(
173
                    $struct->fields,
174
                    $this->languageHandler->load($struct->initialLanguageId)->languageCode,
175
                    $struct->alwaysAvailable
176
                ),
177
                null,
178
                \PDO::PARAM_INT
179
            )
180
        );
181
182
        $q->prepare()->execute();
183
184
        return $this->dbHandler->lastInsertId(
185
            $this->dbHandler->getSequenceName('ezcontentobject', 'id')
186
        );
187
    }
188
189
    /**
190
     * Generates a language mask for $version.
191
     *
192
     * @param \eZ\Publish\SPI\Persistence\Content\Field[] $fields
193
     * @param string $initialLanguageCode
194
     * @param bool $alwaysAvailable
195
     *
196
     * @return int
197
     */
198
    protected function generateLanguageMask(array $fields, $initialLanguageCode, $alwaysAvailable)
199
    {
200
        $languages = array($initialLanguageCode => true);
201
        foreach ($fields as $field) {
202
            if (isset($languages[$field->languageCode])) {
203
                continue;
204
            }
205
206
            $languages[$field->languageCode] = true;
207
        }
208
209
        if ($alwaysAvailable) {
210
            $languages['always-available'] = true;
211
        }
212
213
        return $this->languageMaskGenerator->generateLanguageMask($languages);
214
    }
215
216
    /**
217
     * Inserts a new version.
218
     *
219
     * @param \eZ\Publish\SPI\Persistence\Content\VersionInfo $versionInfo
220
     * @param \eZ\Publish\SPI\Persistence\Content\Field[] $fields
221
     *
222
     * @return int ID
223
     */
224
    public function insertVersion(VersionInfo $versionInfo, array $fields)
225
    {
226
        /** @var $q \eZ\Publish\Core\Persistence\Database\InsertQuery */
227
        $q = $this->dbHandler->createInsertQuery();
228
        $q->insertInto(
229
            $this->dbHandler->quoteTable('ezcontentobject_version')
230
        )->set(
231
            $this->dbHandler->quoteColumn('id'),
232
            $this->dbHandler->getAutoIncrementValue('ezcontentobject_version', 'id')
233
        )->set(
234
            $this->dbHandler->quoteColumn('version'),
235
            $q->bindValue($versionInfo->versionNo, null, \PDO::PARAM_INT)
236
        )->set(
237
            $this->dbHandler->quoteColumn('modified'),
238
            $q->bindValue($versionInfo->modificationDate, null, \PDO::PARAM_INT)
239
        )->set(
240
            $this->dbHandler->quoteColumn('creator_id'),
241
            $q->bindValue($versionInfo->creatorId, null, \PDO::PARAM_INT)
242
        )->set(
243
            $this->dbHandler->quoteColumn('created'),
244
            $q->bindValue($versionInfo->creationDate, null, \PDO::PARAM_INT)
245
        )->set(
246
            $this->dbHandler->quoteColumn('status'),
247
            $q->bindValue($versionInfo->status, null, \PDO::PARAM_INT)
248
        )->set(
249
            $this->dbHandler->quoteColumn('initial_language_id'),
250
            $q->bindValue(
251
                $this->languageHandler->loadByLanguageCode($versionInfo->initialLanguageCode)->id,
252
                null,
253
                \PDO::PARAM_INT
254
            )
255
        )->set(
256
            $this->dbHandler->quoteColumn('contentobject_id'),
257
            $q->bindValue($versionInfo->contentInfo->id, null, \PDO::PARAM_INT)
258
        )->set(
259
            // As described in field mapping document
260
            $this->dbHandler->quoteColumn('workflow_event_pos'),
261
            $q->bindValue(0, null, \PDO::PARAM_INT)
262
        )->set(
263
            $this->dbHandler->quoteColumn('language_mask'),
264
            $q->bindValue(
265
                $this->generateLanguageMask(
266
                    $fields,
267
                    $versionInfo->initialLanguageCode,
268
                    $versionInfo->contentInfo->alwaysAvailable
269
                ),
270
                null,
271
                \PDO::PARAM_INT
272
            )
273
        );
274
275
        $q->prepare()->execute();
276
277
        return $this->dbHandler->lastInsertId(
278
            $this->dbHandler->getSequenceName('ezcontentobject_version', 'id')
279
        );
280
    }
281
282
    /**
283
     * Updates an existing content identified by $contentId in respect to $struct.
284
     *
285
     * @param int $contentId
286
     * @param \eZ\Publish\SPI\Persistence\Content\MetadataUpdateStruct $struct
287
     * @param \eZ\Publish\SPI\Persistence\Content\VersionInfo $prePublishVersionInfo Provided on publish
288
     */
289
    public function updateContent($contentId, MetadataUpdateStruct $struct, VersionInfo $prePublishVersionInfo = null)
290
    {
291
        $q = $this->dbHandler->createUpdateQuery();
292
        $q->update($this->dbHandler->quoteTable('ezcontentobject'));
293
294
        if (isset($struct->name)) {
295
            $q->set(
296
                $this->dbHandler->quoteColumn('name'),
297
                $q->bindValue($struct->name, null, \PDO::PARAM_STR)
298
            );
299
        }
300
        if (isset($struct->mainLanguageId)) {
301
            $q->set(
302
                $this->dbHandler->quoteColumn('initial_language_id'),
303
                $q->bindValue($struct->mainLanguageId, null, \PDO::PARAM_INT)
304
            );
305
        }
306
        if (isset($struct->modificationDate)) {
307
            $q->set(
308
                $this->dbHandler->quoteColumn('modified'),
309
                $q->bindValue($struct->modificationDate, null, \PDO::PARAM_INT)
310
            );
311
        }
312
        if (isset($struct->ownerId)) {
313
            $q->set(
314
                $this->dbHandler->quoteColumn('owner_id'),
315
                $q->bindValue($struct->ownerId, null, \PDO::PARAM_INT)
316
            );
317
        }
318
        if (isset($struct->publicationDate)) {
319
            $q->set(
320
                $this->dbHandler->quoteColumn('published'),
321
                $q->bindValue($struct->publicationDate, null, \PDO::PARAM_INT)
322
            );
323
        }
324
        if (isset($struct->remoteId)) {
325
            $q->set(
326
                $this->dbHandler->quoteColumn('remote_id'),
327
                $q->bindValue($struct->remoteId, null, \PDO::PARAM_STR)
328
            );
329
        }
330
        if ($prePublishVersionInfo !== null) {
331
            $mask = 0;
332
333
            if (isset($struct->alwaysAvailable)) {
334
                $mask |= $struct->alwaysAvailable ? 1 : 0;
335
            } else {
336
                $mask |= $prePublishVersionInfo->contentInfo->alwaysAvailable ? 1 : 0;
337
            }
338
339
            foreach ($prePublishVersionInfo->languageIds as $languageId) {
340
                $mask |= $languageId;
341
            }
342
343
            $q->set(
344
                $this->dbHandler->quoteColumn('language_mask'),
345
                $q->bindValue($mask, null, \PDO::PARAM_INT)
346
            );
347
        }
348
        $q->where(
349
            $q->expr->eq(
350
                $this->dbHandler->quoteColumn('id'),
351
                $q->bindValue($contentId, null, \PDO::PARAM_INT)
352
            )
353
        );
354
        $q->prepare()->execute();
355
356
        // Handle alwaysAvailable flag update separately as it's a more complex task and has impact on several tables
357
        if (isset($struct->alwaysAvailable) || isset($struct->mainLanguageId)) {
358
            $this->updateAlwaysAvailableFlag($contentId, $struct->alwaysAvailable);
359
        }
360
    }
361
362
    /**
363
     * Updates version $versionNo for content identified by $contentId, in respect to $struct.
364
     *
365
     * @param int $contentId
366
     * @param int $versionNo
367
     * @param \eZ\Publish\SPI\Persistence\Content\UpdateStruct $struct
368
     */
369
    public function updateVersion($contentId, $versionNo, UpdateStruct $struct)
370
    {
371
        $q = $this->dbHandler->createUpdateQuery();
372
        $q->update(
373
            $this->dbHandler->quoteTable('ezcontentobject_version')
374
        )->set(
375
            $this->dbHandler->quoteColumn('creator_id'),
376
            $q->bindValue($struct->creatorId, null, \PDO::PARAM_INT)
377
        )->set(
378
            $this->dbHandler->quoteColumn('modified'),
379
            $q->bindValue($struct->modificationDate, null, \PDO::PARAM_INT)
380
        )->set(
381
            $this->dbHandler->quoteColumn('initial_language_id'),
382
            $q->bindValue($struct->initialLanguageId, null, \PDO::PARAM_INT)
383
        )->set(
384
            $this->dbHandler->quoteColumn('language_mask'),
385
            $q->expr->bitOr(
386
                $this->dbHandler->quoteColumn('language_mask'),
387
                $q->bindValue(
388
                    $this->generateLanguageMask(
389
                        $struct->fields,
390
                        $this->languageHandler->load($struct->initialLanguageId)->languageCode,
391
                        false
392
                    ),
393
                    null,
394
                    \PDO::PARAM_INT
395
                )
396
            )
397
        )->where(
398
            $q->expr->lAnd(
399
                $q->expr->eq(
400
                    $this->dbHandler->quoteColumn('contentobject_id'),
401
                    $q->bindValue($contentId, null, \PDO::PARAM_INT)
402
                ),
403
                $q->expr->eq(
404
                    $this->dbHandler->quoteColumn('version'),
405
                    $q->bindValue($versionNo, null, \PDO::PARAM_INT)
406
                )
407
            )
408
        );
409
        $q->prepare()->execute();
410
    }
411
412
    /**
413
     * Updates "always available" flag for Content identified by $contentId, in respect to
414
     * Content's current main language and optionally new $alwaysAvailable state.
415
     *
416
     * @param int $contentId
417
     * @param bool|null $alwaysAvailable New "always available" value or null if not defined
418
     */
419
    public function updateAlwaysAvailableFlag($contentId, $alwaysAvailable = null)
420
    {
421
        // We will need to know some info on the current language mask to update the flag
422
        // everywhere needed
423
        $contentInfoRow = $this->loadContentInfo($contentId);
424
        if (!isset($alwaysAvailable)) {
425
            $alwaysAvailable = (bool)$contentInfoRow['language_mask'] & 1;
426
        }
427
428
        /** @var $q \eZ\Publish\Core\Persistence\Database\UpdateQuery */
429
        $q = $this->dbHandler->createUpdateQuery();
430
        $q
431
            ->update($this->dbHandler->quoteTable('ezcontentobject'))
432
            ->set(
433
                $this->dbHandler->quoteColumn('language_mask'),
434
                $alwaysAvailable ?
435
                    $q->expr->bitOr($this->dbHandler->quoteColumn('language_mask'), 1) :
436
                    $q->expr->bitAnd($this->dbHandler->quoteColumn('language_mask'), -2)
437
            )
438
            ->where(
439
                $q->expr->eq(
440
                    $this->dbHandler->quoteColumn('id'),
441
                    $q->bindValue($contentId, null, \PDO::PARAM_INT)
442
                )
443
            );
444
        $q->prepare()->execute();
445
446
        // Now we need to update ezcontentobject_name
447
        /** @var $qName \eZ\Publish\Core\Persistence\Database\UpdateQuery */
448
        $qName = $this->dbHandler->createUpdateQuery();
449
        $qName
450
            ->update($this->dbHandler->quoteTable('ezcontentobject_name'))
451
            ->set(
452
                $this->dbHandler->quoteColumn('language_id'),
453
                $alwaysAvailable ?
454
                    $qName->expr->bitOr($this->dbHandler->quoteColumn('language_id'), 1) :
455
                    $qName->expr->bitAnd($this->dbHandler->quoteColumn('language_id'), -2)
456
            )
457
            ->where(
458
                $qName->expr->lAnd(
459
                    $qName->expr->eq(
460
                        $this->dbHandler->quoteColumn('contentobject_id'),
461
                        $qName->bindValue($contentId, null, \PDO::PARAM_INT)
462
                    ),
463
                    $qName->expr->eq(
464
                        $this->dbHandler->quoteColumn('content_version'),
465
                        $qName->bindValue(
466
                            $contentInfoRow['current_version'],
467
                            null,
468
                            \PDO::PARAM_INT
469
                        )
470
                    )
471
                )
472
            );
473
        $qName->prepare()->execute();
474
475
        // Now update ezcontentobject_attribute for current version
476
        // Create update query that will be reused
477
        /** @var $qAttr \eZ\Publish\Core\Persistence\Database\UpdateQuery */
478
        $qAttr = $this->dbHandler->createUpdateQuery();
479
        $qAttr
480
            ->update($this->dbHandler->quoteTable('ezcontentobject_attribute'))
481
            ->where(
482
                $qAttr->expr->lAnd(
483
                    $qAttr->expr->eq(
484
                        $this->dbHandler->quoteColumn('contentobject_id'),
485
                        $qAttr->bindValue($contentId, null, \PDO::PARAM_INT)
486
                    ),
487
                    $qAttr->expr->eq(
488
                        $this->dbHandler->quoteColumn('version'),
489
                        $qAttr->bindValue(
490
                            $contentInfoRow['current_version'],
491
                            null,
492
                            \PDO::PARAM_INT
493
                        )
494
                    )
495
                )
496
            );
497
498
        // If there is only a single language, update all fields and return
499
        if (!$this->languageMaskGenerator->isLanguageMaskComposite($contentInfoRow['language_mask'])) {
500
            $qAttr->set(
501
                $this->dbHandler->quoteColumn('language_id'),
502
                $alwaysAvailable ?
503
                    $qAttr->expr->bitOr($this->dbHandler->quoteColumn('language_id'), 1) :
504
                    $qAttr->expr->bitAnd($this->dbHandler->quoteColumn('language_id'), -2)
505
            );
506
            $qAttr->prepare()->execute();
507
508
            return;
509
        }
510
511
        // Otherwise:
512
        // 1. Remove always available flag on all fields
513
        $qAttr->set(
514
            $this->dbHandler->quoteColumn('language_id'),
515
            $qAttr->expr->bitAnd($this->dbHandler->quoteColumn('language_id'), -2)
516
        );
517
        $qAttr->prepare()->execute();
518
519
        // 2. If Content is always available set the flag only on fields in main language
520
        if ($alwaysAvailable) {
521
            $qAttr->set(
522
                $this->dbHandler->quoteColumn('language_id'),
523
                $qAttr->expr->bitOr($this->dbHandler->quoteColumn('language_id'), 1)
524
            );
525
            $qAttr->where(
526
                $qAttr->expr->gt(
527
                    $qAttr->expr->bitAnd(
528
                        $this->dbHandler->quoteColumn('language_id'),
529
                        $qAttr->bindValue($contentInfoRow['initial_language_id'], null, PDO::PARAM_INT)
530
                    ),
531
                    $qAttr->bindValue(0, null, PDO::PARAM_INT)
532
                )
533
            );
534
            $qAttr->prepare()->execute();
535
        }
536
    }
537
538
    /**
539
     * Sets the status of the version identified by $contentId and $version to $status.
540
     *
541
     * The $status can be one of STATUS_DRAFT, STATUS_PUBLISHED, STATUS_ARCHIVED
542
     *
543
     * @param int $contentId
544
     * @param int $version
545
     * @param int $status
546
     *
547
     * @return bool
548
     */
549
    public function setStatus($contentId, $version, $status)
550
    {
551
        $q = $this->dbHandler->createUpdateQuery();
552
        $q->update(
553
            $this->dbHandler->quoteTable('ezcontentobject_version')
554
        )->set(
555
            $this->dbHandler->quoteColumn('status'),
556
            $q->bindValue($status, null, \PDO::PARAM_INT)
557
        )->set(
558
            $this->dbHandler->quoteColumn('modified'),
559
            $q->bindValue(time(), null, \PDO::PARAM_INT)
560
        )->where(
561
            $q->expr->lAnd(
562
                $q->expr->eq(
563
                    $this->dbHandler->quoteColumn('contentobject_id'),
564
                    $q->bindValue($contentId, null, \PDO::PARAM_INT)
565
                ),
566
                $q->expr->eq(
567
                    $this->dbHandler->quoteColumn('version'),
568
                    $q->bindValue($version, null, \PDO::PARAM_INT)
569
                )
570
            )
571
        );
572
        $statement = $q->prepare();
573
        $statement->execute();
574
575
        if ((bool)$statement->rowCount() === false) {
576
            return false;
577
        }
578
579
        if ($status !== APIVersionInfo::STATUS_PUBLISHED) {
580
            return true;
581
        }
582
583
        // If the version's status is PUBLISHED, we set the content to published status as well
584
        $q = $this->dbHandler->createUpdateQuery();
585
        $q->update(
586
            $this->dbHandler->quoteTable('ezcontentobject')
587
        )->set(
588
            $this->dbHandler->quoteColumn('status'),
589
            $q->bindValue(ContentInfo::STATUS_PUBLISHED, null, \PDO::PARAM_INT)
590
        )->set(
591
            $this->dbHandler->quoteColumn('current_version'),
592
            $q->bindValue($version, null, \PDO::PARAM_INT)
593
        )->where(
594
            $q->expr->eq(
595
                $this->dbHandler->quoteColumn('id'),
596
                $q->bindValue($contentId, null, \PDO::PARAM_INT)
597
            )
598
        );
599
        $statement = $q->prepare();
600
        $statement->execute();
601
602
        return (bool)$statement->rowCount();
603
    }
604
605
    /**
606
     * Inserts a new field.
607
     *
608
     * Only used when a new field is created (i.e. a new object or a field in a
609
     * new language!). After that, field IDs need to stay the same, only the
610
     * version number changes.
611
     *
612
     * @param \eZ\Publish\SPI\Persistence\Content $content
613
     * @param \eZ\Publish\SPI\Persistence\Content\Field $field
614
     * @param \eZ\Publish\Core\Persistence\Legacy\Content\StorageFieldValue $value
615
     *
616
     * @return int ID
617
     */
618
    public function insertNewField(Content $content, Field $field, StorageFieldValue $value)
619
    {
620
        $q = $this->dbHandler->createInsertQuery();
621
622
        $this->setInsertFieldValues($q, $content, $field, $value);
623
624
        // Insert with auto increment ID
625
        $q->set(
626
            $this->dbHandler->quoteColumn('id'),
627
            $this->dbHandler->getAutoIncrementValue('ezcontentobject_attribute', 'id')
628
        );
629
630
        $q->prepare()->execute();
631
632
        return $this->dbHandler->lastInsertId(
633
            $this->dbHandler->getSequenceName('ezcontentobject_attribute', 'id')
634
        );
635
    }
636
637
    /**
638
     * Inserts an existing field.
639
     *
640
     * Used to insert a field with an exsting ID but a new version number.
641
     *
642
     * @param Content $content
643
     * @param Field $field
644
     * @param StorageFieldValue $value
645
     */
646
    public function insertExistingField(Content $content, Field $field, StorageFieldValue $value)
647
    {
648
        $q = $this->dbHandler->createInsertQuery();
649
650
        $this->setInsertFieldValues($q, $content, $field, $value);
651
652
        $q->set(
653
            $this->dbHandler->quoteColumn('id'),
654
            $q->bindValue($field->id, null, \PDO::PARAM_INT)
655
        );
656
657
        $q->prepare()->execute();
658
    }
659
660
    /**
661
     * Sets field (ezcontentobject_attribute) values to the given query.
662
     *
663
     * @param \eZ\Publish\Core\Persistence\Database\InsertQuery $q
664
     * @param Content $content
665
     * @param Field $field
666
     * @param StorageFieldValue $value
667
     */
668
    protected function setInsertFieldValues(InsertQuery $q, Content $content, Field $field, StorageFieldValue $value)
669
    {
670
        $q->insertInto(
671
            $this->dbHandler->quoteTable('ezcontentobject_attribute')
672
        )->set(
673
            $this->dbHandler->quoteColumn('contentobject_id'),
674
            $q->bindValue($content->versionInfo->contentInfo->id, null, \PDO::PARAM_INT)
675
        )->set(
676
            $this->dbHandler->quoteColumn('contentclassattribute_id'),
677
            $q->bindValue($field->fieldDefinitionId, null, \PDO::PARAM_INT)
678
        )->set(
679
            $this->dbHandler->quoteColumn('data_type_string'),
680
            $q->bindValue($field->type)
681
        )->set(
682
            $this->dbHandler->quoteColumn('language_code'),
683
            $q->bindValue($field->languageCode)
684
        )->set(
685
            $this->dbHandler->quoteColumn('version'),
686
            $q->bindValue($field->versionNo, null, \PDO::PARAM_INT)
687
        )->set(
688
            $this->dbHandler->quoteColumn('data_float'),
689
            $q->bindValue($value->dataFloat)
690
        )->set(
691
            $this->dbHandler->quoteColumn('data_int'),
692
            $q->bindValue($value->dataInt, null, \PDO::PARAM_INT)
693
        )->set(
694
            $this->dbHandler->quoteColumn('data_text'),
695
            $q->bindValue($value->dataText)
696
        )->set(
697
            $this->dbHandler->quoteColumn('sort_key_int'),
698
            $q->bindValue($value->sortKeyInt, null, \PDO::PARAM_INT)
699
        )->set(
700
            $this->dbHandler->quoteColumn('sort_key_string'),
701
            $q->bindValue(mb_substr($value->sortKeyString, 0, 255))
702
        )->set(
703
            $this->dbHandler->quoteColumn('language_id'),
704
            $q->bindValue(
705
                $this->languageMaskGenerator->generateLanguageIndicator(
706
                    $field->languageCode,
707
                    $this->isLanguageAlwaysAvailable($content, $field->languageCode)
708
                ),
709
                null,
710
                \PDO::PARAM_INT
711
            )
712
        );
713
    }
714
715
    /**
716
     * Checks if $languageCode is always available in $content.
717
     *
718
     * @param \eZ\Publish\SPI\Persistence\Content $content
719
     * @param string $languageCode
720
     *
721
     * @return bool
722
     */
723
    protected function isLanguageAlwaysAvailable(Content $content, $languageCode)
724
    {
725
        return (
726
            $content->versionInfo->contentInfo->alwaysAvailable &&
727
            $content->versionInfo->contentInfo->mainLanguageCode === $languageCode
728
        );
729
    }
730
731
    /**
732
     * Updates an existing field.
733
     *
734
     * @param Field $field
735
     * @param StorageFieldValue $value
736
     */
737
    public function updateField(Field $field, StorageFieldValue $value)
738
    {
739
        // Note, no need to care for language_id here, since Content->$alwaysAvailable
740
        // cannot change on update
741
        $q = $this->dbHandler->createUpdateQuery();
742
        $this->setFieldUpdateValues($q, $value);
743
        $q->where(
744
            $q->expr->lAnd(
745
                $q->expr->eq(
746
                    $this->dbHandler->quoteColumn('id'),
747
                    $q->bindValue($field->id, null, \PDO::PARAM_INT)
748
                ),
749
                $q->expr->eq(
750
                    $this->dbHandler->quoteColumn('version'),
751
                    $q->bindValue($field->versionNo, null, \PDO::PARAM_INT)
752
                )
753
            )
754
        );
755
        $q->prepare()->execute();
756
    }
757
758
    /**
759
     * Sets update fields for $value on $q.
760
     *
761
     * @param \eZ\Publish\Core\Persistence\Database\UpdateQuery $q
762
     * @param StorageFieldValue $value
763
     */
764
    protected function setFieldUpdateValues(UpdateQuery $q, StorageFieldValue $value)
765
    {
766
        $q->update(
767
            $this->dbHandler->quoteTable('ezcontentobject_attribute')
768
        )->set(
769
            $this->dbHandler->quoteColumn('data_float'),
770
            $q->bindValue($value->dataFloat)
771
        )->set(
772
            $this->dbHandler->quoteColumn('data_int'),
773
            $q->bindValue($value->dataInt, null, \PDO::PARAM_INT)
774
        )->set(
775
            $this->dbHandler->quoteColumn('data_text'),
776
            $q->bindValue($value->dataText)
777
        )->set(
778
            $this->dbHandler->quoteColumn('sort_key_int'),
779
            $q->bindValue($value->sortKeyInt, null, \PDO::PARAM_INT)
780
        )->set(
781
            $this->dbHandler->quoteColumn('sort_key_string'),
782
            $q->bindValue(mb_substr($value->sortKeyString, 0, 255))
783
        );
784
    }
785
786
    /**
787
     * Updates an existing, non-translatable field.
788
     *
789
     * @param \eZ\Publish\SPI\Persistence\Content\Field $field
790
     * @param \eZ\Publish\Core\Persistence\Legacy\Content\StorageFieldValue $value
791
     * @param int $contentId
792
     */
793
    public function updateNonTranslatableField(
794
        Field $field,
795
        StorageFieldValue $value,
796
        $contentId
797
    ) {
798
        // Note, no need to care for language_id here, since Content->$alwaysAvailable
799
        // cannot change on update
800
        $q = $this->dbHandler->createUpdateQuery();
801
        $this->setFieldUpdateValues($q, $value);
802
        $q->where(
803
            $q->expr->lAnd(
804
                $q->expr->eq(
805
                    $this->dbHandler->quoteColumn('contentclassattribute_id'),
806
                    $q->bindValue($field->fieldDefinitionId, null, \PDO::PARAM_INT)
807
                ),
808
                $q->expr->eq(
809
                    $this->dbHandler->quoteColumn('contentobject_id'),
810
                    $q->bindValue($contentId, null, \PDO::PARAM_INT)
811
                ),
812
                $q->expr->eq(
813
                    $this->dbHandler->quoteColumn('version'),
814
                    $q->bindValue($field->versionNo, null, \PDO::PARAM_INT)
815
                )
816
            )
817
        );
818
        $q->prepare()->execute();
819
    }
820
821
    /**
822
     * Loads data for a content object.
823
     *
824
     * Returns an array with the relevant data.
825
     *
826
     * @param mixed $contentId
827
     * @param mixed $version
828
     * @param string[] $translations
829
     *
830
     * @return array
831
     */
832
    public function load($contentId, $version, array $translations = null)
833
    {
834
        $query = $this->queryBuilder->createFindQuery($translations);
835
        $query->where(
836
            $query->expr->lAnd(
837
                $query->expr->eq(
838
                    $this->dbHandler->quoteColumn('id', 'ezcontentobject'),
839
                    $query->bindValue($contentId)
840
                ),
841
                $query->expr->eq(
842
                    $this->dbHandler->quoteColumn('version', 'ezcontentobject_version'),
843
                    $query->bindValue($version)
844
                )
845
            )
846
        );
847
        $statement = $query->prepare();
848
        $statement->execute();
849
850
        return $statement->fetchAll(\PDO::FETCH_ASSOC);
851
    }
852
853
    /**
854
     * @see loadContentInfo(), loadContentInfoByRemoteId()
855
     *
856
     * @param string $column
857
     * @param mixed $id
858
     *
859
     * @throws \eZ\Publish\Core\Base\Exceptions\NotFoundException
860
     *
861
     * @return array
862
     */
863
    private function internalLoadContentInfo($column, $id)
864
    {
865
        /** @var $query \eZ\Publish\Core\Persistence\Database\SelectQuery */
866
        $query = $this->dbHandler->createSelectQuery();
867
        $query->select(
868
            'ezcontentobject.*',
869
            $this->dbHandler->aliasedColumn($query, 'main_node_id', 'ezcontentobject_tree')
870
        )->from(
871
            $this->dbHandler->quoteTable('ezcontentobject')
872
        )->leftJoin(
873
            $this->dbHandler->quoteTable('ezcontentobject_tree'),
874
            $query->expr->lAnd(
875
                $query->expr->eq(
876
                    $this->dbHandler->quoteColumn('contentobject_id', 'ezcontentobject_tree'),
877
                    $this->dbHandler->quoteColumn('id', 'ezcontentobject')
878
                ),
879
                $query->expr->eq(
880
                    $this->dbHandler->quoteColumn('main_node_id', 'ezcontentobject_tree'),
881
                    $this->dbHandler->quoteColumn('node_id', 'ezcontentobject_tree')
882
                )
883
            )
884
        )->where(
885
            $query->expr->eq(
886
                $this->dbHandler->quoteColumn($column, 'ezcontentobject'),
887
                $query->bindValue($id, null, $column === 'id' ? PDO::PARAM_INT : PDO::PARAM_STR)
888
            )
889
        );
890
        $statement = $query->prepare();
891
        $statement->execute();
892
        $row = $statement->fetch(PDO::FETCH_ASSOC);
893
894
        if (empty($row)) {
895
            throw new NotFound('content', "$column: $id");
896
        }
897
898
        return $row;
899
    }
900
    /**
901
     * Loads info for content identified by $contentId.
902
     * Will basically return a hash containing all field values for ezcontentobject table plus some additional keys:
903
     *  - always_available => Boolean indicating if content's language mask contains alwaysAvailable bit field
904
     *  - main_language_code => Language code for main (initial) language. E.g. "eng-GB".
905
     *
906
     * @param int $contentId
907
     *
908
     * @throws \eZ\Publish\Core\Base\Exceptions\NotFoundException
909
     *
910
     * @return array
911
     */
912
    public function loadContentInfo($contentId)
913
    {
914
        return $this->internalLoadContentInfo('id', $contentId);
915
    }
916
917
    /**
918
     * Loads info for a content object identified by its remote ID.
919
     *
920
     * Returns an array with the relevant data.
921
     *
922
     * @param mixed $remoteId
923
     *
924
     * @throws \eZ\Publish\Core\Base\Exceptions\NotFoundException
925
     *
926
     * @return array
927
     */
928
    public function loadContentInfoByRemoteId($remoteId)
929
    {
930
        return $this->internalLoadContentInfo('remote_id', $remoteId);
931
    }
932
933
    /**
934
     * Loads version info for content identified by $contentId and $versionNo.
935
     * Will basically return a hash containing all field values from ezcontentobject_version table plus following keys:
936
     *  - names => Hash of content object names. Key is the language code, value is the name.
937
     *  - languages => Hash of language ids. Key is the language code (e.g. "eng-GB"), value is the language numeric id without the always available bit.
938
     *  - initial_language_code => Language code for initial language in this version.
939
     *
940
     * @param int $contentId
941
     * @param int $versionNo
942
     *
943
     * @return array
944
     */
945 View Code Duplication
    public function loadVersionInfo($contentId, $versionNo)
946
    {
947
        $query = $this->queryBuilder->createVersionInfoFindQuery();
948
        $query->where(
949
            $query->expr->lAnd(
950
                $query->expr->eq(
951
                    $this->dbHandler->quoteColumn('contentobject_id', 'ezcontentobject_version'),
952
                    $query->bindValue($contentId, null, \PDO::PARAM_INT)
953
                ),
954
                $query->expr->eq(
955
                    $this->dbHandler->quoteColumn('version', 'ezcontentobject_version'),
956
                    $query->bindValue($versionNo, null, \PDO::PARAM_INT)
957
                )
958
            )
959
        );
960
        $statement = $query->prepare();
961
        $statement->execute();
962
963
        return $statement->fetchAll(\PDO::FETCH_ASSOC);
964
    }
965
966
    /**
967
     * Returns data for all versions with given status created by the given $userId.
968
     *
969
     * @param int $userId
970
     * @param int $status
971
     *
972
     * @return string[][]
973
     */
974
    public function listVersionsForUser($userId, $status = VersionInfo::STATUS_DRAFT)
975
    {
976
        $query = $this->queryBuilder->createVersionInfoFindQuery();
977
        $query->where(
978
            $query->expr->lAnd(
979
                $query->expr->eq(
980
                    $this->dbHandler->quoteColumn('status', 'ezcontentobject_version'),
981
                    $query->bindValue($status, null, \PDO::PARAM_INT)
982
                ),
983
                $query->expr->eq(
984
                    $this->dbHandler->quoteColumn('creator_id', 'ezcontentobject_version'),
985
                    $query->bindValue($userId, null, \PDO::PARAM_INT)
986
                )
987
            )
988
        );
989
990
        return $this->listVersionsHelper($query);
991
    }
992
993
    /**
994
     * Returns all version data for the given $contentId.
995
     *
996
     * @param mixed $contentId
997
     *
998
     * @return string[][]
999
     */
1000
    public function listVersions($contentId)
1001
    {
1002
        $query = $this->queryBuilder->createVersionInfoFindQuery();
1003
        $query->where(
1004
            $query->expr->eq(
1005
                $this->dbHandler->quoteColumn('contentobject_id', 'ezcontentobject_version'),
1006
                $query->bindValue($contentId, null, \PDO::PARAM_INT)
1007
            )
1008
        );
1009
1010
        return $this->listVersionsHelper($query);
1011
    }
1012
1013
    /**
1014
     * Helper for {@see listVersions()} and {@see listVersionsForUser()} that filters duplicates
1015
     * that are the result of the cartesian product performed by createVersionInfoFindQuery().
1016
     *
1017
     * @param \eZ\Publish\Core\Persistence\Database\SelectQuery $query
1018
     *
1019
     * @return string[][]
1020
     */
1021
    private function listVersionsHelper(SelectQuery $query)
1022
    {
1023
        $query->orderBy(
1024
            $this->dbHandler->quoteColumn('id', 'ezcontentobject_version')
1025
        );
1026
1027
        $statement = $query->prepare();
1028
        $statement->execute();
1029
1030
        $results = array();
1031
        $previousId = null;
1032
        foreach ($statement->fetchAll(\PDO::FETCH_ASSOC) as $row) {
1033
            if ($row['ezcontentobject_version_id'] == $previousId) {
1034
                continue;
1035
            }
1036
1037
            $previousId = $row['ezcontentobject_version_id'];
1038
            $results[] = $row;
1039
        }
1040
1041
        return $results;
1042
    }
1043
1044
    /**
1045
     * Returns all version numbers for the given $contentId.
1046
     *
1047
     * @param mixed $contentId
1048
     *
1049
     * @return int[]
1050
     */
1051
    public function listVersionNumbers($contentId)
1052
    {
1053
        $query = $this->dbHandler->createSelectQuery();
1054
        $query->selectDistinct(
1055
            $this->dbHandler->quoteColumn('version')
1056
        )->from(
1057
            $this->dbHandler->quoteTable('ezcontentobject_version')
1058
        )->where(
1059
            $query->expr->eq(
1060
                $this->dbHandler->quoteColumn('contentobject_id'),
1061
                $query->bindValue($contentId, null, \PDO::PARAM_INT)
1062
            )
1063
        );
1064
1065
        $statement = $query->prepare();
1066
        $statement->execute();
1067
1068
        return $statement->fetchAll(\PDO::FETCH_COLUMN);
1069
    }
1070
1071
    /**
1072
     * Returns last version number for content identified by $contentId.
1073
     *
1074
     * @param int $contentId
1075
     *
1076
     * @return int
1077
     */
1078
    public function getLastVersionNumber($contentId)
1079
    {
1080
        $query = $this->dbHandler->createSelectQuery();
1081
        $query->select(
1082
            $query->expr->max($this->dbHandler->quoteColumn('version'))
1083
        )->from(
1084
            $this->dbHandler->quoteTable('ezcontentobject_version')
1085
        )->where(
1086
            $query->expr->eq(
1087
                $this->dbHandler->quoteColumn('contentobject_id'),
1088
                $query->bindValue($contentId, null, \PDO::PARAM_INT)
1089
            )
1090
        );
1091
1092
        $statement = $query->prepare();
1093
        $statement->execute();
1094
1095
        return (int)$statement->fetchColumn();
1096
    }
1097
1098
    /**
1099
     * Returns all IDs for locations that refer to $contentId.
1100
     *
1101
     * @param int $contentId
1102
     *
1103
     * @return int[]
1104
     */
1105
    public function getAllLocationIds($contentId)
1106
    {
1107
        $query = $this->dbHandler->createSelectQuery();
1108
        $query->select(
1109
            $this->dbHandler->quoteColumn('node_id')
1110
        )->from(
1111
            $this->dbHandler->quoteTable('ezcontentobject_tree')
1112
        )->where(
1113
            $query->expr->eq(
1114
                $this->dbHandler->quoteColumn('contentobject_id'),
1115
                $query->bindValue($contentId, null, \PDO::PARAM_INT)
1116
            )
1117
        );
1118
1119
        $statement = $query->prepare();
1120
        $statement->execute();
1121
1122
        return $statement->fetchAll(\PDO::FETCH_COLUMN);
1123
    }
1124
1125
    /**
1126
     * Returns all field IDs of $contentId grouped by their type.
1127
     * If $versionNo is set only field IDs for that version are returned.
1128
     *
1129
     * @param int $contentId
1130
     * @param int|null $versionNo
1131
     *
1132
     * @return int[][]
1133
     */
1134
    public function getFieldIdsByType($contentId, $versionNo = null)
1135
    {
1136
        $query = $this->dbHandler->createSelectQuery();
1137
        $query->select(
1138
            $this->dbHandler->quoteColumn('id'),
1139
            $this->dbHandler->quoteColumn('data_type_string')
1140
        )->from(
1141
            $this->dbHandler->quoteTable('ezcontentobject_attribute')
1142
        )->where(
1143
            $query->expr->eq(
1144
                $this->dbHandler->quoteColumn('contentobject_id'),
1145
                $query->bindValue($contentId, null, \PDO::PARAM_INT)
1146
            )
1147
        );
1148
1149
        if (isset($versionNo)) {
1150
            $query->where(
1151
                $query->expr->eq(
1152
                    $this->dbHandler->quoteColumn('version'),
1153
                    $query->bindValue($versionNo, null, \PDO::PARAM_INT)
1154
                )
1155
            );
1156
        }
1157
1158
        $statement = $query->prepare();
1159
        $statement->execute();
1160
1161
        $result = array();
1162
        foreach ($statement->fetchAll() as $row) {
1163
            if (!isset($result[$row['data_type_string']])) {
1164
                $result[$row['data_type_string']] = array();
1165
            }
1166
            $result[$row['data_type_string']][] = (int)$row['id'];
1167
        }
1168
1169
        return $result;
1170
    }
1171
1172
    /**
1173
     * Deletes relations to and from $contentId.
1174
     * If $versionNo is set only relations for that version are deleted.
1175
     *
1176
     * @param int $contentId
1177
     * @param int|null $versionNo
1178
     */
1179
    public function deleteRelations($contentId, $versionNo = null)
1180
    {
1181
        $query = $this->dbHandler->createDeleteQuery();
1182
        $query->deleteFrom(
1183
            $this->dbHandler->quoteTable('ezcontentobject_link')
1184
        );
1185
1186
        if (isset($versionNo)) {
1187
            $query->where(
1188
                $query->expr->lAnd(
1189
                    $query->expr->eq(
1190
                        $this->dbHandler->quoteColumn('from_contentobject_id'),
1191
                        $query->bindValue($contentId, null, \PDO::PARAM_INT)
1192
                    ),
1193
                    $query->expr->eq(
1194
                        $this->dbHandler->quoteColumn('from_contentobject_version'),
1195
                        $query->bindValue($versionNo, null, \PDO::PARAM_INT)
1196
                    )
1197
                )
1198
            );
1199
        } else {
1200
            $query->where(
1201
                $query->expr->lOr(
1202
                    $query->expr->eq(
1203
                        $this->dbHandler->quoteColumn('from_contentobject_id'),
1204
                        $query->bindValue($contentId, null, \PDO::PARAM_INT)
1205
                    ),
1206
                    $query->expr->eq(
1207
                        $this->dbHandler->quoteColumn('to_contentobject_id'),
1208
                        $query->bindValue($contentId, null, \PDO::PARAM_INT)
1209
                    )
1210
                )
1211
            );
1212
        }
1213
1214
        $query->prepare()->execute();
1215
    }
1216
1217
    /**
1218
     * Removes relations to Content with $contentId from Relation and RelationList field type fields.
1219
     *
1220
     * @param int $contentId
1221
     */
1222
    public function removeReverseFieldRelations($contentId)
1223
    {
1224
        $query = $this->dbHandler->createSelectQuery();
1225
        $query
1226
            ->select('ezcontentobject_attribute.*')
1227
            ->from('ezcontentobject_attribute')
1228
            ->innerJoin(
1229
                'ezcontentobject_link',
1230
                $query->expr->lAnd(
1231
                    $query->expr->eq(
1232
                        $this->dbHandler->quoteColumn('from_contentobject_id', 'ezcontentobject_link'),
1233
                        $this->dbHandler->quoteColumn('contentobject_id', 'ezcontentobject_attribute')
1234
                    ),
1235
                    $query->expr->eq(
1236
                        $this->dbHandler->quoteColumn('from_contentobject_version', 'ezcontentobject_link'),
1237
                        $this->dbHandler->quoteColumn('version', 'ezcontentobject_attribute')
1238
                    ),
1239
                    $query->expr->eq(
1240
                        $this->dbHandler->quoteColumn('contentclassattribute_id', 'ezcontentobject_link'),
1241
                        $this->dbHandler->quoteColumn('contentclassattribute_id', 'ezcontentobject_attribute')
1242
                    )
1243
                )
1244
            )
1245
            ->where(
1246
                $query->expr->eq(
1247
                    $this->dbHandler->quoteColumn('to_contentobject_id', 'ezcontentobject_link'),
1248
                    $query->bindValue($contentId, null, PDO::PARAM_INT)
1249
                ),
1250
                $query->expr->gt(
1251
                    $query->expr->bitAnd(
1252
                        $this->dbHandler->quoteColumn('relation_type', 'ezcontentobject_link'),
1253
                        $query->bindValue(8, null, PDO::PARAM_INT)
1254
                    ),
1255
                    0
1256
                )
1257
            );
1258
1259
        $statement = $query->prepare();
1260
        $statement->execute();
1261
1262
        while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
1263
            if ($row['data_type_string'] === 'ezobjectrelation') {
1264
                $this->removeRelationFromRelationField($row);
1265
            }
1266
1267
            if ($row['data_type_string'] === 'ezobjectrelationlist') {
1268
                $this->removeRelationFromRelationListField($contentId, $row);
1269
            }
1270
        }
1271
    }
1272
1273
    /**
1274
     * Updates field value of RelationList field type identified by given $row data,
1275
     * removing relations toward given $contentId.
1276
     *
1277
     * @param int $contentId
1278
     * @param array $row
1279
     */
1280
    protected function removeRelationFromRelationListField($contentId, array $row)
1281
    {
1282
        $document = new DOMDocument('1.0', 'utf-8');
1283
        $document->loadXML($row['data_text']);
1284
1285
        $xpath = new DOMXPath($document);
1286
        $xpathExpression = "//related-objects/relation-list/relation-item[@contentobject-id='{$contentId}']";
1287
1288
        $relationItems = $xpath->query($xpathExpression);
1289
        foreach ($relationItems as $relationItem) {
1290
            $relationItem->parentNode->removeChild($relationItem);
1291
        }
1292
1293
        $query = $this->dbHandler->createUpdateQuery();
1294
        $query
1295
            ->update('ezcontentobject_attribute')
1296
            ->set(
1297
                'data_text',
1298
                $query->bindValue($document->saveXML(), null, PDO::PARAM_STR)
1299
            )
1300
            ->where(
1301
                $query->expr->lAnd(
1302
                    $query->expr->eq(
1303
                        $this->dbHandler->quoteColumn('id'),
1304
                        $query->bindValue($row['id'], null, PDO::PARAM_INT)
1305
                    ),
1306
                    $query->expr->eq(
1307
                        $this->dbHandler->quoteColumn('version'),
1308
                        $query->bindValue($row['version'], null, PDO::PARAM_INT)
1309
                    )
1310
                )
1311
            );
1312
1313
        $query->prepare()->execute();
1314
    }
1315
1316
    /**
1317
     * Updates field value of Relation field type identified by given $row data,
1318
     * removing relation data.
1319
     *
1320
     * @param array $row
1321
     */
1322
    protected function removeRelationFromRelationField(array $row)
1323
    {
1324
        $query = $this->dbHandler->createUpdateQuery();
1325
        $query
1326
            ->update('ezcontentobject_attribute')
1327
            ->set('data_int', $query->bindValue(null, null, PDO::PARAM_INT))
1328
            ->set('sort_key_int', $query->bindValue(0, null, PDO::PARAM_INT))
1329
            ->where(
1330
                $query->expr->lAnd(
1331
                    $query->expr->eq(
1332
                        $this->dbHandler->quoteColumn('id'),
1333
                        $query->bindValue($row['id'], null, PDO::PARAM_INT)
1334
                    ),
1335
                    $query->expr->eq(
1336
                        $this->dbHandler->quoteColumn('version'),
1337
                        $query->bindValue($row['version'], null, PDO::PARAM_INT)
1338
                    )
1339
                )
1340
            );
1341
1342
        $query->prepare()->execute();
1343
    }
1344
1345
    /**
1346
     * Deletes the field with the given $fieldId.
1347
     *
1348
     * @param int $fieldId
1349
     */
1350
    public function deleteField($fieldId)
1351
    {
1352
        $query = $this->dbHandler->createDeleteQuery();
1353
        $query->deleteFrom(
1354
            $this->dbHandler->quoteTable('ezcontentobject_attribute')
1355
        )->where(
1356
            $query->expr->eq(
1357
                $this->dbHandler->quoteColumn('id'),
1358
                $query->bindValue($fieldId, null, \PDO::PARAM_INT)
1359
            )
1360
        );
1361
1362
        $query->prepare()->execute();
1363
    }
1364
1365
    /**
1366
     * Deletes all fields of $contentId in all versions.
1367
     * If $versionNo is set only fields for that version are deleted.
1368
     *
1369
     * @param int $contentId
1370
     * @param int|null $versionNo
1371
     */
1372
    public function deleteFields($contentId, $versionNo = null)
1373
    {
1374
        $query = $this->dbHandler->createDeleteQuery();
1375
        $query->deleteFrom('ezcontentobject_attribute')
1376
            ->where(
1377
                $query->expr->eq(
1378
                    $this->dbHandler->quoteColumn('contentobject_id'),
1379
                    $query->bindValue($contentId, null, \PDO::PARAM_INT)
1380
                )
1381
            );
1382
1383
        if (isset($versionNo)) {
1384
            $query->where(
1385
                $query->expr->eq(
1386
                    $this->dbHandler->quoteColumn('version'),
1387
                    $query->bindValue($versionNo, null, \PDO::PARAM_INT)
1388
                )
1389
            );
1390
        }
1391
1392
        $query->prepare()->execute();
1393
    }
1394
1395
    /**
1396
     * Deletes all versions of $contentId.
1397
     * If $versionNo is set only that version is deleted.
1398
     *
1399
     * @param int $contentId
1400
     * @param int|null $versionNo
1401
     */
1402
    public function deleteVersions($contentId, $versionNo = null)
1403
    {
1404
        $query = $this->dbHandler->createDeleteQuery();
1405
        $query->deleteFrom('ezcontentobject_version')
1406
            ->where(
1407
                $query->expr->eq(
1408
                    $this->dbHandler->quoteColumn('contentobject_id'),
1409
                    $query->bindValue($contentId, null, \PDO::PARAM_INT)
1410
                )
1411
            );
1412
1413
        if (isset($versionNo)) {
1414
            $query->where(
1415
                $query->expr->eq(
1416
                    $this->dbHandler->quoteColumn('version'),
1417
                    $query->bindValue($versionNo, null, \PDO::PARAM_INT)
1418
                )
1419
            );
1420
        }
1421
1422
        $query->prepare()->execute();
1423
    }
1424
1425
    /**
1426
     * Deletes all names of $contentId.
1427
     * If $versionNo is set only names for that version are deleted.
1428
     *
1429
     * @param int $contentId
1430
     * @param int|null $versionNo
1431
     */
1432
    public function deleteNames($contentId, $versionNo = null)
1433
    {
1434
        $query = $this->dbHandler->createDeleteQuery();
1435
        $query->deleteFrom('ezcontentobject_name')
1436
            ->where(
1437
                $query->expr->eq(
1438
                    $this->dbHandler->quoteColumn('contentobject_id'),
1439
                    $query->bindValue($contentId, null, \PDO::PARAM_INT)
1440
                )
1441
            );
1442
1443
        if (isset($versionNo)) {
1444
            $query->where(
1445
                $query->expr->eq(
1446
                    $this->dbHandler->quoteColumn('content_version'),
1447
                    $query->bindValue($versionNo, null, \PDO::PARAM_INT)
1448
                )
1449
            );
1450
        }
1451
1452
        $query->prepare()->execute();
1453
    }
1454
1455
    /**
1456
     * Sets the name for Content $contentId in version $version to $name in $language.
1457
     *
1458
     * @param int $contentId
1459
     * @param int $version
1460
     * @param string $name
1461
     * @param string $language
1462
     */
1463
    public function setName($contentId, $version, $name, $language)
1464
    {
1465
        $language = $this->languageHandler->loadByLanguageCode($language);
1466
1467
        // Is it an insert or an update ?
1468
        $qSelect = $this->dbHandler->createSelectQuery();
1469
        $qSelect
1470
            ->select(
1471
                $qSelect->alias($qSelect->expr->count('*'), 'count')
1472
            )
1473
            ->from($this->dbHandler->quoteTable('ezcontentobject_name'))
1474
            ->where(
1475
                $qSelect->expr->lAnd(
1476
                    $qSelect->expr->eq($this->dbHandler->quoteColumn('contentobject_id'), $qSelect->bindValue($contentId)),
1477
                    $qSelect->expr->eq($this->dbHandler->quoteColumn('content_version'), $qSelect->bindValue($version)),
1478
                    $qSelect->expr->eq($this->dbHandler->quoteColumn('content_translation'), $qSelect->bindValue($language->languageCode))
1479
                )
1480
            );
1481
        $stmt = $qSelect->prepare();
1482
        $stmt->execute();
1483
        $res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
1484
1485
        $insert = $res[0]['count'] == 0;
1486
        if ($insert) {
1487
            $q = $this->dbHandler->createInsertQuery();
1488
            $q->insertInto($this->dbHandler->quoteTable('ezcontentobject_name'));
1489
        } else {
1490
            $q = $this->dbHandler->createUpdateQuery();
1491
            $q->update($this->dbHandler->quoteTable('ezcontentobject_name'))
1492
                ->where(
1493
                    $q->expr->lAnd(
1494
                        $q->expr->eq($this->dbHandler->quoteColumn('contentobject_id'), $q->bindValue($contentId)),
1495
                        $q->expr->eq($this->dbHandler->quoteColumn('content_version'), $q->bindValue($version)),
1496
                        $q->expr->eq($this->dbHandler->quoteColumn('content_translation'), $q->bindValue($language->languageCode))
1497
                    )
1498
                );
1499
        }
1500
1501
        $q->set(
1502
            $this->dbHandler->quoteColumn('contentobject_id'),
1503
            $q->bindValue($contentId, null, \PDO::PARAM_INT)
1504
        )->set(
1505
            $this->dbHandler->quoteColumn('content_version'),
1506
            $q->bindValue($version, null, \PDO::PARAM_INT)
1507
        )->set(
1508
            $this->dbHandler->quoteColumn('language_id'),
1509
            $q->bindValue($language->id, null, \PDO::PARAM_INT)
1510
        )->set(
1511
            $this->dbHandler->quoteColumn('content_translation'),
1512
            $q->bindValue($language->languageCode)
1513
        )->set(
1514
            $this->dbHandler->quoteColumn('real_translation'),
1515
            $q->bindValue($language->languageCode)
1516
        )->set(
1517
            $this->dbHandler->quoteColumn('name'),
1518
            $q->bindValue($name)
1519
        );
1520
        $q->prepare()->execute();
1521
    }
1522
1523
    /**
1524
     * Deletes the actual content object referred to by $contentId.
1525
     *
1526
     * @param int $contentId
1527
     */
1528
    public function deleteContent($contentId)
1529
    {
1530
        $query = $this->dbHandler->createDeleteQuery();
1531
        $query->deleteFrom('ezcontentobject')
1532
            ->where(
1533
                $query->expr->eq(
1534
                    $this->dbHandler->quoteColumn('id'),
1535
                    $query->bindValue($contentId, null, \PDO::PARAM_INT)
1536
                )
1537
            );
1538
1539
        $query->prepare()->execute();
1540
    }
1541
1542
    /**
1543
     * Loads relations from $contentId to published content, optionally only from $contentVersionNo.
1544
     *
1545
     * $relationType can also be filtered.
1546
     *
1547
     * @param int $contentId
1548
     * @param int $contentVersionNo
1549
     * @param int $relationType
1550
     *
1551
     * @return string[][] array of relation data
1552
     */
1553
    public function loadRelations($contentId, $contentVersionNo = null, $relationType = null)
1554
    {
1555
        $query = $this->queryBuilder->createRelationFindQuery();
1556
        $query->innerJoin(
1557
            $query->alias(
1558
                $this->dbHandler->quoteTable('ezcontentobject'),
1559
                'ezcontentobject_to'
1560
            ),
1561
            $query->expr->lAnd(
1562
                $query->expr->eq(
1563
                    $this->dbHandler->quoteColumn('to_contentobject_id', 'ezcontentobject_link'),
1564
                    $this->dbHandler->quoteColumn('id', 'ezcontentobject_to')
1565
                ),
1566
                $query->expr->eq(
1567
                    $this->dbHandler->quoteColumn('status', 'ezcontentobject_to'),
1568
                    $query->bindValue(1, null, \PDO::PARAM_INT)
1569
                )
1570
            )
1571
        )->where(
1572
            $query->expr->eq(
1573
                $this->dbHandler->quoteColumn('from_contentobject_id', 'ezcontentobject_link'),
1574
                $query->bindValue($contentId, null, \PDO::PARAM_INT)
1575
            )
1576
        );
1577
1578
        // source version number
1579
        if (isset($contentVersionNo)) {
1580
            $query->where(
1581
                $query->expr->eq(
1582
                    $this->dbHandler->quoteColumn('from_contentobject_version', 'ezcontentobject_link'),
1583
                    $query->bindValue($contentVersionNo, null, \PDO::PARAM_INT)
1584
                )
1585
            );
1586
        } else { // from published version only
1587
            $query->from(
1588
                $this->dbHandler->quoteTable('ezcontentobject')
1589
            )->where(
1590
                $query->expr->lAnd(
1591
                    $query->expr->eq(
1592
                        $this->dbHandler->quoteColumn('id', 'ezcontentobject'),
1593
                        $this->dbHandler->quoteColumn('from_contentobject_id', 'ezcontentobject_link')
1594
                    ),
1595
                    $query->expr->eq(
1596
                        $this->dbHandler->quoteColumn('current_version', 'ezcontentobject'),
1597
                        $this->dbHandler->quoteColumn('from_contentobject_version', 'ezcontentobject_link')
1598
                    )
1599
                )
1600
            );
1601
        }
1602
1603
        // relation type
1604 View Code Duplication
        if (isset($relationType)) {
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...
1605
            $query->where(
1606
                $query->expr->gt(
1607
                    $query->expr->bitAnd(
1608
                        $this->dbHandler->quoteColumn('relation_type', 'ezcontentobject_link'),
1609
                        $query->bindValue($relationType, null, \PDO::PARAM_INT)
1610
                    ),
1611
                    0
1612
                )
1613
            );
1614
        }
1615
1616
        $statement = $query->prepare();
1617
        $statement->execute();
1618
1619
        return $statement->fetchAll(\PDO::FETCH_ASSOC);
1620
    }
1621
1622
    /**
1623
     * Loads data that related to $toContentId.
1624
     *
1625
     * @param int $toContentId
1626
     * @param int $relationType
1627
     *
1628
     * @return mixed[][] Content data, array structured like {@see \eZ\Publish\Core\Persistence\Legacy\Content\Gateway::load()}
1629
     */
1630
    public function loadReverseRelations($toContentId, $relationType = null)
1631
    {
1632
        $query = $this->queryBuilder->createRelationFindQuery();
1633
        $query->where(
1634
            $query->expr->eq(
1635
                $this->dbHandler->quoteColumn('to_contentobject_id', 'ezcontentobject_link'),
1636
                $query->bindValue($toContentId, null, \PDO::PARAM_INT)
1637
            )
1638
        );
1639
1640
        // ezcontentobject join
1641
        $query->from(
1642
            $this->dbHandler->quoteTable('ezcontentobject')
1643
        )->where(
1644
            $query->expr->lAnd(
1645
                $query->expr->eq(
1646
                    $this->dbHandler->quoteColumn('id', 'ezcontentobject'),
1647
                    $this->dbHandler->quoteColumn('from_contentobject_id', 'ezcontentobject_link')
1648
                ),
1649
                $query->expr->eq(
1650
                    $this->dbHandler->quoteColumn('current_version', 'ezcontentobject'),
1651
                    $this->dbHandler->quoteColumn('from_contentobject_version', 'ezcontentobject_link')
1652
                ),
1653
                $query->expr->eq(
1654
                    $this->dbHandler->quoteColumn('status', 'ezcontentobject'),
1655
                    $query->bindValue(1, null, \PDO::PARAM_INT)
1656
                )
1657
            )
1658
        );
1659
1660
        // relation type
1661 View Code Duplication
        if (isset($relationType)) {
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...
1662
            $query->where(
1663
                $query->expr->gt(
1664
                    $query->expr->bitAnd(
1665
                        $this->dbHandler->quoteColumn('relation_type', 'ezcontentobject_link'),
1666
                        $query->bindValue($relationType, null, \PDO::PARAM_INT)
1667
                    ),
1668
                    0
1669
                )
1670
            );
1671
        }
1672
1673
        $statement = $query->prepare();
1674
1675
        $statement->execute();
1676
1677
        return $statement->fetchAll(\PDO::FETCH_ASSOC);
1678
    }
1679
1680
    /**
1681
     * Inserts a new relation database record.
1682
     *
1683
     * @param \eZ\Publish\SPI\Persistence\Content\Relation\CreateStruct $createStruct
1684
     *
1685
     * @return int ID the inserted ID
1686
     */
1687 View Code Duplication
    public function insertRelation(RelationCreateStruct $createStruct)
1688
    {
1689
        $q = $this->dbHandler->createInsertQuery();
1690
        $q->insertInto(
1691
            $this->dbHandler->quoteTable('ezcontentobject_link')
1692
        )->set(
1693
            $this->dbHandler->quoteColumn('id'),
1694
            $this->dbHandler->getAutoIncrementValue('ezcontentobject_link', 'id')
1695
        )->set(
1696
            $this->dbHandler->quoteColumn('contentclassattribute_id'),
1697
            $q->bindValue((int)$createStruct->sourceFieldDefinitionId, null, \PDO::PARAM_INT)
1698
        )->set(
1699
            $this->dbHandler->quoteColumn('from_contentobject_id'),
1700
            $q->bindValue($createStruct->sourceContentId, null, \PDO::PARAM_INT)
1701
        )->set(
1702
            $this->dbHandler->quoteColumn('from_contentobject_version'),
1703
            $q->bindValue($createStruct->sourceContentVersionNo, null, \PDO::PARAM_INT)
1704
        )->set(
1705
            $this->dbHandler->quoteColumn('relation_type'),
1706
            $q->bindValue($createStruct->type, null, \PDO::PARAM_INT)
1707
        )->set(
1708
            $this->dbHandler->quoteColumn('to_contentobject_id'),
1709
            $q->bindValue($createStruct->destinationContentId, null, \PDO::PARAM_INT)
1710
        );
1711
1712
        $q->prepare()->execute();
1713
1714
        return $this->dbHandler->lastInsertId(
1715
            $this->dbHandler->getSequenceName('ezcontentobject_link', 'id')
1716
        );
1717
    }
1718
1719
    /**
1720
     * Deletes the relation with the given $relationId.
1721
     *
1722
     * @param int $relationId
1723
     * @param int $type {@see \eZ\Publish\API\Repository\Values\Content\Relation::COMMON,
1724
     *                 \eZ\Publish\API\Repository\Values\Content\Relation::EMBED,
1725
     *                 \eZ\Publish\API\Repository\Values\Content\Relation::LINK,
1726
     *                 \eZ\Publish\API\Repository\Values\Content\Relation::FIELD}
1727
     */
1728
    public function deleteRelation($relationId, $type)
1729
    {
1730
        // Legacy Storage stores COMMON, LINK and EMBED types using bitmask, therefore first load
1731
        // existing relation type by given $relationId for comparison
1732
        /** @var $query \eZ\Publish\Core\Persistence\Database\SelectQuery */
1733
        $query = $this->dbHandler->createSelectQuery();
1734
        $query->select(
1735
            $this->dbHandler->quoteColumn('relation_type')
1736
        )->from(
1737
            $this->dbHandler->quoteTable('ezcontentobject_link')
1738
        )->where(
1739
            $query->expr->eq(
1740
                $this->dbHandler->quoteColumn('id'),
1741
                $query->bindValue($relationId, null, \PDO::PARAM_INT)
1742
            )
1743
        );
1744
1745
        $statement = $query->prepare();
1746
        $statement->execute();
1747
        $loadedRelationType = $statement->fetchColumn();
1748
1749
        if (!$loadedRelationType) {
1750
            return;
1751
        }
1752
1753
        // If relation type matches then delete
1754
        if ($loadedRelationType == $type) {
1755
            /** @var $query \eZ\Publish\Core\Persistence\Database\DeleteQuery */
1756
            $query = $this->dbHandler->createDeleteQuery();
1757
            $query->deleteFrom(
1758
                'ezcontentobject_link'
1759
            )->where(
1760
                $query->expr->eq(
1761
                    $this->dbHandler->quoteColumn('id'),
1762
                    $query->bindValue($relationId, null, \PDO::PARAM_INT)
1763
                )
1764
            );
1765
1766
            $query->prepare()->execute();
1767
        } elseif ($loadedRelationType & $type) { // If relation type is composite update bitmask
1768
            /** @var $query \eZ\Publish\Core\Persistence\Database\UpdateQuery */
1769
            $query = $this->dbHandler->createUpdateQuery();
1770
            $query->update(
1771
                $this->dbHandler->quoteTable('ezcontentobject_link')
1772
            )->set(
1773
                $this->dbHandler->quoteColumn('relation_type'),
1774
                $query->expr->bitAnd(
1775
                    $this->dbHandler->quoteColumn('relation_type'),
1776
                    $query->bindValue(~$type, null, \PDO::PARAM_INT)
1777
                )
1778
            )->where(
1779
                $query->expr->eq(
1780
                    $this->dbHandler->quoteColumn('id'),
1781
                    $query->bindValue($relationId, null, \PDO::PARAM_INT)
1782
                )
1783
            );
1784
1785
            $query->prepare()->execute();
1786
        } else {
1787
            // No match, do nothing
1788
        }
1789
    }
1790
1791
    /**
1792
     * Returns all Content IDs for a given $contentTypeId.
1793
     *
1794
     * @param int $contentTypeId
1795
     *
1796
     * @return int[]
1797
     */
1798
    public function getContentIdsByContentTypeId($contentTypeId)
1799
    {
1800
        $query = $this->dbHandler->createSelectQuery();
1801
        $query
1802
            ->select($this->dbHandler->quoteColumn('id'))
1803
            ->from($this->dbHandler->quoteTable('ezcontentobject'))
1804
            ->where(
1805
                $query->expr->eq(
1806
                    $this->dbHandler->quoteColumn('contentclass_id'),
1807
                    $query->bindValue($contentTypeId, null, PDO::PARAM_INT)
1808
                )
1809
            );
1810
1811
        $statement = $query->prepare();
1812
        $statement->execute();
1813
1814
        return $statement->fetchAll(PDO::FETCH_COLUMN);
1815
    }
1816
1817
    /**
1818
     * Load name data for set of content id's and corresponding version number.
1819
     *
1820
     * @param array[] $rows array of hashes with 'id' and 'version' to load names for
1821
     *
1822
     * @return array
1823
     */
1824
    public function loadVersionedNameData($rows)
1825
    {
1826
        $query = $this->queryBuilder->createNamesQuery();
1827
        $conditions = array();
1828
        foreach ($rows as $row) {
1829
            $conditions[] = $query->expr->lAnd(
1830
                $query->expr->eq(
1831
                    $this->dbHandler->quoteColumn('contentobject_id'),
1832
                    $query->bindValue($row['id'], null, \PDO::PARAM_INT)
1833
                ),
1834
                $query->expr->eq(
1835
                    $this->dbHandler->quoteColumn('content_version'),
1836
                    $query->bindValue($row['version'], null, \PDO::PARAM_INT)
1837
                )
1838
            );
1839
        }
1840
1841
        $query->where($query->expr->lOr($conditions));
1842
        $stmt = $query->prepare();
1843
        $stmt->execute();
1844
1845
        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
1846
    }
1847
1848
    /**
1849
     * Batch method for copying all relation meta data for copied Content object.
1850
     *
1851
     * {@inheritdoc}
1852
     *
1853
     * @param int $originalContentId
1854
     * @param int $copiedContentId
1855
     * @param int|null $versionNo If specified only copy for a given version number, otherwise all.
1856
     */
1857
    public function copyRelations($originalContentId, $copiedContentId, $versionNo = null)
1858
    {
1859
        // Given we can retain all columns, we just create copies with new `from_contentobject_id` using INSERT INTO SELECT
1860
        $sql = 'INSERT INTO ezcontentobject_link ( contentclassattribute_id, from_contentobject_id, from_contentobject_version, relation_type, to_contentobject_id )
1861
                SELECT  L2.contentclassattribute_id, :copied_id, L2.from_contentobject_version, L2.relation_type, L2.to_contentobject_id
1862
                FROM    ezcontentobject_link AS L2
1863
                WHERE   L2.from_contentobject_id = :original_id';
1864
1865
        if ($versionNo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $versionNo of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1866
            $stmt = $this->connection->prepare($sql . ' AND L2.from_contentobject_version = :version');
1867
            $stmt->bindValue('version', $versionNo, PDO::PARAM_INT);
1868
        } else {
1869
            $stmt = $this->connection->prepare($sql);
1870
        }
1871
1872
        $stmt->bindValue('original_id', $originalContentId, PDO::PARAM_INT);
1873
        $stmt->bindValue('copied_id', $copiedContentId, PDO::PARAM_INT);
1874
1875
        $stmt->execute();
1876
    }
1877
}
1878