From 8b1ab2dd7f865ff2cde75a72210e28df90ce144e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20W=C3=B3js?= Date: Fri, 16 Feb 2018 16:19:28 +0100 Subject: [PATCH] EZP-28836: Skipping validation of non-modified fields when content is updated (cherry picked from commit a2613f129c83d5e3b0a11e24ef1b62fb9670f1f7) --- .../ApiLoader/RepositoryFactory.php | 6 +- .../Base/Container/ApiLoader/RepositoryFactory.php | 5 +- eZ/Publish/Core/Repository/ContentService.php | 68 +++++--- .../Core/Repository/Helper/RelationProcessor.php | 23 ++- eZ/Publish/Core/Repository/Repository.php | 9 +- .../Core/Repository/Tests/Service/Mock/Base.php | 12 ++ .../Repository/Tests/Service/Mock/ContentTest.php | 180 ++++++++++++++++----- .../Tests/Service/Mock/RelationProcessorTest.php | 56 +++++++ eZ/Publish/Core/settings/repository/inner.yml | 8 + 9 files changed, 294 insertions(+), 73 deletions(-) diff --git a/eZ/Bundle/EzPublishCoreBundle/ApiLoader/RepositoryFactory.php b/eZ/Bundle/EzPublishCoreBundle/ApiLoader/RepositoryFactory.php index aaba3298d4..f1e2ed75c0 100644 --- a/eZ/Bundle/EzPublishCoreBundle/ApiLoader/RepositoryFactory.php +++ b/eZ/Bundle/EzPublishCoreBundle/ApiLoader/RepositoryFactory.php @@ -9,6 +9,7 @@ namespace eZ\Bundle\EzPublishCoreBundle\ApiLoader; use eZ\Publish\Core\MVC\ConfigResolverInterface; +use eZ\Publish\Core\Repository\Helper\RelationProcessor; use eZ\Publish\Core\Repository\Values\User\UserReference; use eZ\Publish\Core\Search\Common\BackgroundIndexer; use eZ\Publish\SPI\Persistence\Handler as PersistenceHandler; @@ -82,13 +83,15 @@ public function __construct( * @param \eZ\Publish\SPI\Persistence\Handler $persistenceHandler * @param \eZ\Publish\SPI\Search\Handler $searchHandler * @param \eZ\Publish\Core\Search\Common\BackgroundIndexer $backgroundIndexer + * @param \eZ\Publish\Core\Repository\Helper\RelationProcessor $relationProcessor * * @return \eZ\Publish\API\Repository\Repository */ public function buildRepository( PersistenceHandler $persistenceHandler, SearchHandler $searchHandler, - BackgroundIndexer $backgroundIndexer + BackgroundIndexer $backgroundIndexer, + RelationProcessor $relationProcessor ) { $config = $this->container->get('ezpublish.api.repository_configuration_provider')->getRepositoryConfig(); @@ -96,6 +99,7 @@ public function buildRepository( $persistenceHandler, $searchHandler, $backgroundIndexer, + $relationProcessor, array( 'fieldType' => $this->fieldTypeCollectionFactory->getFieldTypes(), 'nameableFieldTypes' => $this->fieldTypeNameableCollectionFactory->getNameableFieldTypes(), diff --git a/eZ/Publish/Core/Base/Container/ApiLoader/RepositoryFactory.php b/eZ/Publish/Core/Base/Container/ApiLoader/RepositoryFactory.php index fc6b2bd817..4365ae8201 100644 --- a/eZ/Publish/Core/Base/Container/ApiLoader/RepositoryFactory.php +++ b/eZ/Publish/Core/Base/Container/ApiLoader/RepositoryFactory.php @@ -8,6 +8,7 @@ */ namespace eZ\Publish\Core\Base\Container\ApiLoader; +use eZ\Publish\Core\Repository\Helper\RelationProcessor; use eZ\Publish\Core\Repository\Values\User\UserReference; use eZ\Publish\Core\Search\Common\BackgroundIndexer; use eZ\Publish\SPI\Persistence\Handler as PersistenceHandler; @@ -73,12 +74,14 @@ public function __construct( public function buildRepository( PersistenceHandler $persistenceHandler, SearchHandler $searchHandler, - BackgroundIndexer $backgroundIndexer + BackgroundIndexer $backgroundIndexer, + RelationProcessor $relationProcessor ) { $repository = new $this->repositoryClass( $persistenceHandler, $searchHandler, $backgroundIndexer, + $relationProcessor, array( 'fieldType' => $this->fieldTypeCollectionFactory->getFieldTypes(), 'nameableFieldTypes' => $this->fieldTypeNameableCollectionFactory->getNameableFieldTypes(), diff --git a/eZ/Publish/Core/Repository/ContentService.php b/eZ/Publish/Core/Repository/ContentService.php index 594b0af3e0..a8cb25afb6 100644 --- a/eZ/Publish/Core/Repository/ContentService.php +++ b/eZ/Publish/Core/Repository/ContentService.php @@ -1171,7 +1171,16 @@ public function updateContent(APIVersionInfo $versionInfo, APIContentUpdateStruc } $mainLanguageCode = $content->contentInfo->mainLanguageCode; - $languageCodes = $this->getLanguageCodesForUpdate($contentUpdateStruct, $content); + if ($contentUpdateStruct->initialLanguageCode === null) { + $contentUpdateStruct->initialLanguageCode = $mainLanguageCode; + } + + $allLanguageCodes = $this->getLanguageCodesForUpdate($contentUpdateStruct, $content); + foreach ($allLanguageCodes as $languageCode) { + $this->persistenceHandler->contentLanguageHandler()->loadByLanguageCode($languageCode); + } + + $updatedLanguageCodes = $this->getUpdatedLanguageCodes($contentUpdateStruct); $contentType = $this->repository->getContentTypeService()->loadContentType( $content->contentInfo->contentTypeId ); @@ -1193,9 +1202,10 @@ public function updateContent(APIVersionInfo $versionInfo, APIContentUpdateStruc $fieldDefinition->fieldTypeIdentifier ); - foreach ($languageCodes as $languageCode) { + foreach ($allLanguageCodes as $languageCode) { $isCopied = $isEmpty = $isRetained = false; $isLanguageNew = !in_array($languageCode, $content->versionInfo->languageCodes); + $isLanguageUpdated = in_array($languageCode, $updatedLanguageCodes); $valueLanguageCode = $fieldDefinition->isTranslatable ? $languageCode : $mainLanguageCode; $isFieldUpdated = isset($fields[$fieldDefinition->identifier][$valueLanguageCode]); $isProcessed = isset($fieldValues[$fieldDefinition->identifier][$valueLanguageCode]); @@ -1216,7 +1226,7 @@ public function updateContent(APIVersionInfo $versionInfo, APIContentUpdateStruc if ($fieldType->isEmptyValue($fieldValue)) { $isEmpty = true; - if ($fieldDefinition->isRequired) { + if ($isLanguageUpdated && $fieldDefinition->isRequired) { $allFieldErrors[$fieldDefinition->id][$languageCode] = new ValidationError( "Value for required field definition '%identifier%' with language '%languageCode%' is empty", null, @@ -1224,7 +1234,7 @@ public function updateContent(APIVersionInfo $versionInfo, APIContentUpdateStruc 'empty' ); } - } else { + } elseif ($isLanguageUpdated) { $fieldErrors = $fieldType->validate( $fieldDefinition, $fieldValue @@ -1275,7 +1285,7 @@ public function updateContent(APIVersionInfo $versionInfo, APIContentUpdateStruc 'name' => $this->nameSchemaService->resolveNameSchema( $content, $fieldValues, - $languageCodes, + $allLanguageCodes, $contentType ), 'creatorId' => $contentUpdateStruct->creatorId ?: $this->repository->getCurrentUserReference()->getUserId(), @@ -1314,6 +1324,34 @@ public function updateContent(APIVersionInfo $versionInfo, APIContentUpdateStruc ); } + /** + * Returns only updated language codes. + * + * @param \eZ\Publish\API\Repository\Values\Content\ContentUpdateStruct $contentUpdateStruct + * + * @return array + */ + private function getUpdatedLanguageCodes(APIContentUpdateStruct $contentUpdateStruct) + { + $languageCodes = [ + $contentUpdateStruct->initialLanguageCode => true, + ]; + + foreach ($contentUpdateStruct->fields as $field) { + if ($field->languageCode === null || isset($languageCodes[$field->languageCode])) { + continue; + } + +// dump($field->fieldDefIdentifier, $field->languageCode); + + $languageCodes[$field->languageCode] = true; + } + +// dump(array_keys($languageCodes)); + + return array_keys($languageCodes); + } + /** * Returns all language codes used in given $fields. * @@ -1326,26 +1364,12 @@ public function updateContent(APIVersionInfo $versionInfo, APIContentUpdateStruc */ protected function getLanguageCodesForUpdate(APIContentUpdateStruct $contentUpdateStruct, APIContent $content) { - if ($contentUpdateStruct->initialLanguageCode !== null) { - $this->persistenceHandler->contentLanguageHandler()->loadByLanguageCode( - $contentUpdateStruct->initialLanguageCode - ); - } else { - $contentUpdateStruct->initialLanguageCode = $content->contentInfo->mainLanguageCode; - } - $languageCodes = array_fill_keys($content->versionInfo->languageCodes, true); $languageCodes[$contentUpdateStruct->initialLanguageCode] = true; - foreach ($contentUpdateStruct->fields as $field) { - if ($field->languageCode === null || isset($languageCodes[$field->languageCode])) { - continue; - } - - $this->persistenceHandler->contentLanguageHandler()->loadByLanguageCode( - $field->languageCode - ); - $languageCodes[$field->languageCode] = true; + $updatedLanguageCodes = $this->getUpdatedLanguageCodes($contentUpdateStruct); + foreach ($updatedLanguageCodes as $languageCode) { + $languageCodes[$languageCode] = true; } return array_keys($languageCodes); diff --git a/eZ/Publish/Core/Repository/Helper/RelationProcessor.php b/eZ/Publish/Core/Repository/Helper/RelationProcessor.php index 5256a8eefd..1392df597c 100644 --- a/eZ/Publish/Core/Repository/Helper/RelationProcessor.php +++ b/eZ/Publish/Core/Repository/Helper/RelationProcessor.php @@ -8,12 +8,15 @@ */ namespace eZ\Publish\Core\Repository\Helper; +use eZ\Publish\API\Repository\Exceptions\NotFoundException; use eZ\Publish\SPI\Persistence\Handler; use eZ\Publish\API\Repository\Values\ContentType\ContentType; use eZ\Publish\Core\Repository\Values\Content\Relation; use eZ\Publish\Core\FieldType\Value as BaseValue; use eZ\Publish\SPI\FieldType\FieldType as SPIFieldType; use eZ\Publish\SPI\Persistence\Content\Relation\CreateStruct as SPIRelationCreateStruct; +use Psr\Log\LoggerAwareTrait; +use Psr\Log\NullLogger; /** * RelationProcessor is an internal service used for handling field relations upon Content creation or update. @@ -22,6 +25,8 @@ */ class RelationProcessor { + use LoggerAwareTrait; + /** * @var \eZ\Publish\SPI\Persistence\Handler */ @@ -35,6 +40,7 @@ class RelationProcessor public function __construct(Handler $handler) { $this->persistenceHandler = $handler; + $this->logger = new NullLogger(); } /** @@ -70,12 +76,19 @@ public function appendFieldRelations( if (isset($destinationIds['locationIds'])) { foreach ($destinationIds['locationIds'] as $locationId) { - if (!isset($locationIdToContentIdMapping[$locationId])) { - $location = $this->persistenceHandler->locationHandler()->load($locationId); - $locationIdToContentIdMapping[$locationId] = $location->contentId; - } + try { + if (!isset($locationIdToContentIdMapping[$locationId])) { + $location = $this->persistenceHandler->locationHandler()->load($locationId); + $locationIdToContentIdMapping[$locationId] = $location->contentId; + } - $relations[$relationType][$locationIdToContentIdMapping[$locationId]] = true; + $relations[$relationType][$locationIdToContentIdMapping[$locationId]] = true; + } catch (NotFoundException $e) { + $this->logger->error('Invalid relation: destination location not found', [ + 'fieldDefinitionId' => $fieldDefinitionId, + 'locationId' => $locationId, + ]); + } } } diff --git a/eZ/Publish/Core/Repository/Repository.php b/eZ/Publish/Core/Repository/Repository.php index 283182b28d..d7e0c3b873 100644 --- a/eZ/Publish/Core/Repository/Repository.php +++ b/eZ/Publish/Core/Repository/Repository.php @@ -12,6 +12,7 @@ use eZ\Publish\API\Repository\Values\User\UserReference as APIUserReference; use eZ\Publish\Core\Base\Exceptions\InvalidArgumentValue; use eZ\Publish\Core\Base\Exceptions\InvalidArgumentType; +use eZ\Publish\Core\Repository\Helper\RelationProcessor; use eZ\Publish\Core\Repository\Permission\CachedPermissionService; use eZ\Publish\Core\Repository\Permission\PermissionCriterionResolver; use eZ\Publish\Core\Repository\Values\User\UserReference; @@ -260,12 +261,14 @@ public function __construct( PersistenceHandler $persistenceHandler, SearchHandler $searchHandler, BackgroundIndexer $backgroundIndexer, + RelationProcessor $relationProcessor, array $serviceSettings = array(), APIUserReference $user = null ) { $this->persistenceHandler = $persistenceHandler; $this->searchHandler = $searchHandler; $this->backgroundIndexer = $backgroundIndexer; + $this->relationProcessor = $relationProcessor; $this->serviceSettings = $serviceSettings + array( 'content' => array(), 'contentType' => array(), @@ -860,12 +863,6 @@ public function getNameSchemaService() */ protected function getRelationProcessor() { - if ($this->relationProcessor !== null) { - return $this->relationProcessor; - } - - $this->relationProcessor = new Helper\RelationProcessor($this->persistenceHandler); - return $this->relationProcessor; } diff --git a/eZ/Publish/Core/Repository/Tests/Service/Mock/Base.php b/eZ/Publish/Core/Repository/Tests/Service/Mock/Base.php index 626bac7b64..fce26167b3 100644 --- a/eZ/Publish/Core/Repository/Tests/Service/Mock/Base.php +++ b/eZ/Publish/Core/Repository/Tests/Service/Mock/Base.php @@ -7,6 +7,7 @@ namespace eZ\Publish\Core\Repository\Tests\Service\Mock; use eZ\Publish\Core\Base\Tests\PHPUnit5CompatTrait; +use eZ\Publish\Core\Repository\Helper\RelationProcessor; use eZ\Publish\Core\Search\Common\BackgroundIndexer\NullIndexer; use PHPUnit\Framework\TestCase; use eZ\Publish\Core\Repository\Repository; @@ -60,6 +61,7 @@ protected function getRepository(array $serviceSettings = array()) $this->getPersistenceMock(), $this->getSPIMockHandler('Search\\Handler'), new NullIndexer(), + $this->getRelationProcessorMock(), $serviceSettings, $this->getStubbedUser(14) ); @@ -199,6 +201,16 @@ protected function getPersistenceMock() return $this->persistenceMock; } + protected function getRelationProcessorMock() + { + return $this->getMock(RelationProcessor::class, + array(), + array(), + '', + false + ); + } + /** * Returns a SPI Handler mock. * diff --git a/eZ/Publish/Core/Repository/Tests/Service/Mock/ContentTest.php b/eZ/Publish/Core/Repository/Tests/Service/Mock/ContentTest.php index 4698bb47d5..6221e31fe9 100644 --- a/eZ/Publish/Core/Repository/Tests/Service/Mock/ContentTest.php +++ b/eZ/Publish/Core/Repository/Tests/Service/Mock/ContentTest.php @@ -4802,7 +4802,6 @@ public function assertForTestUpdateContentRequiredField( /** @var \PHPUnit_Framework_MockObject_MockObject $languageHandlerMock */ $languageHandlerMock = $this->getPersistenceMock()->contentLanguageHandler(); $contentTypeServiceMock = $this->getContentTypeServiceMock(); - $fieldTypeServiceMock = $this->getFieldTypeServiceMock(); $fieldTypeMock = $this->createMock('eZ\\Publish\\SPI\\FieldType\\FieldType'); $existingLanguageCodes = array_map( function (Field $field) { @@ -5081,44 +5080,32 @@ function () { $languageCodes ); $allFieldErrors = array(); - $validateCount = 0; $emptyValue = self::EMPTY_FIELD_VALUE; - foreach ($contentType->getFieldDefinitions() as $fieldDefinition) { - foreach ($fieldValues[$fieldDefinition->identifier] as $languageCode => $value) { - $fieldTypeMock->expects($this->at($validateCount++)) - ->method('acceptValue') - ->will( - $this->returnCallback( - function ($valueString) { - return new ValueStub($valueString); - } - ) - ); - - $fieldTypeMock->expects($this->at($validateCount++)) - ->method('isEmptyValue') - ->will( - $this->returnCallback( - function (ValueStub $value) use ($emptyValue) { - return $emptyValue === (string)$value; - } - ) - ); - if (self::EMPTY_FIELD_VALUE === (string)$value) { - continue; - } + $fieldTypeMock->expects($this->exactly(count($fieldValues) * count($languageCodes))) + ->method('acceptValue') + ->will( + $this->returnCallback( + function ($valueString) { + return new ValueStub($valueString); + } + ) + ); - $fieldTypeMock->expects($this->at($validateCount++)) - ->method('validate') - ->with( - $this->equalTo($fieldDefinition), - $this->equalTo($value) - )->will($this->returnArgument(1)); + $fieldTypeMock->expects($this->exactly(count($fieldValues) * count($languageCodes))) + ->method('isEmptyValue') + ->will( + $this->returnCallback( + function (ValueStub $value) use ($emptyValue) { + return $emptyValue === (string)$value; + } + ) + ); - $allFieldErrors[$fieldDefinition->id][$languageCode] = $value; - } - } + $fieldTypeMock + ->expects($this->any()) + ->method('validate') + ->willReturnArgument(1); $this->getFieldTypeRegistryMock()->expects($this->any()) ->method('getFieldType') @@ -5136,7 +5123,124 @@ function (ValueStub $value) use ($emptyValue) { public function providerForTestUpdateContentThrowsContentFieldValidationException() { - return $this->providerForTestUpdateContentNonRedundantFieldSetComplex(); + $allFieldErrors = [ + [ + 'fieldDefinitionId1' => [ + 'eng-GB' => 'newValue1-eng-GB', + 'eng-US' => 'newValue1-eng-GB', + ], + 'fieldDefinitionId2' => [ + 'eng-GB' => 'initialValue2', + ], + 'fieldDefinitionId3' => [ + 'eng-GB' => 'initialValue3', + 'eng-US' => 'initialValue3', + ], + 'fieldDefinitionId4' => [ + 'eng-GB' => 'initialValue4', + 'eng-US' => 'newValue4', + ], + ], + [ + 'fieldDefinitionId1' => [ + 'eng-GB' => 'newValue1-eng-GB', + 'eng-US' => 'newValue1-eng-GB', + ], + 'fieldDefinitionId2' => [ + 'eng-GB' => 'initialValue2', + ], + 'fieldDefinitionId3' => [ + 'eng-GB' => 'initialValue3', + 'eng-US' => 'initialValue3', + ], + 'fieldDefinitionId4' => [ + 'eng-GB' => 'initialValue4', + 'eng-US' => 'newValue4', + ], + ], + [ + 'fieldDefinitionId1' => [ + 'eng-GB' => 'newValue1-eng-GB', + 'eng-US' => 'newValue1-eng-GB', + ], + 'fieldDefinitionId2' => [ + 'eng-GB' => 'initialValue2', + 'eng-US' => 'newValue2', + ], + 'fieldDefinitionId3' => [ + 'eng-GB' => 'initialValue3', + 'eng-US' => 'initialValue3', + ], + 'fieldDefinitionId4' => [ + 'eng-GB' => 'initialValue4', + 'eng-US' => 'defaultValue4', + ], + ], + [ + 'fieldDefinitionId1' => [ + 'eng-GB' => 'newValue1-eng-GB', + 'eng-US' => 'newValue1-eng-GB', + ], + 'fieldDefinitionId2' => [ + 'eng-GB' => 'initialValue2', + 'eng-US' => 'newValue2', + ], + 'fieldDefinitionId3' => [ + 'eng-GB' => 'initialValue3', + 'eng-US' => 'initialValue3', + ], + 'fieldDefinitionId4' => [ + 'eng-GB' => 'initialValue4', + 'eng-US' => 'defaultValue4', + ], + ], + [ + 'fieldDefinitionId1' => [ + 'eng-GB' => 'newValue1-eng-GB', + 'ger-DE' => 'newValue1-eng-GB', + 'eng-US' => 'newValue1-eng-GB', + ], + 'fieldDefinitionId2' => [ + 'eng-GB' => 'initialValue2', + 'eng-US' => 'newValue2', + ], + 'fieldDefinitionId3' => [ + 'eng-GB' => 'initialValue3', + 'ger-DE' => 'initialValue3', + 'eng-US' => 'initialValue3', + ], + 'fieldDefinitionId4' => [ + 'eng-GB' => 'initialValue4', + 'eng-US' => 'defaultValue4', + 'ger-DE' => 'defaultValue4', + ], + ], + [ + 'fieldDefinitionId1' => [ + 'eng-US' => 'newValue1-eng-GB', + 'ger-DE' => 'newValue1-eng-GB', + ], + 'fieldDefinitionId2' => [ + 'eng-US' => 'newValue2', + ], + 'fieldDefinitionId3' => [ + 'ger-DE' => 'initialValue3', + 'eng-US' => 'initialValue3', + ], + 'fieldDefinitionId4' => [ + 'ger-DE' => 'defaultValue4', + 'eng-US' => 'defaultValue4', + ], + ], + ]; + + $data = $this->providerForTestUpdateContentNonRedundantFieldSetComplex(); + $count = count($data); + for ($i = 0; $i < $count; ++$i) { + $data[$i][] = $allFieldErrors[$i]; + } + + return $data; } /** @@ -5149,10 +5253,10 @@ public function providerForTestUpdateContentThrowsContentFieldValidationExceptio * @expectedException \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException * @expectedExceptionMessage Content fields did not validate */ - public function testUpdateContentThrowsContentFieldValidationException($initialLanguageCode, $structFields) + public function testUpdateContentThrowsContentFieldValidationException($initialLanguageCode, $structFields, $spiField, $allFieldErrors) { list($existingFields, $fieldDefinitions) = $this->fixturesForTestUpdateContentNonRedundantFieldSetComplex(); - list($versionInfo, $contentUpdateStruct, $allFieldErrors) = + list($versionInfo, $contentUpdateStruct) = $this->assertForTestUpdateContentThrowsContentFieldValidationException( $initialLanguageCode, $structFields, diff --git a/eZ/Publish/Core/Repository/Tests/Service/Mock/RelationProcessorTest.php b/eZ/Publish/Core/Repository/Tests/Service/Mock/RelationProcessorTest.php index 4d7ef92284..a68cc93ad8 100644 --- a/eZ/Publish/Core/Repository/Tests/Service/Mock/RelationProcessorTest.php +++ b/eZ/Publish/Core/Repository/Tests/Service/Mock/RelationProcessorTest.php @@ -8,13 +8,17 @@ */ namespace eZ\Publish\Core\Repository\Tests\Service\Mock; +use eZ\Publish\API\Repository\Exceptions\NotFoundException; use eZ\Publish\API\Repository\Values\ContentType\ContentType; +use eZ\Publish\Core\FieldType\Value; use eZ\Publish\Core\Repository\Tests\Service\Mock\Base as BaseServiceMockTest; use eZ\Publish\Core\Repository\Values\ContentType\FieldDefinition; use eZ\Publish\API\Repository\Values\Content\Relation; use eZ\Publish\API\Repository\Values\Content\ContentInfo; +use eZ\Publish\SPI\FieldType\FieldType; use eZ\Publish\SPI\Persistence\Content\Relation\CreateStruct; use eZ\Publish\SPI\Persistence\Content\Location; +use Psr\Log\LoggerInterface; /** * Mock Test case for RelationProcessor service. @@ -259,6 +263,58 @@ public function testAppendFieldRelationsLocationMappingWorks() ); } + public function testAppendFieldRelationsLogMissingLocations() + { + $fieldValueMock = $this->getMockForAbstractClass(Value::class); + $fieldTypeMock = $this->getMock(FieldType::class); + + $locationId = 123465; + $fieldDefinitionId = 42; + + $fieldTypeMock + ->expects($this->once()) + ->method('getRelations') + ->with($this->equalTo($fieldValueMock)) + ->will( + $this->returnValue( + [ + Relation::LINK => [ + 'locationIds' => [$locationId], + ], + ] + ) + ); + + $locationHandler = $this->getPersistenceMock()->locationHandler(); + $locationHandler + ->expects($this->any()) + ->method('load') + ->with($locationId) + ->willThrowException($this->getMock(NotFoundException::class)); + + $logger = $this->getMock(LoggerInterface::class); + $logger + ->expects($this->once()) + ->method('error') + ->with('Invalid relation: destination location not found', [ + 'fieldDefinitionId' => $fieldDefinitionId, + 'locationId' => $locationId, + ]); + + $relations = []; + $locationIdToContentIdMapping = []; + + $relationProcessor = $this->getPartlyMockedRelationProcessor(); + $relationProcessor->setLogger($logger); + $relationProcessor->appendFieldRelations( + $relations, + $locationIdToContentIdMapping, + $fieldTypeMock, + $fieldValueMock, + $fieldDefinitionId + ); + } + /** * Test for the processFieldRelations() method. * diff --git a/eZ/Publish/Core/settings/repository/inner.yml b/eZ/Publish/Core/settings/repository/inner.yml index 7b32187611..0d61f2a869 100644 --- a/eZ/Publish/Core/settings/repository/inner.yml +++ b/eZ/Publish/Core/settings/repository/inner.yml @@ -39,6 +39,7 @@ services: - "@ezpublish.api.persistence_handler" - "@ezpublish.spi.search" - '@ezpublish.search.background_indexer' + - '@ezpublish.repository.relation_processor' lazy: true ezpublish.api.service.inner_content: @@ -126,3 +127,10 @@ services: ezpublish.search.background_indexer: class: eZ\Publish\Core\Search\Common\BackgroundIndexer\NullIndexer + + ezpublish.repository.relation_processor: + class: eZ\Publish\Core\Repository\Helper\RelationProcessor + arguments: + - '@ezpublish.api.persistence_handler' + calls: + - ['setLogger', ['@?logger']]