Completed
Push — master ( 22e8a3...5822db )
by André
23:39
created

DomainMapper::buildContentDomainObject()   B

Complexity

Conditions 6
Paths 16

Size

Total Lines 28
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 17
nc 16
nop 4
dl 0
loc 28
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the DomainMapper 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\Repository\Helper;
10
11
use eZ\Publish\API\Repository\Values\Content\Search\SearchResult;
12
use eZ\Publish\SPI\Persistence\Content\Handler as ContentHandler;
13
use eZ\Publish\SPI\Persistence\Content\Location\Handler as LocationHandler;
14
use eZ\Publish\SPI\Persistence\Content\Language\Handler as LanguageHandler;
15
use eZ\Publish\SPI\Persistence\Content\Type\Handler as TypeHandler;
16
use eZ\Publish\Core\Repository\Values\Content\Content;
17
use eZ\Publish\API\Repository\Values\Content\VersionInfo as APIVersionInfo;
18
use eZ\Publish\Core\Repository\Values\Content\VersionInfo;
19
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
20
use eZ\Publish\API\Repository\Values\ContentType\ContentType;
21
use eZ\Publish\API\Repository\Values\Content\Field;
22
use eZ\Publish\Core\Repository\Values\Content\Relation;
23
use eZ\Publish\API\Repository\Values\Content\Location as APILocation;
24
use eZ\Publish\Core\Repository\Values\Content\Location;
25
use eZ\Publish\SPI\Persistence\Content as SPIContent;
26
use eZ\Publish\SPI\Persistence\Content\Location as SPILocation;
27
use eZ\Publish\SPI\Persistence\Content\VersionInfo as SPIVersionInfo;
28
use eZ\Publish\SPI\Persistence\Content\ContentInfo as SPIContentInfo;
29
use eZ\Publish\SPI\Persistence\Content\Relation as SPIRelation;
30
use eZ\Publish\SPI\Persistence\Content\Type as SPIType;
31
use eZ\Publish\SPI\Persistence\Content\Location\CreateStruct as SPILocationCreateStruct;
32
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
33
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException;
34
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentValue;
35
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentType;
36
use DateTime;
37
38
/**
39
 * DomainMapper is an internal service.
40
 *
41
 * @internal Meant for internal use by Repository.
42
 */
