Completed
Push — master ( f2dfe9...84d91c )
by André
35:37 queued 16:15
created

Mapper::extractVersionInfoFromRow()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 35

Duplication

Lines 11
Ratio 31.43 %

Importance

Changes 0
Metric Value
cc 3
nc 4
nop 2
dl 11
loc 35
rs 9.36
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the Mapper 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
namespace eZ\Publish\Core\Persistence\Legacy\Content;
10
11
use eZ\Publish\Core\Base\Exceptions\NotFoundException;
12
use eZ\Publish\SPI\Persistence\Content;
13
use eZ\Publish\SPI\Persistence\Content\CreateStruct;
14
use eZ\Publish\SPI\Persistence\Content\Field;
15
use eZ\Publish\SPI\Persistence\Content\FieldValue;
16
use eZ\Publish\SPI\Persistence\Content\Relation;
17
use eZ\Publish\SPI\Persistence\Content\Relation\CreateStruct as RelationCreateStruct;
18
use eZ\Publish\Core\Persistence\Legacy\Content\FieldValue\ConverterRegistry as Registry;
19
use eZ\Publish\SPI\Persistence\Content\Language\Handler as LanguageHandler;
20
use eZ\Publish\SPI\Persistence\Content\ContentInfo;
21
use eZ\Publish\SPI\Persistence\Content\VersionInfo;
22
23
/**
24
 * Mapper for Content Handler.
25
 *
26
 * Performs mapping of Content objects.
27
 */
