Skip to content

Commit 8441b19

Browse files
authored
EZEE-3176: Reduced scope of content changes to new and updated fields (#86)
1 parent c9ecd0a commit 8441b19

File tree

10 files changed

+583
-285
lines changed

10 files changed

+583
-285
lines changed

eZ/Publish/API/Repository/Tests/ContentServiceTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,8 +1601,8 @@ public function testUpdateContentThrowsBadStateException()
16011601

16021602
// Now create an update struct and modify some fields
16031603
$contentUpdateStruct = $this->contentService->newContentUpdateStruct();
1604-
$contentUpdateStruct->setField('title', 'An awesome² story about ezp.');
1605-
$contentUpdateStruct->setField('title', 'An awesome²³ story about ezp.', self::ENG_GB);
1604+
$contentUpdateStruct->setField('name', 'An awesome² story about ezp.');
1605+
$contentUpdateStruct->setField('name', 'An awesome²³ story about ezp.', self::ENG_GB);
16061606

16071607
$contentUpdateStruct->initialLanguageCode = self::ENG_US;
16081608

eZ/Publish/API/Repository/Tests/PermissionResolverTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,7 @@ public function testCanUserWithMultipleTargetsNo()
681681
$contentService = $repository->getContentService();
682682

683683
$contentCreateStruct = $contentService->newContentCreateStruct($contentType, 'eng-US');
684-
$contentCreateStruct->setField('name', 'My awesome forums');
684+
$contentCreateStruct->setField('title', 'My awesome forums');
685685
$contentCreateStruct->remoteId = 'abcdef0123456789abcdef0123456789';
686686
$contentCreateStruct->alwaysAvailable = true;
687687

eZ/Publish/Core/Repository/ContentService.php

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,11 @@ public function createContent(APIContentCreateStruct $contentCreateStruct, array
580580
$contentCreateStruct->contentType->id
581581
);
582582

583+
$contentCreateStruct->fields = $this->contentMapper->getFieldsForCreate(
584+
$contentCreateStruct->fields,
585+
$contentCreateStruct->contentType
586+
);
587+
583588
if (empty($contentCreateStruct->sectionId)) {
584589
if (isset($locationCreateStructs[0])) {
585590
$location = $this->repository->getLocationService()->loadLocation(
@@ -649,13 +654,11 @@ public function createContent(APIContentCreateStruct $contentCreateStruct, array
649654
$isEmptyValue = false;
650655
$valueLanguageCode = $fieldDefinition->isTranslatable ? $languageCode : $contentCreateStruct->mainLanguageCode;
651656
$isLanguageMain = $languageCode === $contentCreateStruct->mainLanguageCode;
652-
if (isset($fields[$fieldDefinition->identifier][$valueLanguageCode])) {
653-
$fieldValue = $fields[$fieldDefinition->identifier][$valueLanguageCode]->value;
654-
} else {
655-
$fieldValue = $fieldDefinition->defaultValue;
656-
}
657657

658-
$fieldValue = $fieldType->acceptValue($fieldValue);
658+
$fieldValue = $this->contentMapper->getFieldValueForCreate(
659+
$fieldDefinition,
660+
$fields[$fieldDefinition->identifier][$valueLanguageCode] ?? null
661+
);
659662

660663
if ($fieldType->isEmptyValue($fieldValue)) {
661664
$isEmptyValue = true;
@@ -1200,12 +1203,15 @@ public function updateContent(APIVersionInfo $versionInfo, APIContentUpdateStruc
12001203
$versionInfo->versionNo
12011204
);
12021205

1206+
$updatedFields = $this->contentMapper->getFieldsForUpdate($contentUpdateStruct->fields, $content);
1207+
12031208
if (!$this->repository->getPermissionResolver()->canUser(
12041209
'content',
12051210
'edit',
12061211
$content,
12071212
[
12081213
(new Target\Builder\VersionBuilder())
1214+
->updateFields($updatedFields)
12091215
->updateFieldsTo(
12101216
$contentUpdateStruct->initialLanguageCode,
12111217
$contentUpdateStruct->fields
@@ -1301,17 +1307,16 @@ protected function internalUpdateContent(
13011307

13021308
if (!$isFieldUpdated && !$isLanguageNew) {
13031309
$isRetained = true;
1304-
$fieldValue = $content->getField($fieldDefinition->identifier, $valueLanguageCode)->value;
13051310
} elseif (!$isFieldUpdated && $isLanguageNew && !$fieldDefinition->isTranslatable) {
13061311
$isCopied = true;
1307-
$fieldValue = $content->getField($fieldDefinition->identifier, $valueLanguageCode)->value;
1308-
} elseif ($isFieldUpdated) {
1309-
$fieldValue = $fields[$fieldDefinition->identifier][$valueLanguageCode]->value;
1310-
} else {
1311-
$fieldValue = $fieldDefinition->defaultValue;
13121312
}
13131313

1314-
$fieldValue = $fieldType->acceptValue($fieldValue);
1314+
$fieldValue = $this->contentMapper->getFieldValueForUpdate(
1315+
$fields[$fieldDefinition->identifier][$valueLanguageCode] ?? null,
1316+
$content->getField($fieldDefinition->identifier, $valueLanguageCode),
1317+
$fieldDefinition,
1318+
$isLanguageNew
1319+
);
13151320

13161321
if ($fieldType->isEmptyValue($fieldValue)) {
13171322
$isEmpty = true;

eZ/Publish/Core/Repository/Mapper/ContentMapper.php

Lines changed: 136 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@
88

99
namespace eZ\Publish\Core\Repository\Mapper;
1010

11-
use eZ\Publish\API\Repository\Values\Content\Content as APIContent;
12-
use eZ\Publish\API\Repository\Values\Content\ContentCreateStruct as APIContentCreateStruct;
13-
use eZ\Publish\API\Repository\Values\Content\ContentUpdateStruct as APIContentUpdateStruct;
11+
use eZ\Publish\API\Repository\Values\Content\Content;
12+
use eZ\Publish\API\Repository\Values\Content\ContentCreateStruct;
13+
use eZ\Publish\API\Repository\Values\Content\ContentUpdateStruct;
1414
use eZ\Publish\API\Repository\Values\Content\Field;
1515
use eZ\Publish\API\Repository\Values\ContentType\ContentType;
16+
use eZ\Publish\API\Repository\Values\ContentType\FieldDefinition;
1617
use eZ\Publish\Core\Base\Exceptions\ContentValidationException;
18+
use eZ\Publish\Core\FieldType\FieldTypeRegistry;
19+
use eZ\Publish\SPI\FieldType\Value;
1720
use eZ\Publish\SPI\Persistence\Content\Language\Handler;
1821

1922
/**
@@ -24,10 +27,15 @@ class ContentMapper
2427
/** @var \eZ\Publish\Core\Persistence\Legacy\Content\Language\Handler */
2528
private $contentLanguageHandler;
2629

30+
/** @var \eZ\Publish\Core\FieldType\FieldTypeRegistry */
31+
private $fieldTypeRegistry;
32+
2733
public function __construct(
28-
Handler $contentLanguageHandler
34+
Handler $contentLanguageHandler,
35+
FieldTypeRegistry $fieldTypeRegistry
2936
) {
3037
$this->contentLanguageHandler = $contentLanguageHandler;
38+
$this->fieldTypeRegistry = $fieldTypeRegistry;
3139
}
3240

3341
/**
@@ -41,7 +49,7 @@ public function __construct(
4149
*
4250
* @return array
4351
*/
44-
public function mapFieldsForCreate(APIContentCreateStruct $contentCreateStruct): array
52+
public function mapFieldsForCreate(ContentCreateStruct $contentCreateStruct): array
4553
{
4654
$fields = [];
4755

@@ -82,7 +90,7 @@ public function mapFieldsForCreate(APIContentCreateStruct $contentCreateStruct):
8290
*
8391
* @return string[]
8492
*/
85-
public function getLanguageCodesForCreate(APIContentCreateStruct $contentCreateStruct): array
93+
public function getLanguageCodesForCreate(ContentCreateStruct $contentCreateStruct): array
8694
{
8795
$languageCodes = [];
8896

@@ -121,9 +129,9 @@ public function getLanguageCodesForCreate(APIContentCreateStruct $contentCreateS
121129
* @return array
122130
*/
123131
public function mapFieldsForUpdate(
124-
APIContentUpdateStruct $contentUpdateStruct,
132+
ContentUpdateStruct $contentUpdateStruct,
125133
ContentType $contentType,
126-
string $mainLanguageCode
134+
?string $mainLanguageCode = null
127135
): array {
128136
$fields = [];
129137

@@ -159,6 +167,48 @@ public function mapFieldsForUpdate(
159167
return $fields;
160168
}
161169

170+
public function getFieldValueForCreate(
171+
FieldDefinition $fieldDefinition,
172+
?Field $field
173+
): Value {
174+
if (null !== $field) {
175+
$fieldValue = $field->value;
176+
} else {
177+
$fieldValue = $fieldDefinition->defaultValue;
178+
}
179+
180+
$fieldType = $this->fieldTypeRegistry->getFieldType(
181+
$fieldDefinition->fieldTypeIdentifier
182+
);
183+
184+
return $fieldType->acceptValue($fieldValue);
185+
}
186+
187+
public function getFieldValueForUpdate(
188+
?Field $newField,
189+
?Field $previousField,
190+
FieldDefinition $fieldDefinition,
191+
bool $isLanguageNew
192+
): Value {
193+
$isFieldUpdated = null !== $newField;
194+
195+
if (!$isFieldUpdated && !$isLanguageNew) {
196+
$fieldValue = $previousField->value;
197+
} elseif (!$isFieldUpdated && $isLanguageNew && !$fieldDefinition->isTranslatable) {
198+
$fieldValue = $previousField->value;
199+
} elseif ($isFieldUpdated) {
200+
$fieldValue = $newField->value;
201+
} else {
202+
$fieldValue = $fieldDefinition->defaultValue;
203+
}
204+
205+
$fieldType = $this->fieldTypeRegistry->getFieldType(
206+
$fieldDefinition->fieldTypeIdentifier
207+
);
208+
209+
return $fieldType->acceptValue($fieldValue);
210+
}
211+
162212
/**
163213
* Returns all language codes used in given $fields.
164214
*
@@ -167,7 +217,7 @@ public function mapFieldsForUpdate(
167217
*
168218
* @return string[]
169219
*/
170-
public function getLanguageCodesForUpdate(APIContentUpdateStruct $contentUpdateStruct, APIContent $content): array
220+
public function getLanguageCodesForUpdate(ContentUpdateStruct $contentUpdateStruct, Content $content): array
171221
{
172222
$languageCodes = array_fill_keys($content->versionInfo->languageCodes, true);
173223
$languageCodes[$contentUpdateStruct->initialLanguageCode] = true;
@@ -187,7 +237,7 @@ public function getLanguageCodesForUpdate(APIContentUpdateStruct $contentUpdateS
187237
*
188238
* @return string[]
189239
*/
190-
public function getUpdatedLanguageCodes(APIContentUpdateStruct $contentUpdateStruct): array
240+
public function getUpdatedLanguageCodes(ContentUpdateStruct $contentUpdateStruct): array
191241
{
192242
$languageCodes = [
193243
$contentUpdateStruct->initialLanguageCode => true,
@@ -227,4 +277,80 @@ private function cloneField(Field $field, array $overrides = []): Field
227277

228278
return new Field($fieldData);
229279
}
280+
281+
/**
282+
* @param \eZ\Publish\API\Repository\Values\Content\Field[] $updatedFields
283+
*
284+
* @return \eZ\Publish\API\Repository\Values\Content\Field[]
285+
*/
286+
public function getFieldsForUpdate(array $updatedFields, Content $content): array
287+
{
288+
$contentType = $content->getContentType();
289+
$fields = [];
290+
291+
foreach ($updatedFields as $updatedField) {
292+
$fieldDefinition = $contentType->getFieldDefinition($updatedField->fieldDefIdentifier);
293+
294+
if ($fieldDefinition === null) {
295+
throw new ContentValidationException(
296+
"Field definition '%identifier%' does not exist in given Content Type",
297+
['%identifier%' => $updatedField->fieldDefIdentifier]
298+
);
299+
}
300+
301+
$fieldType = $this->fieldTypeRegistry->getFieldType($fieldDefinition->fieldTypeIdentifier);
302+
303+
$field = $content->getField($updatedField->fieldDefIdentifier);
304+
$updatedFieldValue = $this->getFieldValueForUpdate(
305+
$updatedField,
306+
$field,
307+
$contentType->getFieldDefinition($updatedField->fieldDefIdentifier),
308+
!in_array($updatedField->languageCode, $content->versionInfo->languageCodes, true)
309+
);
310+
311+
if (!empty($field)) {
312+
$updatedFieldHash = md5(json_encode($fieldType->toHash($updatedFieldValue)));
313+
$contentFieldHash = md5(json_encode($fieldType->toHash($field->value)));
314+
315+
if ($updatedFieldHash !== $contentFieldHash) {
316+
$fields[] = $updatedField;
317+
}
318+
}
319+
}
320+
321+
return $fields;
322+
}
323+
324+
public function getFieldsForCreate(array $createdFields, ContentType $contentType): array
325+
{
326+
$fields = [];
327+
328+
/** @var \eZ\Publish\API\Repository\Values\Content\Field $createdField */
329+
foreach ($createdFields as $createdField) {
330+
$fieldDefinition = $contentType->getFieldDefinition($createdField->fieldDefIdentifier);
331+
332+
if ($fieldDefinition === null) {
333+
throw new ContentValidationException(
334+
"Field definition '%identifier%' does not exist in the given Content Type",
335+
['%identifier%' => $createdField->fieldDefIdentifier]
336+
);
337+
}
338+
339+
$fieldType = $this->fieldTypeRegistry->getFieldType($fieldDefinition->fieldTypeIdentifier);
340+
341+
$createdFieldValue = $this->getFieldValueForCreate(
342+
$fieldDefinition,
343+
$createdField
344+
);
345+
346+
$createdFieldHash = md5(json_encode($fieldType->toHash($createdFieldValue)));
347+
$defaultFieldHash = md5(json_encode($fieldType->toHash($fieldDefinition->defaultValue)));
348+
349+
if ($createdFieldHash !== $defaultFieldHash) {
350+
$fields[] = $createdField;
351+
}
352+
}
353+
354+
return $fields;
355+
}
230356
}

eZ/Publish/Core/Repository/Tests/Service/Mock/Base.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,8 @@ protected function getRoleDomainMapperMock(array $methods = []): RoleDomainMappe
395395
protected function getContentMapper(): ContentMapper
396396
{
397397
return new ContentMapper(
398-
$this->getPersistenceMock()->contentLanguageHandler()
398+
$this->getPersistenceMock()->contentLanguageHandler(),
399+
$this->getFieldTypeRegistryMock()
399400
);
400401
}
401402

0 commit comments

Comments
 (0)