43
class DomainMapper
44
{
45
    const MAX_LOCATION_PRIORITY = 2147483647;
46
    const MIN_LOCATION_PRIORITY = -2147483648;
47
48
    /**
49
     * @var \eZ\Publish\SPI\Persistence\Content\Handler
50
     */
51
    protected $contentHandler;
52
53
    /**
54
     * @var \eZ\Publish\SPI\Persistence\Content\Location\Handler
55
     */
56
    protected $locationHandler;
57
58
    /**
59
     * @var \eZ\Publish\SPI\Persistence\Content\Type\Handler
60
     */
61
    protected $contentTypeHandler;
62
63
    /**
64
     * @var \eZ\Publish\SPI\Persistence\Content\Language\Handler
65
     */
66
    protected $contentLanguageHandler;
67
68
    /**
69
     * @var FieldTypeRegistry
70
     */
71
    protected $fieldTypeRegistry;
72
73
    /**
74
     * Setups service with reference to repository.
75
     *
76
     * @param \eZ\Publish\SPI\Persistence\Content\Handler $contentHandler
77
     * @param \eZ\Publish\SPI\Persistence\Content\Location\Handler $locationHandler
78
     * @param \eZ\Publish\SPI\Persistence\Content\Type\Handler $contentTypeHandler
79
     * @param \eZ\Publish\SPI\Persistence\Content\Language\Handler $contentLanguageHandler
80
     * @param FieldTypeRegistry $fieldTypeRegistry
81
     */
82
    public function __construct(
83
        ContentHandler $contentHandler,
84
        LocationHandler $locationHandler,
85
        TypeHandler $contentTypeHandler,
86
        LanguageHandler $contentLanguageHandler,
87
        FieldTypeRegistry $fieldTypeRegistry
88
    ) {
89
        $this->contentHandler = $contentHandler;
90
        $this->locationHandler = $locationHandler;
91
        $this->contentTypeHandler = $contentTypeHandler;
92
        $this->contentLanguageHandler = $contentLanguageHandler;
93
        $this->fieldTypeRegistry = $fieldTypeRegistry;
94
    }
95
96
    /**
97
     * Builds a Content domain object from value object returned from persistence.
98
     *
99
     * @param \eZ\Publish\SPI\Persistence\Content $spiContent
100
     * @param ContentType|SPIType $contentType
101
     * @param array|null $fieldLanguages Language codes to filter fields on
102
     * @param string|null $fieldAlwaysAvailableLanguage Language code fallback if a given field is not found in $fieldLanguages
103
     *
104
     * @return \eZ\Publish\Core\Repository\Values\Content\Content
105
     */
106
    public function buildContentDomainObject(SPIContent $spiContent, $contentType = null, array $fieldLanguages = null, $fieldAlwaysAvailableLanguage = null)
107
    {
108
        if ($contentType === null) {
109
            $contentType = $this->contentTypeHandler->load(
110
                $spiContent->versionInfo->contentInfo->contentTypeId
111
            );
112
        }
113
114
        $prioritizedFieldLanguageCode = null;
115
        $prioritizedLanguages = $fieldLanguages ?: [];
116
        if (!empty($prioritizedLanguages)) {
117
            $availableFieldLanguageMap = array_fill_keys($spiContent->versionInfo->languageCodes, true);
118
            foreach ($prioritizedLanguages as $prioritizedLanguage) {
119
                if (isset($availableFieldLanguageMap[$prioritizedLanguage])) {
120
                    $prioritizedFieldLanguageCode = $prioritizedLanguage;
121
                    break;
122
                }
123
            }
124
        }
125
126
        return new Content(
127
            array(
128
                'internalFields' => $this->buildDomainFields($spiContent->fields, $contentType, $fieldLanguages, $fieldAlwaysAvailableLanguage),
129
                'versionInfo' => $this->buildVersionInfoDomainObject($spiContent->versionInfo, $prioritizedLanguages),
130
                'prioritizedFieldLanguageCode' => $prioritizedFieldLanguageCode,
131
            )
132
        );
133
    }
134
135
    /**
136
     * Returns an array of domain fields created from given array of SPI fields.
137
     *
138
     * @throws InvalidArgumentType On invalid $contentType
139
     *
140
     * @param \eZ\Publish\SPI\Persistence\Content\Field[] $spiFields
141
     * @param ContentType|SPIType $contentType
142
     * @param array $languages A language priority, filters returned fields and is used as prioritized language code on
143
     *                         returned value object. If not given all languages are returned.
144
     * @param string|null $alwaysAvailableLanguage Language code fallback if a given field is not found in $languages
145
     *
146
     * @return array
147
     */
148
    public function buildDomainFields(array $spiFields, $contentType, array $languages = null, $alwaysAvailableLanguage = null)
149
    {
150
        if (!$contentType instanceof SPIType && !$contentType instanceof ContentType) {
151
            throw new InvalidArgumentType('$contentType', 'SPI ContentType | API ContentType');
152
        }
153
154
        $fieldIdentifierMap = array();
155
        foreach ($contentType->fieldDefinitions as $fieldDefinitions) {
156
            $fieldIdentifierMap[$fieldDefinitions->id] = $fieldDefinitions->identifier;
157
        }
158
159
        $fieldInFilterLanguagesMap = array();
160
        if ($languages !== null && $alwaysAvailableLanguage !== null) {
161
            foreach ($spiFields as $spiField) {
162
                if (in_array($spiField->languageCode, $languages)) {
163
                    $fieldInFilterLanguagesMap[$spiField->fieldDefinitionId] = true;
164
                }
165
            }
166
        }
167
168
        $fields = array();
169
        foreach ($spiFields as $spiField) {
170
            // We ignore fields in content not part of the content type
171
            if (!isset($fieldIdentifierMap[$spiField->fieldDefinitionId])) {
172
                continue;
173
            }
174
175
            if ($languages !== null && !in_array($spiField->languageCode, $languages)) {
176
                // If filtering is enabled we ignore fields in other languages then $fieldLanguages, if:
177
                if ($alwaysAvailableLanguage === null) {
178
                    // Ignore field if we don't have $alwaysAvailableLanguageCode fallback
179
                    continue;
180
                } elseif (!empty($fieldInFilterLanguagesMap[$spiField->fieldDefinitionId])) {
181
                    // Ignore field if it exists in one of the filtered languages
182
                    continue;
183
                } elseif ($spiField->languageCode !== $alwaysAvailableLanguage) {
184
                    // Also ignore if field is not in $alwaysAvailableLanguageCode
185
                    continue;
186
                }
187
            }
188
189
            $fields[] = new Field(
190
                array(
191
                    'id' => $spiField->id,
192
                    'value' => $this->fieldTypeRegistry->getFieldType($spiField->type)
193
                        ->fromPersistenceValue($spiField->value),
194
                    'languageCode' => $spiField->languageCode,
195
                    'fieldDefIdentifier' => $fieldIdentifierMap[$spiField->fieldDefinitionId],
196
                    'fieldTypeIdentifier' => $spiField->type,
197
                )
198
            );
199
        }
200
201
        return $fields;
202
    }
203
204
    /**
205
     * Builds a VersionInfo domain object from value object returned from persistence.
206
     *
207
     * @param \eZ\Publish\SPI\Persistence\Content\VersionInfo $spiVersionInfo
208
     * @param array $prioritizedLanguages
209
     *
210
     * @return \eZ\Publish\Core\Repository\Values\Content\VersionInfo
211
     */
212
    public function buildVersionInfoDomainObject(SPIVersionInfo $spiVersionInfo, array $prioritizedLanguages = [])
213
    {
214
        // Map SPI statuses to API
215
        switch ($spiVersionInfo->status) {
216
            case SPIVersionInfo::STATUS_ARCHIVED:
217
                $status = APIVersionInfo::STATUS_ARCHIVED;
218
                break;
219
220
            case SPIVersionInfo::STATUS_PUBLISHED:
221
                $status = APIVersionInfo::STATUS_PUBLISHED;
222
                break;
223
224
            case SPIVersionInfo::STATUS_DRAFT:
225
            default:
226
                $status = APIVersionInfo::STATUS_DRAFT;
227
        }
228
229
        // Find prioritised language among names
230
        $prioritizedNameLanguageCode = null;
231
        foreach ($prioritizedLanguages as $prioritizedLanguage) {
232
            if (isset($spiVersionInfo->names[$prioritizedLanguage])) {
233
                $prioritizedNameLanguageCode = $prioritizedLanguage;
234
                break;
235
            }
236
        }
237
238
        return new VersionInfo(
239
            array(
240
                'id' => $spiVersionInfo->id,
241
                'versionNo' => $spiVersionInfo->versionNo,
242
                'modificationDate' => $this->getDateTime($spiVersionInfo->modificationDate),
243
                'creatorId' => $spiVersionInfo->creatorId,
244
                'creationDate' => $this->getDateTime($spiVersionInfo->creationDate),
245
                'status' => $status,
246
                'initialLanguageCode' => $spiVersionInfo->initialLanguageCode,
247
                'languageCodes' => $spiVersionInfo->languageCodes,
248
                'names' => $spiVersionInfo->names,
249
                'contentInfo' => $this->buildContentInfoDomainObject($spiVersionInfo->contentInfo),
250
                'prioritizedNameLanguageCode' => $prioritizedNameLanguageCode,
251
            )
252
        );
253
    }
254
255
    /**
256
     * Builds a ContentInfo domain object from value object returned from persistence.
257
     *
258
     * @param \eZ\Publish\SPI\Persistence\Content\ContentInfo $spiContentInfo
259
     *
260
     * @return \eZ\Publish\API\Repository\Values\Content\ContentInfo
261
     */
262
    public function buildContentInfoDomainObject(SPIContentInfo $spiContentInfo)
263
    {
264
        return new ContentInfo(
265
            array(
266
                'id' => $spiContentInfo->id,
267
                'contentTypeId' => $spiContentInfo->contentTypeId,
268
                'name' => $spiContentInfo->name,
269
                'sectionId' => $spiContentInfo->sectionId,
270
                'currentVersionNo' => $spiContentInfo->currentVersionNo,
271
                'published' => $spiContentInfo->isPublished,
272
                'ownerId' => $spiContentInfo->ownerId,
273
                'modificationDate' => $spiContentInfo->modificationDate == 0 ?
274
                    null :
275
                    $this->getDateTime($spiContentInfo->modificationDate),
276
                'publishedDate' => $spiContentInfo->publicationDate == 0 ?
277
                    null :
278
                    $this->getDateTime($spiContentInfo->publicationDate),
279
                'alwaysAvailable' => $spiContentInfo->alwaysAvailable,
280
                'remoteId' => $spiContentInfo->remoteId,
281
                'mainLanguageCode' => $spiContentInfo->mainLanguageCode,
282
                'mainLocationId' => $spiContentInfo->mainLocationId,
283
            )
284
        );
285
    }
286
287
    /**
288
     * Builds API Relation object from provided SPI Relation object.
289
     *
290
     * @param \eZ\Publish\SPI\Persistence\Content\Relation $spiRelation
291
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $sourceContentInfo
292
     * @param \eZ\Publish\API\Repository\Values\Content\ContentInfo $destinationContentInfo
293
     *
294
     * @return \eZ\Publish\API\Repository\Values\Content\Relation
295
     */
296
    public function buildRelationDomainObject(
297
        SPIRelation $spiRelation,
298
        ContentInfo $sourceContentInfo,
299
        ContentInfo $destinationContentInfo
300
    ) {
301
        $sourceFieldDefinitionIdentifier = null;
302
        if ($spiRelation->sourceFieldDefinitionId !== null) {
303
            $contentType = $this->contentTypeHandler->load($sourceContentInfo->contentTypeId);
304
            foreach ($contentType->fieldDefinitions as $fieldDefinition) {
305
                if ($fieldDefinition->id !== $spiRelation->sourceFieldDefinitionId) {
306
                    continue;
307
                }
308
309
                $sourceFieldDefinitionIdentifier = $fieldDefinition->identifier;
310
                break;
311
            }
312
        }
313
314
        return new Relation(
315
            array(
316
                'id' => $spiRelation->id,
317
                'sourceFieldDefinitionIdentifier' => $sourceFieldDefinitionIdentifier,
318
                'type' => $spiRelation->type,
319
                'sourceContentInfo' => $sourceContentInfo,
320
                'destinationContentInfo' => $destinationContentInfo,
321
            )
322
        );
323
    }
324
325
    /**
326
     * Builds domain location object from provided persistence location.
327
     *
328
     * @param \eZ\Publish\SPI\Persistence\Content\Location $spiLocation
329
     * @param \eZ\Publish\SPI\Persistence\Content\ContentInfo|null $contentInfo
330
     *
331
     * @return \eZ\Publish\API\Repository\Values\Content\Location
332
     */
333
    public function buildLocationDomainObject(SPILocation $spiLocation, SPIContentInfo $contentInfo = null)
334
    {
335
        // TODO: this is hardcoded workaround for missing ContentInfo on root location
336
        if ($spiLocation->id == 1) {
337
            $legacyDateTime = $this->getDateTime(1030968000); //  first known commit of eZ Publish 3.x
338
            $contentInfo = new ContentInfo(
339
                array(
340
                    'id' => 0,
341
                    'name' => 'Top Level Nodes',
342
                    'sectionId' => 1,
343
                    'mainLocationId' => 1,
344
                    'contentTypeId' => 1,
345
                    'currentVersionNo' => 1,
346
                    'published' => 1,
347
                    'ownerId' => 14, // admin user
348
                    'modificationDate' => $legacyDateTime,
349
                    'publishedDate' => $legacyDateTime,
350
                    'alwaysAvailable' => 1,
351
                    'remoteId' => null,
352
                    'mainLanguageCode' => 'eng-GB',
353
                )
354
            );
355
        } else {
356
            $contentInfo = $this->buildContentInfoDomainObject(
357
                $contentInfo ?: $this->contentHandler->loadContentInfo($spiLocation->contentId)
358
            );
359
        }
360
361
        return new Location(
362
            array(
363
                'contentInfo' => $contentInfo,
364
                'id' => $spiLocation->id,
365
                'priority' => $spiLocation->priority,
366
                'hidden' => $spiLocation->hidden,
367
                'invisible' => $spiLocation->invisible,
368
                'remoteId' => $spiLocation->remoteId,
369
                'parentLocationId' => $spiLocation->parentId,
370
                'pathString' => $spiLocation->pathString,
371
                'depth' => $spiLocation->depth,
372
                'sortField' => $spiLocation->sortField,
373
                'sortOrder' => $spiLocation->sortOrder,
374
            )
375
        );
376
    }
377
378
    /**
379
     * Build API Location and corresponding ContentInfo domain objects and apply to LocationSearchResult.
380
     *
381
     * Loading of ContentInfo objects are done in one operation.
382
     *
383
     * @param \eZ\Publish\API\Repository\Values\Content\Search\SearchResult $result SPI search result with SPI Location items as hits
384
     *
385
     * @return \eZ\Publish\SPI\Persistence\Content\Location[] Locations we did not find content info for is retunred as an array.
386
     */
387
    public function buildLocationDomainObjectsOnSearchResult(SearchResult $result)
388
    {
389
        $contentIds = [];
390
        foreach ($result->searchHits as $hit) {
391
            $contentIds[] = $hit->valueObject->contentId;
0 ignored issues
show
Documentation introduced by
The property contentId does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
392
        }
393
394
        $missingLocations = [];
395
        $contentInfoList = $this->contentHandler->loadContentInfoList($contentIds);
396
        foreach ($result->searchHits as $key => $hit) {
397
            if (isset($contentInfoList[$hit->valueObject->contentId])) {
0 ignored issues
show
Documentation introduced by
The property contentId does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
398
                $hit->valueObject = $this->buildLocationDomainObject(
399
                    $hit->valueObject,
0 ignored issues
show
Compatibility introduced by
$hit->valueObject of type object<eZ\Publish\API\Re...ory\Values\ValueObject> is not a sub-type of object<eZ\Publish\SPI\Pe...tence\Content\Location>. It seems like you assume a child class of the class eZ\Publish\API\Repository\Values\ValueObject to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
400
                    $contentInfoList[$hit->valueObject->contentId]
0 ignored issues
show
Documentation introduced by
The property contentId does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
401
                );
402
            } else {
403
                $missingLocations[] = $hit->valueObject;
404
                unset($result->searchHits[$key]);
405
                --$result->totalCount;
406
            }
407
        }
408
409
        return $missingLocations;
410
    }
411
412
    /**
413
     * Creates an array of SPI location create structs from given array of API location create structs.
414
     *
415
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
416
     *
417
     * @param \eZ\Publish\API\Repository\Values\Content\LocationCreateStruct $locationCreateStruct
418
     * @param \eZ\Publish\API\Repository\Values\Content\Location $parentLocation
419
     * @param mixed $mainLocation
420
     * @param mixed $contentId
421
     * @param mixed $contentVersionNo
422
     *
423
     * @return \eZ\Publish\SPI\Persistence\Content\Location\CreateStruct
424
     */
425
    public function buildSPILocationCreateStruct(
426
        $locationCreateStruct,
427
        APILocation $parentLocation,
428
        $mainLocation,
429
        $contentId,
430
        $contentVersionNo
431
    ) {
432
        if (!$this->isValidLocationPriority($locationCreateStruct->priority)) {
433
            throw new InvalidArgumentValue('priority', $locationCreateStruct->priority, 'LocationCreateStruct');
434
        }
435
436
        if (!is_bool($locationCreateStruct->hidden)) {
437
            throw new InvalidArgumentValue('hidden', $locationCreateStruct->hidden, 'LocationCreateStruct');
438
        }
439
440
        if ($locationCreateStruct->remoteId !== null && (!is_string($locationCreateStruct->remoteId) || empty($locationCreateStruct->remoteId))) {
441
            throw new InvalidArgumentValue('remoteId', $locationCreateStruct->remoteId, 'LocationCreateStruct');
442
        }
443
444
        if ($locationCreateStruct->sortField !== null && !$this->isValidLocationSortField($locationCreateStruct->sortField)) {
445
            throw new InvalidArgumentValue('sortField', $locationCreateStruct->sortField, 'LocationCreateStruct');
446
        }
447
448
        if ($locationCreateStruct->sortOrder !== null && !$this->isValidLocationSortOrder($locationCreateStruct->sortOrder)) {
449
            throw new InvalidArgumentValue('sortOrder', $locationCreateStruct->sortOrder, 'LocationCreateStruct');
450
        }
451
452
        $remoteId = $locationCreateStruct->remoteId;
453
        if (null === $remoteId) {
454
            $remoteId = $this->getUniqueHash($locationCreateStruct);
455
        } else {
456
            try {
457
                $this->locationHandler->loadByRemoteId($remoteId);
458
                throw new InvalidArgumentException(
459
                    '$locationCreateStructs',
460
                    "Another Location with remoteId '{$remoteId}' exists"
461
                );
462
            } catch (NotFoundException $e) {
463
                // Do nothing
464
            }
465
        }
466
467
        return new SPILocationCreateStruct(
468
            array(
469
                'priority' => $locationCreateStruct->priority,
470
                'hidden' => $locationCreateStruct->hidden,
471
                // If we declare the new Location as hidden, it is automatically invisible
472
                // Otherwise it picks up visibility from parent Location
473
                // Note: There is no need to check for hidden status of parent, as hidden Location
474
                // is always invisible as well
475
                'invisible' => ($locationCreateStruct->hidden === true || $parentLocation->invisible),
476
                'remoteId' => $remoteId,
477
                'contentId' => $contentId,
478
                'contentVersion' => $contentVersionNo,
479
                // pathIdentificationString will be set in storage
480
                'pathIdentificationString' => null,
481
                'mainLocationId' => $mainLocation,
482
                'sortField' => $locationCreateStruct->sortField !== null ? $locationCreateStruct->sortField : Location::SORT_FIELD_NAME,
483
                'sortOrder' => $locationCreateStruct->sortOrder !== null ? $locationCreateStruct->sortOrder : Location::SORT_ORDER_ASC,
484
                'parentId' => $locationCreateStruct->parentLocationId,
485
            )
486
        );
487
    }
488
489
    /**
490
     * Checks if given $sortField value is one of the defined sort field constants.
491
     *
492
     * @param mixed $sortField
493
     *
494
     * @return bool
495
     */
496
    public function isValidLocationSortField($sortField)
497
    {
498
        switch ($sortField) {
499
            case APILocation::SORT_FIELD_PATH:
500
            case APILocation::SORT_FIELD_PUBLISHED:
501
            case APILocation::SORT_FIELD_MODIFIED:
502
            case APILocation::SORT_FIELD_SECTION:
503
            case APILocation::SORT_FIELD_DEPTH:
504
            case APILocation::SORT_FIELD_CLASS_IDENTIFIER:
505
            case APILocation::SORT_FIELD_CLASS_NAME:
506
            case APILocation::SORT_FIELD_PRIORITY:
507
            case APILocation::SORT_FIELD_NAME:
508
            case APILocation::SORT_FIELD_MODIFIED_SUBNODE:
0 ignored issues
show
Deprecated Code introduced by
The constant eZ\Publish\API\Repositor..._FIELD_MODIFIED_SUBNODE has been deprecated.

This class constant has been deprecated.

Loading history...
509
            case APILocation::SORT_FIELD_NODE_ID:
510
            case APILocation::SORT_FIELD_CONTENTOBJECT_ID:
511
                return true;
512
        }
513
514
        return false;
515
    }
516
517
    /**
518
     * Checks if given $sortOrder value is one of the defined sort order constants.
519
     *
520
     * @param mixed $sortOrder
521
     *
522
     * @return bool
523
     */
524
    public function isValidLocationSortOrder($sortOrder)
525
    {
526
        switch ($sortOrder) {
527
            case APILocation::SORT_ORDER_DESC:
528
            case APILocation::SORT_ORDER_ASC:
529
                return true;
530
        }
531
532
        return false;
533
    }
534
535
    /**
536
     * Checks if given $priority is valid.
537
     *
538
     * @param int $priority
539
     *
540
     * @return bool
541
     */
542
    public function isValidLocationPriority($priority)
543
    {
544
        if ($priority === null) {
545
            return true;
546
        }
547
548
        return is_int($priority) && $priority >= self::MIN_LOCATION_PRIORITY && $priority <= self::MAX_LOCATION_PRIORITY;
549
    }
550
551
    /**
552
     * Validates given translated list $list, which should be an array of strings with language codes as keys.
553
     *
554
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
555
     *
556
     * @param mixed $list
557
     * @param string $argumentName
558
     */
559
    public function validateTranslatedList($list, $argumentName)
560
    {
561
        if (!is_array($list)) {
562
            throw new InvalidArgumentType($argumentName, 'array', $list);
563
        }
564
565
        foreach ($list as $languageCode => $translation) {
566
            $this->contentLanguageHandler->loadByLanguageCode($languageCode);
567
568
            if (!is_string($translation)) {
569
                throw new InvalidArgumentType($argumentName . "['$languageCode']", 'string', $translation);
570
            }
571
        }
572
    }
573
574
    /**
575
     * Returns \DateTime object from given $timestamp in environment timezone.
576
     *
577
     * This method is needed because constructing \DateTime with $timestamp will
578
     * return the object in UTC timezone.
579
     *
580
     * @param int $timestamp
581
     *
582
     * @return \DateTime
583
     */
584
    public function getDateTime($timestamp)
585
    {
586
        $dateTime = new DateTime();
587
        $dateTime->setTimestamp($timestamp);
588
589
        return $dateTime;
590
    }
591
592
    /**
593
     * Creates unique hash string for given $object.
594
     *
595
     * Used for remoteId.
596
     *
597
     * @param object $object
598
     *
599
     * @return string
600
     */
601
    public function getUniqueHash($object)
602
    {
603
        return md5(uniqid(get_class($object), true));
604
    }
605
}
606