28
class Mapper
29
{
30
    /**
31
     * FieldValue converter registry.
32
     *
33
     * @var \eZ\Publish\Core\Persistence\Legacy\Content\FieldValue\ConverterRegistry
34
     */
35
    protected $converterRegistry;
36
37
    /**
38
     * Caching language handler.
39
     *
40
     * @var \eZ\Publish\SPI\Persistence\Content\Language\Handler
41
     */
42
    protected $languageHandler;
43
44
    /**
45
     * Creates a new mapper.
46
     *
47
     * @param \eZ\Publish\Core\Persistence\Legacy\Content\FieldValue\ConverterRegistry $converterRegistry
48
     * @param \eZ\Publish\SPI\Persistence\Content\Language\Handler $languageHandler
49
     */
50
    public function __construct(Registry $converterRegistry, LanguageHandler $languageHandler)
51
    {
52
        $this->converterRegistry = $converterRegistry;
53
        $this->languageHandler = $languageHandler;
54
    }
55
56
    /**
57
     * Creates a Content from the given $struct and $currentVersionNo.
58
     *
59
     * @param \eZ\Publish\SPI\Persistence\Content\CreateStruct $struct
60
     * @param mixed $currentVersionNo
61
     *
62
     * @return \eZ\Publish\SPI\Persistence\Content\ContentInfo
63
     */
64
    private function createContentInfoFromCreateStruct(CreateStruct $struct, $currentVersionNo = 1)
65
    {
66
        $contentInfo = new ContentInfo();
67
68
        $contentInfo->id = null;
69
        $contentInfo->contentTypeId = $struct->typeId;
70
        $contentInfo->sectionId = $struct->sectionId;
71
        $contentInfo->ownerId = $struct->ownerId;
72
        $contentInfo->alwaysAvailable = $struct->alwaysAvailable;
73
        $contentInfo->remoteId = $struct->remoteId;
74
        $contentInfo->mainLanguageCode = $this->languageHandler
75
            ->load(isset($struct->mainLanguageId) ? $struct->mainLanguageId : $struct->initialLanguageId)
76
            ->languageCode;
77
        $contentInfo->name = isset($struct->name[$contentInfo->mainLanguageCode])
78
            ? $struct->name[$contentInfo->mainLanguageCode]
79
            : '';
80
        // For drafts published and modified timestamps should be 0
81
        $contentInfo->publicationDate = 0;
82
        $contentInfo->modificationDate = 0;
83
        $contentInfo->currentVersionNo = $currentVersionNo;
84
        $contentInfo->status = ContentInfo::STATUS_DRAFT;
85
        $contentInfo->isPublished = false;
86
87
        return $contentInfo;
88
    }
89
90
    /**
91
     * Creates a new version for the given $struct and $versionNo.
92
     *
93
     * @param \eZ\Publish\SPI\Persistence\Content\CreateStruct $struct
94
     * @param mixed $versionNo
95
     *
96
     * @return \eZ\Publish\SPI\Persistence\Content\VersionInfo
97
     */
98
    public function createVersionInfoFromCreateStruct(CreateStruct $struct, $versionNo)
99
    {
100
        $versionInfo = new VersionInfo();
101
102
        $versionInfo->id = null;
103
        $versionInfo->contentInfo = $this->createContentInfoFromCreateStruct($struct, $versionNo);
104
        $versionInfo->versionNo = $versionNo;
105
        $versionInfo->creatorId = $struct->ownerId;
106
        $versionInfo->status = VersionInfo::STATUS_DRAFT;
107
        $versionInfo->initialLanguageCode = $this->languageHandler->load($struct->initialLanguageId)->languageCode;
108
        $versionInfo->creationDate = $struct->modified;
109
        $versionInfo->modificationDate = $struct->modified;
110
        $versionInfo->names = $struct->name;
111
112
        $languages = [];
113
        foreach ($struct->fields as $field) {
114
            if (!isset($languages[$field->languageCode])) {
115
                $languages[$field->languageCode] = true;
116
            }
117
        }
118
        $versionInfo->languageCodes = array_keys($languages);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_keys($languages) of type array<integer,integer|string> is incompatible with the declared type array<integer,string> of property $languageCodes.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
119
120
        return $versionInfo;
121
    }
122
123
    /**
124
     * Creates a new version for the given $content.
125
     *
126
     * @param \eZ\Publish\SPI\Persistence\Content $content
127
     * @param mixed $versionNo
128
     * @param mixed $userId
129
     *
130
     * @return \eZ\Publish\SPI\Persistence\Content\VersionInfo
131
     */
132
    public function createVersionInfoForContent(Content $content, $versionNo, $userId)
133
    {
134
        $versionInfo = new VersionInfo();
135
136
        $versionInfo->contentInfo = $content->versionInfo->contentInfo;
137
        $versionInfo->versionNo = $versionNo;
138
        $versionInfo->creatorId = $userId;
139
        $versionInfo->status = VersionInfo::STATUS_DRAFT;
140
        $versionInfo->initialLanguageCode = $content->versionInfo->initialLanguageCode;
141
        $versionInfo->creationDate = time();
142
        $versionInfo->modificationDate = $versionInfo->creationDate;
143
        $versionInfo->names = is_object($content->versionInfo) ? $content->versionInfo->names : array();
144
        $versionInfo->languageCodes = $content->versionInfo->languageCodes;
145
146
        return $versionInfo;
147
    }
148
149
    /**
150
     * Converts value of $field to storage value.
151
     *
152
     * @param \eZ\Publish\SPI\Persistence\Content\Field $field
153
     *
154
     * @return \eZ\Publish\Core\Persistence\Legacy\Content\StorageFieldValue
155
     */
156
    public function convertToStorageValue(Field $field)
157
    {
158
        $converter = $this->converterRegistry->getConverter(
159
            $field->type
160
        );
161
        $storageValue = new StorageFieldValue();
162
        $converter->toStorageValue(
163
            $field->value,
164
            $storageValue
165
        );
166
167
        return $storageValue;
168
    }
169
170
    /**
171
     * Extracts Content objects (and nested) from database result $rows.
172
     *
173
     * Expects database rows to be indexed by keys of the format
174
     *
175
     *      "$tableName_$columnName"
176
     *
177
     * @param array $rows
178
     * @param array $nameRows
179
     *
180
     * @return \eZ\Publish\SPI\Persistence\Content[]
181
     */
182
    public function extractContentFromRows(array $rows, array $nameRows, $prefix = 'ezcontentobject_')
183
    {
184
        $versionedNameData = array();
185
        foreach ($nameRows as $row) {
186
            $contentId = (int)$row['ezcontentobject_name_contentobject_id'];
187
            $versionNo = (int)$row['ezcontentobject_name_content_version'];
188
            $versionedNameData[$contentId][$versionNo][$row['ezcontentobject_name_content_translation']] = $row['ezcontentobject_name_name'];
189
        }
190
191
        $contentInfos = array();
192
        $versionInfos = array();
193
        $fields = array();
194
195
        foreach ($rows as $row) {
196
            $contentId = (int)$row["{$prefix}id"];
197
            if (!isset($contentInfos[$contentId])) {
198
                $contentInfos[$contentId] = $this->extractContentInfoFromRow($row, $prefix);
199
            }
200
            if (!isset($versionInfos[$contentId])) {
201
                $versionInfos[$contentId] = array();
202
            }
203
204
            $versionId = (int)$row['ezcontentobject_version_id'];
205
            if (!isset($versionInfos[$contentId][$versionId])) {
206
                $versionInfos[$contentId][$versionId] = $this->extractVersionInfoFromRow($row);
207
            }
208
209
            $fieldId = (int)$row['ezcontentobject_attribute_id'];
210 View Code Duplication
            if (!isset($fields[$contentId][$versionId][$fieldId])) {
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...
211
                $fields[$contentId][$versionId][$fieldId] = $this->extractFieldFromRow($row);
212
            }
213
        }
214
215
        $results = array();
216
        foreach ($contentInfos as $contentId => $contentInfo) {
217
            foreach ($versionInfos[$contentId] as $versionId => $versionInfo) {
218
                // Fallback to just main language name if versioned name data is missing
219 View Code Duplication
                if (isset($versionedNameData[$contentId][$versionInfo->versionNo])) {
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...
220
                    $names = $versionedNameData[$contentId][$versionInfo->versionNo];
221
                } else {
222
                    $names = [$contentInfo->mainLanguageCode => $contentInfo->name];
223
                }
224
225
                $content = new Content();
226
                $content->versionInfo = $versionInfo;
227
                $content->versionInfo->names = $names;
228
                $content->versionInfo->contentInfo = $contentInfo;
229
                $content->fields = array_values($fields[$contentId][$versionId]);
230
                $results[] = $content;
231
            }
232
        }
233
234
        return $results;
235
    }
236
237
    /**
238
     * Extracts a ContentInfo object from $row.
239
     *
240
     * @param array $row
241
     * @param string $prefix Prefix for row keys, which are initially mapped by ezcontentobject fields
242
     * @param string $treePrefix Prefix for tree row key, which are initially mapped by ezcontentobject_tree_ fields
243
     *
244
     * @return \eZ\Publish\SPI\Persistence\Content\ContentInfo
245
     */
246
    public function extractContentInfoFromRow(array $row, $prefix = '', $treePrefix = 'ezcontentobject_tree_')
247
    {
248
        $contentInfo = new ContentInfo();
249
        $contentInfo->id = (int)$row["{$prefix}id"];
250
        $contentInfo->name = $row["{$prefix}name"];
251
        $contentInfo->contentTypeId = (int)$row["{$prefix}contentclass_id"];
252
        $contentInfo->sectionId = (int)$row["{$prefix}section_id"];
253
        $contentInfo->currentVersionNo = (int)$row["{$prefix}current_version"];
254
        $contentInfo->isPublished = ($row["{$prefix}status"] == ContentInfo::STATUS_PUBLISHED);
255
        $contentInfo->ownerId = (int)$row["{$prefix}owner_id"];
256
        $contentInfo->publicationDate = (int)$row["{$prefix}published"];
257
        $contentInfo->modificationDate = (int)$row["{$prefix}modified"];
258
        $contentInfo->alwaysAvailable = (int)$row["{$prefix}language_mask"] & 1;
0 ignored issues
show
Documentation Bug introduced by
The property $alwaysAvailable was declared of type boolean, but (int) $row["{$prefix}language_mask"] & 1 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
259
        $contentInfo->mainLanguageCode = $this->languageHandler->load($row["{$prefix}initial_language_id"])->languageCode;
260
        $contentInfo->remoteId = $row["{$prefix}remote_id"];
261
        $contentInfo->mainLocationId = ($row["{$treePrefix}main_node_id"] !== null ? (int)$row["{$treePrefix}main_node_id"] : null);
262
        $contentInfo->status = (int)$row["{$prefix}status"];
263
        $contentInfo->isPublished = ($contentInfo->status == ContentInfo::STATUS_PUBLISHED);
264
265
        return $contentInfo;
266
    }
267
268
    /**
269
     * Extracts ContentInfo objects from $rows.
270
     *
271
     * @param array $rows
272
     * @param string $prefix Prefix for row keys, which are initially mapped by ezcontentobject fields
273
     * @param string $treePrefix Prefix for tree row key, which are initially mapped by ezcontentobject_tree_ fields
274
     *
275
     * @return \eZ\Publish\SPI\Persistence\Content\ContentInfo[]
276
     */
277
    public function extractContentInfoFromRows(array $rows, $prefix = '', $treePrefix = 'ezcontentobject_tree_')
278
    {
279
        $contentInfoObjects = array();
280
        foreach ($rows as $row) {
281
            $contentInfoObjects[] = $this->extractContentInfoFromRow($row, $prefix, $treePrefix);
282
        }
283
284
        return $contentInfoObjects;
285
    }
286
287
    /**
288
     * Extracts a VersionInfo object from $row.
289
     *
290
     * This method will return VersionInfo with incomplete data. It is intended to be used only by
291
     * {@link self::extractContentFromRows} where missing data will be filled in.
292
     *
293
     * @param array $row
294
     * @param array $names
295
     *
296
     * @return \eZ\Publish\SPI\Persistence\Content\VersionInfo
297
     */
298
    private function extractVersionInfoFromRow(array $row, array $names = array())
299
    {
300
        $versionInfo = new VersionInfo();
301
        $versionInfo->id = (int)$row['ezcontentobject_version_id'];
302
        $versionInfo->contentInfo = null;
303
        $versionInfo->versionNo = (int)$row['ezcontentobject_version_version'];
304
        $versionInfo->creatorId = (int)$row['ezcontentobject_version_creator_id'];
305
        $versionInfo->creationDate = (int)$row['ezcontentobject_version_created'];
306
        $versionInfo->modificationDate = (int)$row['ezcontentobject_version_modified'];
307
        $versionInfo->status = (int)$row['ezcontentobject_version_status'];
308
        $versionInfo->names = $names;
309
310
        // Map language codes
311
        $allLanguages = $this->loadAllLanguagesWithIdKey();
312
        $versionInfo->languageCodes = $this->extractLanguageCodesFromMask(
313
            (int)$row['ezcontentobject_version_language_mask'],
314
            $allLanguages,
315
            $missing
316
        );
317
        $initialLanguageId = (int)$row['ezcontentobject_version_initial_language_id'];
318 View Code Duplication
        if (isset($allLanguages[$initialLanguageId])) {
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...
319
            $versionInfo->initialLanguageCode = $allLanguages[$initialLanguageId]->languageCode;
320
        } else {
321
            $missing[] = $initialLanguageId;
322
        }
323
324 View Code Duplication
        if (!empty($missing)) {
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...
325
            throw new NotFoundException(
326
                'Language',
327
                implode(', ', $missing) . "' when building content '" . $row['ezcontentobject_id']
328
            );
329
        }
330
331
        return $versionInfo;
332
    }
333
334
    /**
335
     * Extracts a VersionInfo object from $row.
336
     *
337
     * @param array $rows
338
     * @param array $nameRows
339
     *
340
     * @return \eZ\Publish\SPI\Persistence\Content\VersionInfo[]
341
     */
342
    public function extractVersionInfoListFromRows(array $rows, array $nameRows)
343
    {
344
        $nameData = array();
345
        foreach ($nameRows as $row) {
346
            $versionId = $row['ezcontentobject_name_contentobject_id'] . '_' . $row['ezcontentobject_name_content_version'];
347
            $nameData[$versionId][$row['ezcontentobject_name_content_translation']] = $row['ezcontentobject_name_name'];
348
        }
349
350
        $allLanguages = $this->loadAllLanguagesWithIdKey();
351
        $versionInfoList = array();
352
        foreach ($rows as $row) {
353
            $versionId = $row['ezcontentobject_id'] . '_' . $row['ezcontentobject_version_version'];
354
            if (!isset($versionInfoList[$versionId])) {
355
                $versionInfo = new VersionInfo();
356
                $versionInfo->id = (int)$row['ezcontentobject_version_id'];
357
                $versionInfo->contentInfo = $this->extractContentInfoFromRow($row, 'ezcontentobject_');
358
                $versionInfo->versionNo = (int)$row['ezcontentobject_version_version'];
359
                $versionInfo->creatorId = (int)$row['ezcontentobject_version_creator_id'];
360
                $versionInfo->creationDate = (int)$row['ezcontentobject_version_created'];
361
                $versionInfo->modificationDate = (int)$row['ezcontentobject_version_modified'];
362
                $versionInfo->status = (int)$row['ezcontentobject_version_status'];
363
                $versionInfo->names = $nameData[$versionId];
364
                $versionInfoList[$versionId] = $versionInfo;
365
                $versionInfo->languageCodes = $this->extractLanguageCodesFromMask(
366
                    (int)$row['ezcontentobject_version_language_mask'],
367
                    $allLanguages,
368
                    $missing
369
                );
370
                $initialLanguageId = (int)$row['ezcontentobject_version_initial_language_id'];
371 View Code Duplication
                if (isset($allLanguages[$initialLanguageId])) {
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...
372
                    $versionInfo->initialLanguageCode = $allLanguages[$initialLanguageId]->languageCode;
373
                } else {
374
                    $missing[] = $initialLanguageId;
375
                }
376
377 View Code Duplication
                if (!empty($missing)) {
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...
378
                    throw new NotFoundException(
379
                        'Language',
380
                        implode(', ', $missing) . "' when building content '" . $row['ezcontentobject_id']
381
                    );
382
                }
383
            }
384
        }
385
386
        return array_values($versionInfoList);
387
    }
388
389
    /**
390
     * @param int $languageMask
391
     * @param \eZ\Publish\SPI\Persistence\Content\Language[] $allLanguages
392
     * @param int[] &$missing
393
     *
394
     * @return string[]
395
     */
396
    private function extractLanguageCodesFromMask(int $languageMask, array $allLanguages, &$missing = [])
397
    {
398
        $exp = 2;
399
        $result = [];
400
401
        // Decomposition of $languageMask into its binary components to extract language codes
402
        while ($exp <= $languageMask) {
403
            if ($languageMask & $exp) {
404
                if (isset($allLanguages[$exp])) {
405
                    $result[] = $allLanguages[$exp]->languageCode;
406
                } else {
407
                    $missing[] = $exp;
408
                }
409
            }
410
411
            $exp *= 2;
412
        }
413
414
        return $result;
415
    }
416
417
    /**
418
     * @return \eZ\Publish\SPI\Persistence\Content\Language[]
419
     */
420
    private function loadAllLanguagesWithIdKey()
421
    {
422
        $languagesById = [];
423
        foreach ($this->languageHandler->loadAll() as $language) {
424
            $languagesById[$language->id] = $language;
425
        }
426
427
        return $languagesById;
428
    }
429
430
    /**
431
     * Extracts a Field from $row.
432
     *
433
     * @param array $row
434
     *
435
     * @return Field
436
     */
437
    protected function extractFieldFromRow(array $row)
438
    {
439
        $field = new Field();
440
441
        $field->id = (int)$row['ezcontentobject_attribute_id'];
442
        $field->fieldDefinitionId = (int)$row['ezcontentobject_attribute_contentclassattribute_id'];
443
        $field->type = $row['ezcontentobject_attribute_data_type_string'];
444
        $field->value = $this->extractFieldValueFromRow($row, $field->type);
445
        $field->languageCode = $row['ezcontentobject_attribute_language_code'];
446
        $field->versionNo = isset($row['ezcontentobject_version_version']) ?
447
            (int)$row['ezcontentobject_version_version'] :
448
            (int)$row['ezcontentobject_attribute_version'];
449
450
        return $field;
451
    }
452
453
    /**
454
     * Extracts a FieldValue of $type from $row.
455
     *
456
     * @param array $row
457
     * @param string $type
458
     *
459
     * @return \eZ\Publish\SPI\Persistence\Content\FieldValue
460
     *
461
     * @throws \eZ\Publish\Core\Persistence\Legacy\Content\FieldValue\Converter\Exception\NotFound
462
     *         if the necessary converter for $type could not be found.
463
     */
464
    protected function extractFieldValueFromRow(array $row, $type)
465
    {
466
        $storageValue = new StorageFieldValue();
467
468
        // Nullable field
469
        $storageValue->dataFloat = isset($row['ezcontentobject_attribute_data_float'])
470
            ? (float)$row['ezcontentobject_attribute_data_float']
471
            : null;
472
        // Nullable field
473
        $storageValue->dataInt = isset($row['ezcontentobject_attribute_data_int'])
474
            ? (int)$row['ezcontentobject_attribute_data_int']
475
            : null;
476
        $storageValue->dataText = $row['ezcontentobject_attribute_data_text'];
477
        // Not nullable field
478
        $storageValue->sortKeyInt = (int)$row['ezcontentobject_attribute_sort_key_int'];
479
        $storageValue->sortKeyString = $row['ezcontentobject_attribute_sort_key_string'];
480
481
        $fieldValue = new FieldValue();
482
483
        $converter = $this->converterRegistry->getConverter($type);
484
        $converter->toFieldValue($storageValue, $fieldValue);
485
486
        return $fieldValue;
487
    }
488
489
    /**
490
     * Creates CreateStruct from $content.
491
     *
492
     * @param \eZ\Publish\SPI\Persistence\Content $content
493
     *
494
     * @return \eZ\Publish\SPI\Persistence\Content\CreateStruct
495
     */
496
    public function createCreateStructFromContent(Content $content)
497
    {
498
        $struct = new CreateStruct();
499
        $struct->name = $content->versionInfo->names;
500
        $struct->typeId = $content->versionInfo->contentInfo->contentTypeId;
501
        $struct->sectionId = $content->versionInfo->contentInfo->sectionId;
502
        $struct->ownerId = $content->versionInfo->contentInfo->ownerId;
503
        $struct->locations = array();
504
        $struct->alwaysAvailable = $content->versionInfo->contentInfo->alwaysAvailable;
505
        $struct->remoteId = md5(uniqid(get_class($this), true));
506
        $struct->initialLanguageId = $this->languageHandler->loadByLanguageCode($content->versionInfo->initialLanguageCode)->id;
507
        $struct->mainLanguageId = $this->languageHandler->loadByLanguageCode($content->versionInfo->contentInfo->mainLanguageCode)->id;
508
        $struct->modified = time();
509
510
        foreach ($content->fields as $field) {
511
            $newField = clone $field;
512
            $newField->id = null;
513
            $struct->fields[] = $newField;
514
        }
515
516
        return $struct;
517
    }
518
519
    /**
520
     * Extracts relation objects from $rows.
521
     */
522
    public function extractRelationsFromRows(array $rows)
523
    {
524
        $relations = array();
525
526
        foreach ($rows as $row) {
527
            $id = (int)$row['ezcontentobject_link_id'];
528
            if (!isset($relations[$id])) {
529
                $relations[$id] = $this->extractRelationFromRow($row);
530
            }
531
        }
532
533
        return $relations;
534
    }
535
536
    /**
537
     * Extracts a Relation object from a $row.
538
     *
539
     * @param array $row Associative array representing a relation
540
     *
541
     * @return \eZ\Publish\SPI\Persistence\Content\Relation
542
     */
543
    protected function extractRelationFromRow(array $row)
544
    {
545
        $relation = new Relation();
546
        $relation->id = (int)$row['ezcontentobject_link_id'];
547
        $relation->sourceContentId = (int)$row['ezcontentobject_link_from_contentobject_id'];
548
        $relation->sourceContentVersionNo = (int)$row['ezcontentobject_link_from_contentobject_version'];
549
        $relation->destinationContentId = (int)$row['ezcontentobject_link_to_contentobject_id'];
550
        $relation->type = (int)$row['ezcontentobject_link_relation_type'];
551
552
        $contentClassAttributeId = (int)$row['ezcontentobject_link_contentclassattribute_id'];
553
        if ($contentClassAttributeId > 0) {
554
            $relation->sourceFieldDefinitionId = $contentClassAttributeId;
555
        }
556
557
        return $relation;
558
    }
559
560
    /**
561
     * Creates a Content from the given $struct.
562
     *
563
     * @param \eZ\Publish\SPI\Persistence\Content\Relation\CreateStruct $struct
564
     *
565
     * @return \eZ\Publish\SPI\Persistence\Content\Relation
566
     */
567
    public function createRelationFromCreateStruct(RelationCreateStruct $struct)
568
    {
569
        $relation = new Relation();
570
571
        $relation->destinationContentId = $struct->destinationContentId;
572
        $relation->sourceContentId = $struct->sourceContentId;
573
        $relation->sourceContentVersionNo = $struct->sourceContentVersionNo;
574
        $relation->sourceFieldDefinitionId = $struct->sourceFieldDefinitionId;
575
        $relation->type = $struct->type;
576
577
        return $relation;
578
    }
579
}
580