vendor/ezsystems/ezplatform-kernel/eZ/Publish/Core/Repository/Mapper/ContentMapper.php line 25

Open in your IDE?
  1. <?php
  2. /**
  3.  * @copyright Copyright (C) Ibexa AS. All rights reserved.
  4.  * @license For full copyright and license information view LICENSE file distributed with this source code.
  5.  */
  6. declare(strict_types=1);
  7. namespace eZ\Publish\Core\Repository\Mapper;
  8. use eZ\Publish\API\Repository\Values\Content\Content;
  9. use eZ\Publish\API\Repository\Values\Content\ContentCreateStruct;
  10. use eZ\Publish\API\Repository\Values\Content\ContentUpdateStruct;
  11. use eZ\Publish\API\Repository\Values\Content\Field;
  12. use eZ\Publish\API\Repository\Values\ContentType\ContentType;
  13. use eZ\Publish\API\Repository\Values\ContentType\FieldDefinition;
  14. use eZ\Publish\Core\Base\Exceptions\ContentValidationException;
  15. use eZ\Publish\Core\FieldType\FieldTypeRegistry;
  16. use eZ\Publish\SPI\FieldType\Value;
  17. use eZ\Publish\SPI\Persistence\Content\Language\Handler;
  18. /**
  19.  * @internal Meant for internal use by Repository
  20.  */
  21. class ContentMapper
  22. {
  23.     /** @var \eZ\Publish\Core\Persistence\Legacy\Content\Language\Handler */
  24.     private $contentLanguageHandler;
  25.     /** @var \eZ\Publish\Core\FieldType\FieldTypeRegistry */
  26.     private $fieldTypeRegistry;
  27.     public function __construct(
  28.         Handler $contentLanguageHandler,
  29.         FieldTypeRegistry $fieldTypeRegistry
  30.     ) {
  31.         $this->contentLanguageHandler $contentLanguageHandler;
  32.         $this->fieldTypeRegistry $fieldTypeRegistry;
  33.     }
  34.     /**
  35.      * Returns an array of fields like $fields[$field->fieldDefIdentifier][$field->languageCode].
  36.      *
  37.      * @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException If field definition does not exist in the ContentType
  38.      *                                                                          or value is set for non-translatable field in language
  39.      *                                                                          other than main
  40.      *
  41.      * @param \eZ\Publish\API\Repository\Values\Content\ContentCreateStruct $contentCreateStruct
  42.      *
  43.      * @return array
  44.      */
  45.     public function mapFieldsForCreate(ContentCreateStruct $contentCreateStruct): array
  46.     {
  47.         $fields = [];
  48.         foreach ($contentCreateStruct->fields as $field) {
  49.             $fieldDefinition $contentCreateStruct->contentType->getFieldDefinition($field->fieldDefIdentifier);
  50.             if ($fieldDefinition === null) {
  51.                 throw new ContentValidationException(
  52.                     "Field definition '%identifier%' does not exist in the given Content Type",
  53.                     ['%identifier%' => $field->fieldDefIdentifier]
  54.                 );
  55.             }
  56.             if ($field->languageCode === null) {
  57.                 $field $this->cloneField(
  58.                     $field,
  59.                     ['languageCode' => $contentCreateStruct->mainLanguageCode]
  60.                 );
  61.             }
  62.             if (!$fieldDefinition->isTranslatable && ($field->languageCode != $contentCreateStruct->mainLanguageCode)) {
  63.                 throw new ContentValidationException(
  64.                     "You cannot set a value for the non-translatable Field definition '%identifier%' in language '%languageCode%'",
  65.                     ['%identifier%' => $field->fieldDefIdentifier'%languageCode%' => $field->languageCode]
  66.                 );
  67.             }
  68.             $fields[$field->fieldDefIdentifier][$field->languageCode] = $field;
  69.         }
  70.         return $fields;
  71.     }
  72.     /**
  73.      * Returns all language codes used in given $fields.
  74.      *
  75.      * @param \eZ\Publish\API\Repository\Values\Content\ContentCreateStruct $contentCreateStruct
  76.      *
  77.      * @return string[]
  78.      */
  79.     public function getLanguageCodesForCreate(ContentCreateStruct $contentCreateStruct): array
  80.     {
  81.         $languageCodes = [];
  82.         foreach ($contentCreateStruct->fields as $field) {
  83.             if ($field->languageCode === null || isset($languageCodes[$field->languageCode])) {
  84.                 continue;
  85.             }
  86.             $this->contentLanguageHandler->loadByLanguageCode(
  87.                 $field->languageCode
  88.             );
  89.             $languageCodes[$field->languageCode] = true;
  90.         }
  91.         if (!isset($languageCodes[$contentCreateStruct->mainLanguageCode])) {
  92.             $this->contentLanguageHandler->loadByLanguageCode(
  93.                 $contentCreateStruct->mainLanguageCode
  94.             );
  95.             $languageCodes[$contentCreateStruct->mainLanguageCode] = true;
  96.         }
  97.         return array_keys($languageCodes);
  98.     }
  99.     /**
  100.      * Returns an array of fields like $fields[$field->fieldDefIdentifier][$field->languageCode].
  101.      *
  102.      * @throws \eZ\Publish\API\Repository\Exceptions\ContentValidationException If field definition does not exist in the ContentType
  103.      *                                                                          or value is set for non-translatable field in language
  104.      *                                                                          other than main
  105.      *
  106.      * @param \eZ\Publish\API\Repository\Values\Content\ContentUpdateStruct $contentUpdateStruct
  107.      * @param \eZ\Publish\API\Repository\Values\ContentType\ContentType $contentType
  108.      * @param string $mainLanguageCode
  109.      *
  110.      * @return array
  111.      */
  112.     public function mapFieldsForUpdate(
  113.         ContentUpdateStruct $contentUpdateStruct,
  114.         ContentType $contentType,
  115.         ?string $mainLanguageCode null
  116.     ): array {
  117.         $fields = [];
  118.         foreach ($contentUpdateStruct->fields as $field) {
  119.             $fieldDefinition $contentType->getFieldDefinition($field->fieldDefIdentifier);
  120.             if ($fieldDefinition === null) {
  121.                 throw new ContentValidationException(
  122.                     "Field definition '%identifier%' does not exist in given Content Type",
  123.                     ['%identifier%' => $field->fieldDefIdentifier]
  124.                 );
  125.             }
  126.             if ($field->languageCode === null) {
  127.                 if ($fieldDefinition->isTranslatable) {
  128.                     $languageCode $contentUpdateStruct->initialLanguageCode;
  129.                 } else {
  130.                     $languageCode $mainLanguageCode;
  131.                 }
  132.                 $field $this->cloneField($field, ['languageCode' => $languageCode]);
  133.             }
  134.             if (!$fieldDefinition->isTranslatable && ($field->languageCode != $mainLanguageCode)) {
  135.                 throw new ContentValidationException(
  136.                     "You cannot set a value for the non-translatable Field definition '%identifier%' in language '%languageCode%'",
  137.                     ['%identifier%' => $field->fieldDefIdentifier'%languageCode%' => $field->languageCode]
  138.                 );
  139.             }
  140.             $fields[$field->fieldDefIdentifier][$field->languageCode] = $field;
  141.         }
  142.         return $fields;
  143.     }
  144.     public function getFieldValueForCreate(
  145.         FieldDefinition $fieldDefinition,
  146.         ?Field $field
  147.     ): Value {
  148.         if (null !== $field) {
  149.             $fieldValue $field->value;
  150.         } else {
  151.             $fieldValue $fieldDefinition->defaultValue;
  152.         }
  153.         $fieldType $this->fieldTypeRegistry->getFieldType(
  154.             $fieldDefinition->fieldTypeIdentifier
  155.         );
  156.         return $fieldType->acceptValue($fieldValue);
  157.     }
  158.     public function getFieldValueForUpdate(
  159.         ?Field $newField,
  160.         ?Field $previousField,
  161.         FieldDefinition $fieldDefinition,
  162.         bool $isLanguageNew
  163.     ): Value {
  164.         $isFieldUpdated null !== $newField;
  165.         if (!$isFieldUpdated && !$isLanguageNew) {
  166.             $fieldValue $previousField->value;
  167.         } elseif (!$isFieldUpdated && $isLanguageNew && !$fieldDefinition->isTranslatable) {
  168.             $fieldValue $previousField->value;
  169.         } elseif ($isFieldUpdated) {
  170.             $fieldValue $newField->value;
  171.         } else {
  172.             $fieldValue $fieldDefinition->defaultValue;
  173.         }
  174.         $fieldType $this->fieldTypeRegistry->getFieldType(
  175.             $fieldDefinition->fieldTypeIdentifier
  176.         );
  177.         return $fieldType->acceptValue($fieldValue);
  178.     }
  179.     /**
  180.      * Returns all language codes used in given $fields.
  181.      *
  182.      * @param \eZ\Publish\API\Repository\Values\Content\ContentUpdateStruct $contentUpdateStruct
  183.      * @param \eZ\Publish\API\Repository\Values\Content\Content $content
  184.      *
  185.      * @return string[]
  186.      */
  187.     public function getLanguageCodesForUpdate(ContentUpdateStruct $contentUpdateStructContent $content): array
  188.     {
  189.         $languageCodes array_fill_keys($content->versionInfo->languageCodestrue);
  190.         $languageCodes[$contentUpdateStruct->initialLanguageCode] = true;
  191.         $updatedLanguageCodes $this->getUpdatedLanguageCodes($contentUpdateStruct);
  192.         foreach ($updatedLanguageCodes as $languageCode) {
  193.             $languageCodes[$languageCode] = true;
  194.         }
  195.         return array_keys($languageCodes);
  196.     }
  197.     /**
  198.      * Returns only updated language codes.
  199.      *
  200.      * @param \eZ\Publish\API\Repository\Values\Content\ContentUpdateStruct $contentUpdateStruct
  201.      *
  202.      * @return string[]
  203.      */
  204.     public function getUpdatedLanguageCodes(ContentUpdateStruct $contentUpdateStruct): array
  205.     {
  206.         $languageCodes = [
  207.             $contentUpdateStruct->initialLanguageCode => true,
  208.         ];
  209.         foreach ($contentUpdateStruct->fields as $field) {
  210.             if ($field->languageCode === null || isset($languageCodes[$field->languageCode])) {
  211.                 continue;
  212.             }
  213.             $languageCodes[$field->languageCode] = true;
  214.         }
  215.         return array_keys($languageCodes);
  216.     }
  217.     /**
  218.      * Clones $field with overriding specific properties from given $overrides array.
  219.      *
  220.      * @param \eZ\Publish\API\Repository\Values\Content\Field $field
  221.      * @param array $overrides
  222.      *
  223.      * @return \eZ\Publish\API\Repository\Values\Content\Field
  224.      */
  225.     private function cloneField(Field $field, array $overrides = []): Field
  226.     {
  227.         $fieldData array_merge(
  228.             [
  229.                 'id' => $field->id,
  230.                 'value' => $field->value,
  231.                 'languageCode' => $field->languageCode,
  232.                 'fieldDefIdentifier' => $field->fieldDefIdentifier,
  233.                 'fieldTypeIdentifier' => $field->fieldTypeIdentifier,
  234.             ],
  235.             $overrides
  236.         );
  237.         return new Field($fieldData);
  238.     }
  239.     /**
  240.      * @param \eZ\Publish\API\Repository\Values\Content\Field[] $updatedFields
  241.      *
  242.      * @return \eZ\Publish\API\Repository\Values\Content\Field[]
  243.      */
  244.     public function getFieldsForUpdate(array $updatedFieldsContent $content): array
  245.     {
  246.         $contentType $content->getContentType();
  247.         $fields = [];
  248.         foreach ($updatedFields as $updatedField) {
  249.             $fieldDefinition $contentType->getFieldDefinition($updatedField->fieldDefIdentifier);
  250.             if ($fieldDefinition === null) {
  251.                 throw new ContentValidationException(
  252.                     "Field definition '%identifier%' does not exist in given Content Type",
  253.                     ['%identifier%' => $updatedField->fieldDefIdentifier]
  254.                 );
  255.             }
  256.             $fieldType $this->fieldTypeRegistry->getFieldType($fieldDefinition->fieldTypeIdentifier);
  257.             $field $content->getField($updatedField->fieldDefIdentifier);
  258.             $updatedFieldValue $this->getFieldValueForUpdate(
  259.                 $updatedField,
  260.                 $field,
  261.                 $contentType->getFieldDefinition($updatedField->fieldDefIdentifier),
  262.                 !in_array($updatedField->languageCode$content->versionInfo->languageCodestrue)
  263.             );
  264.             if (!empty($field)) {
  265.                 $updatedFieldHash md5(json_encode($fieldType->toHash($updatedFieldValue)));
  266.                 $contentFieldHash md5(json_encode($fieldType->toHash($field->value)));
  267.                 if ($updatedFieldHash !== $contentFieldHash) {
  268.                     $fields[] = $updatedField;
  269.                 }
  270.             }
  271.         }
  272.         return $fields;
  273.     }
  274.     public function getFieldsForCreate(array $createdFieldsContentType $contentType): array
  275.     {
  276.         $fields = [];
  277.         /** @var \eZ\Publish\API\Repository\Values\Content\Field $createdField */
  278.         foreach ($createdFields as $createdField) {
  279.             $fieldDefinition $contentType->getFieldDefinition($createdField->fieldDefIdentifier);
  280.             if ($fieldDefinition === null) {
  281.                 throw new ContentValidationException(
  282.                     "Field definition '%identifier%' does not exist in the given Content Type",
  283.                     ['%identifier%' => $createdField->fieldDefIdentifier]
  284.                 );
  285.             }
  286.             $fieldType $this->fieldTypeRegistry->getFieldType($fieldDefinition->fieldTypeIdentifier);
  287.             $createdFieldValue $this->getFieldValueForCreate(
  288.                 $fieldDefinition,
  289.                 $createdField
  290.             );
  291.             $createdFieldHash md5(json_encode($fieldType->toHash($createdFieldValue)));
  292.             $defaultFieldHash md5(json_encode($fieldType->toHash($fieldDefinition->defaultValue)));
  293.             if ($createdFieldHash !== $defaultFieldHash) {
  294.                 $fields[] = $createdField;
  295.             }
  296.         }
  297.         return $fields;
  298.     }
  299. }