From 0f7966d9a91ad63895f1433b0936bbfe58463af4 Mon Sep 17 00:00:00 2001 From: Nattfarinn Date: Tue, 23 Apr 2024 13:36:46 +0200 Subject: [PATCH] fix: Code Review --- .../Persistence/Legacy/Content/Mapper.php | 50 ++- .../Legacy/Tests/Content/MapperTest.php | 39 +- .../Tests/Content/StorageHandlerTest.php | 39 +- .../Legacy/Tests/Content/AbstractTestCase.php | 2 +- .../storage_engines/legacy/content.yml | 6 +- .../Event/Mapper/ResolveMissingFieldEvent.php | 8 +- .../FieldType/DefaultDataFieldStorage.php | 5 +- .../Mapper/ResolveVirtualFieldSubscriber.php | 10 +- .../ResolveVirtualFieldSubscriberTest.php | 381 ++++++++++++++++++ 9 files changed, 455 insertions(+), 85 deletions(-) create mode 100644 tests/lib/Persistence/Legacy/Content/Mapper/ResolveVirtualFieldSubscriberTest.php diff --git a/eZ/Publish/Core/Persistence/Legacy/Content/Mapper.php b/eZ/Publish/Core/Persistence/Legacy/Content/Mapper.php index fe319d365e..e1880eb79a 100644 --- a/eZ/Publish/Core/Persistence/Legacy/Content/Mapper.php +++ b/eZ/Publish/Core/Persistence/Legacy/Content/Mapper.php @@ -27,39 +27,37 @@ * Performs mapping of Content objects. * * @phpstan-type TVersionedLanguageFieldDefinitionsMap array< - int, array< - int, array< - string, array< - int, \eZ\Publish\SPI\Persistence\Content\Type\FieldDefinition, - > - > - > - > + * int, array< + * int, array< + * string, array< + * int, \eZ\Publish\SPI\Persistence\Content\Type\FieldDefinition, + * > + * > + * > + * > * @phpstan-type TVersionedFieldMap array< - int, array< - int, array< - int, \eZ\Publish\SPI\Persistence\Content\Field, - > - > - > + * int, array< + * int, array< + * int, \eZ\Publish\SPI\Persistence\Content\Field, + * > + * > + * > * @phpstan-type TVersionedNameMap array< - int, array< - int, array< - string, array - > - > - > + * int, array< + * int, array< + * string, array + * > + * > + * > * @phpstan-type TContentInfoMap array * @phpstan-type TVersionInfoMap array< - int, array< - int, \eZ\Publish\SPI\Persistence\Content\VersionInfo, - > - > + * int, array< + * int, \eZ\Publish\SPI\Persistence\Content\VersionInfo, + * > + * > */ class Mapper { - public const EMPTY_FIELD_ID = -1; - /** * FieldValue converter registry. * diff --git a/eZ/Publish/Core/Persistence/Legacy/Tests/Content/MapperTest.php b/eZ/Publish/Core/Persistence/Legacy/Tests/Content/MapperTest.php index 68e506095e..f4e59b9b9b 100644 --- a/eZ/Publish/Core/Persistence/Legacy/Tests/Content/MapperTest.php +++ b/eZ/Publish/Core/Persistence/Legacy/Tests/Content/MapperTest.php @@ -8,6 +8,7 @@ use function count; use eZ\Publish\API\Repository\Values\Content\Relation as RelationValue; +use eZ\Publish\Core\Persistence\Legacy\Bookmark\Handler; use eZ\Publish\Core\Persistence\Legacy\Content\FieldValue\Converter; use eZ\Publish\Core\Persistence\Legacy\Content\FieldValue\ConverterRegistry as Registry; use eZ\Publish\Core\Persistence\Legacy\Content\Gateway; @@ -97,8 +98,8 @@ public function testCreateVersionInfoForContent() ], $versionInfo ); - $this->assertGreaterThanOrEqual($time, $versionInfo->creationDate); - $this->assertGreaterThanOrEqual($time, $versionInfo->modificationDate); + self::assertGreaterThanOrEqual($time, $versionInfo->creationDate); + self::assertGreaterThanOrEqual($time, $versionInfo->modificationDate); } /** @@ -162,7 +163,7 @@ public function testConvertToStorageValue() ); $res = $mapper->convertToStorageValue($field); - $this->assertInstanceOf( + self::assertInstanceOf( StorageFieldValue::class, $res ); @@ -203,7 +204,7 @@ public function testExtractContentFromRows() $expected = [$this->getContentExtractReference()]; - $this->assertEquals( + self::assertEquals( $expected, $result ); @@ -248,7 +249,7 @@ public function testExtractContentFromRowsWithNewFieldDefinitions(): void 'versionNo' => 2, ]); - $this->assertEquals( + self::assertEquals( [ $expectedContent, ], @@ -296,7 +297,7 @@ static function (Content\Type\FieldDefinition $fieldDefinition): bool { }) ); - $this->assertEquals( + self::assertEquals( [ $expectedContent, ], @@ -330,25 +331,25 @@ public function testExtractContentFromRowsMultipleVersions() ); $result = $mapper->extractContentFromRows($rowsFixture, $nameRowsFixture); - $this->assertCount( + self::assertCount( 2, $result ); - $this->assertEquals( + self::assertEquals( 11, $result[0]->versionInfo->contentInfo->id ); - $this->assertEquals( + self::assertEquals( 11, $result[1]->versionInfo->contentInfo->id ); - $this->assertEquals( + self::assertEquals( 1, $result[0]->versionInfo->versionNo ); - $this->assertEquals( + self::assertEquals( 2, $result[1]->versionInfo->versionNo ); @@ -390,7 +391,7 @@ public function testCreateCreateStructFromContent() $struct = $mapper->createCreateStructFromContent($content); - $this->assertInstanceOf(CreateStruct::class, $struct); + self::assertInstanceOf(CreateStruct::class, $struct); return [ 'original' => $content, @@ -429,7 +430,7 @@ public function testCreateCreateStructFromContentBasicProperties($data) */ public function testCreateCreateStructFromContentParentLocationsEmpty($data) { - $this->assertEquals( + self::assertEquals( [], $data['result']->locations ); @@ -441,7 +442,7 @@ public function testCreateCreateStructFromContentParentLocationsEmpty($data) */ public function testCreateCreateStructFromContentFieldCount($data) { - $this->assertEquals( + self::assertEquals( count($data['original']->fields), count($data['result']->fields) ); @@ -454,7 +455,7 @@ public function testCreateCreateStructFromContentFieldCount($data) public function testCreateCreateStructFromContentFieldsNoId($data) { foreach ($data['result']->fields as $field) { - $this->assertNull($field->id); + self::assertNull($field->id); } } @@ -466,7 +467,7 @@ public function testExtractRelationsFromRows() $res = $mapper->extractRelationsFromRows($rows); - $this->assertEquals( + self::assertEquals( $this->getRelationExtractReference(), $res ); @@ -485,7 +486,7 @@ public function testCreateCreateStructFromContentWithPreserveOriginalLanguage() $struct = $mapper->createCreateStructFromContent($content, true); - $this->assertInstanceOf(CreateStruct::class, $struct); + self::assertInstanceOf(CreateStruct::class, $struct); $this->assertStructsEqual($content->versionInfo->contentInfo, $struct, ['sectionId', 'ownerId']); self::assertNotEquals($content->versionInfo->contentInfo->remoteId, $struct->remoteId); self::assertSame($content->versionInfo->contentInfo->contentTypeId, $struct->typeId); @@ -719,7 +720,7 @@ protected function getEventDispatcher(): EventDispatcherInterface $eventDispatcher->addSubscriber( new ResolveVirtualFieldSubscriber( $this->getValueConverterRegistryMock(), - new StorageRegistry([]), + $this->createMock(StorageRegistry::class), $this->createMock(Gateway::class) ) ); @@ -790,7 +791,7 @@ static function ($languageCode) use ($languages) { /** * @return \eZ\Publish\SPI\Persistence\Content\Type\Handler&\PHPUnit\Framework\MockObject\MockObject */ - protected function getContentTypeHandler() + protected function getContentTypeHandler(): Content\Type\Handler { return $this->createMock(Content\Type\Handler::class); } diff --git a/eZ/Publish/Core/Persistence/Legacy/Tests/Content/StorageHandlerTest.php b/eZ/Publish/Core/Persistence/Legacy/Tests/Content/StorageHandlerTest.php index 899d108913..72b6ea4598 100644 --- a/eZ/Publish/Core/Persistence/Legacy/Tests/Content/StorageHandlerTest.php +++ b/eZ/Publish/Core/Persistence/Legacy/Tests/Content/StorageHandlerTest.php @@ -16,6 +16,8 @@ /** * Test case for Content Handler. + * + * @covers \eZ\Publish\Core\Persistence\Legacy\Content\StorageHandler */ class StorageHandlerTest extends TestCase { @@ -47,10 +49,7 @@ class StorageHandlerTest extends TestCase */ protected $versionInfoMock; - /** - * @covers \eZ\Publish\Core\Persistence\Legacy\Content\StorageHandler::storeFieldData - */ - public function testStoreFieldData() + public function testStoreFieldData(): void { $storageMock = $this->getStorageMock(); $storageRegistryMock = $this->getStorageRegistryMock(); @@ -76,10 +75,7 @@ public function testStoreFieldData() $handler->storeFieldData($this->getVersionInfoMock(), $field); } - /** - * @covers \eZ\Publish\Core\Persistence\Legacy\Content\StorageHandler::getFieldData - */ - public function testGetFieldDataAvailable() + public function testGetFieldDataAvailable(): void { $storageMock = $this->getStorageMock(); $storageRegistryMock = $this->getStorageRegistryMock(); @@ -109,10 +105,7 @@ public function testGetFieldDataAvailable() $handler->getFieldData($this->getVersionInfoMock(), $field); } - /** - * @covers \eZ\Publish\Core\Persistence\Legacy\Content\StorageHandler::getFieldData - */ - public function testGetFieldDataNotAvailable() + public function testGetFieldDataNotAvailable(): void { $storageMock = $this->getStorageMock(); $storageRegistryMock = $this->getStorageRegistryMock(); @@ -137,10 +130,7 @@ public function testGetFieldDataNotAvailable() $handler->getFieldData($this->getVersionInfoMock(), $field); } - /** - * @covers \eZ\Publish\Core\Persistence\Legacy\Content\StorageHandler::getFieldData - */ - public function testGetFieldDataNotAvailableForVirtualField() + public function testGetFieldDataNotAvailableForVirtualField(): void { $storageMock = $this->getStorageMock(); $storageRegistryMock = $this->getStorageRegistryMock(); @@ -164,10 +154,7 @@ public function testGetFieldDataNotAvailableForVirtualField() $handler->getFieldData($this->getVersionInfoMock(), $field); } - /** - * @covers \eZ\Publish\Core\Persistence\Legacy\Content\StorageHandler::deleteFieldData - */ - public function testDeleteFieldData() + public function testDeleteFieldData(): void { $storageMock = $this->getStorageMock(); $storageRegistryMock = $this->getStorageRegistryMock(); @@ -194,7 +181,7 @@ public function testDeleteFieldData() * * @return \eZ\Publish\Core\Persistence\Legacy\Content\StorageHandler */ - protected function getStorageHandler() + protected function getStorageHandler(): StorageHandler { if (!isset($this->storageHandler)) { $this->storageHandler = new StorageHandler( @@ -209,9 +196,9 @@ protected function getStorageHandler() /** * Returns a context mock. * - * @return array + * @return int[] */ - protected function getContextMock() + protected function getContextMock(): array { return [23, 42]; } @@ -221,7 +208,7 @@ protected function getContextMock() * * @return \eZ\Publish\Core\Persistence\Legacy\Content\StorageRegistry */ - protected function getStorageRegistryMock() + protected function getStorageRegistryMock(): StorageRegistry { if (!isset($this->storageRegistryMock)) { $this->storageRegistryMock = $this->getMockBuilder(StorageRegistry::class) @@ -238,7 +225,7 @@ protected function getStorageRegistryMock() * * @return \eZ\Publish\SPI\FieldType\FieldStorage */ - protected function getStorageMock() + protected function getStorageMock(): FieldStorage { if (!isset($this->storageMock)) { $this->storageMock = $this->createMock(FieldStorage::class); @@ -247,7 +234,7 @@ protected function getStorageMock() return $this->storageMock; } - protected function getVersionInfoMock() + protected function getVersionInfoMock(): VersionInfo { if (!isset($this->versionInfoMock)) { $this->versionInfoMock = $this->createMock(VersionInfo::class); diff --git a/eZ/Publish/Core/Search/Legacy/Tests/Content/AbstractTestCase.php b/eZ/Publish/Core/Search/Legacy/Tests/Content/AbstractTestCase.php index eb0ec67daf..ab25ca43a7 100644 --- a/eZ/Publish/Core/Search/Legacy/Tests/Content/AbstractTestCase.php +++ b/eZ/Publish/Core/Search/Legacy/Tests/Content/AbstractTestCase.php @@ -125,7 +125,7 @@ protected function getEventDispatcher(): EventDispatcherInterface $eventDispatcher->addSubscriber( new ResolveVirtualFieldSubscriber( $this->getConverterRegistry(), - new StorageRegistry([]), + $this->createMock(StorageRegistry::class), $this->createMock(Gateway::class) ) ); diff --git a/eZ/Publish/Core/settings/storage_engines/legacy/content.yml b/eZ/Publish/Core/settings/storage_engines/legacy/content.yml index 29374fafa2..f7dd8b7dd0 100644 --- a/eZ/Publish/Core/settings/storage_engines/legacy/content.yml +++ b/eZ/Publish/Core/settings/storage_engines/legacy/content.yml @@ -14,9 +14,9 @@ services: Ibexa\Core\Persistence\Legacy\Content\Mapper\ResolveVirtualFieldSubscriber: arguments: - - "@ezpublish.persistence.legacy.field_value_converter.registry" - - "@ezpublish.persistence.external_storage_registry" - - "@ezpublish.persistence.legacy.content.gateway" + $converterRegistry: "@ezpublish.persistence.legacy.field_value_converter.registry" + $storageRegistry: "@ezpublish.persistence.external_storage_registry" + $contentGateway: "@ezpublish.persistence.legacy.content.gateway" tags: - { name: kernel.event_subscriber } diff --git a/src/contracts/Event/Mapper/ResolveMissingFieldEvent.php b/src/contracts/Event/Mapper/ResolveMissingFieldEvent.php index 0dc14deddd..af0f0c2282 100644 --- a/src/contracts/Event/Mapper/ResolveMissingFieldEvent.php +++ b/src/contracts/Event/Mapper/ResolveMissingFieldEvent.php @@ -22,12 +22,15 @@ final class ResolveMissingFieldEvent extends Event /** @var string */ private $languageCode; - /** @var array */ + /** @var array */ private $context; /** @var \eZ\Publish\SPI\Persistence\Content\Field|null */ private $field; + /** + * @param array $context + */ public function __construct( Content $content, FieldDefinition $fieldDefinition, @@ -56,6 +59,9 @@ public function getLanguageCode(): string return $this->languageCode; } + /** + * @return array + */ public function getContext(): array { return $this->context; diff --git a/src/contracts/FieldType/DefaultDataFieldStorage.php b/src/contracts/FieldType/DefaultDataFieldStorage.php index 5ec92f761a..7c8ae9967a 100644 --- a/src/contracts/FieldType/DefaultDataFieldStorage.php +++ b/src/contracts/FieldType/DefaultDataFieldStorage.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace Ibexa\Contracts\FieldType; +namespace Ibexa\Contracts\Core\FieldType; use eZ\Publish\SPI\Persistence\Content\Field; use eZ\Publish\SPI\Persistence\Content\VersionInfo; @@ -18,9 +18,6 @@ interface DefaultDataFieldStorage * $field->value is a {@link \eZ\Publish\SPI\Persistence\Content\FieldValue} object. * This value holds the data as a {@link \eZ\Publish\Core\FieldType\Value} based object, according to * the field type (e.g. for TextLine, it will be a {@link \eZ\Publish\Core\FieldType\TextLine\Value} object). - * - * @param \eZ\Publish\SPI\Persistence\Content\VersionInfo $versionInfo - * @param \eZ\Publish\SPI\Persistence\Content\Field $field */ public function getDefaultFieldData(VersionInfo $versionInfo, Field $field): void; } diff --git a/src/lib/Persistence/Legacy/Content/Mapper/ResolveVirtualFieldSubscriber.php b/src/lib/Persistence/Legacy/Content/Mapper/ResolveVirtualFieldSubscriber.php index c5d1d80cdb..2443586f34 100644 --- a/src/lib/Persistence/Legacy/Content/Mapper/ResolveVirtualFieldSubscriber.php +++ b/src/lib/Persistence/Legacy/Content/Mapper/ResolveVirtualFieldSubscriber.php @@ -19,7 +19,7 @@ use eZ\Publish\SPI\Persistence\Content\Type\FieldDefinition; use eZ\Publish\SPI\Persistence\Content\VersionInfo; use Ibexa\Contracts\Core\Event\Mapper\ResolveMissingFieldEvent; -use Ibexa\Contracts\FieldType\DefaultDataFieldStorage; +use Ibexa\Contracts\Core\FieldType\DefaultDataFieldStorage; use Symfony\Component\EventDispatcher\EventSubscriberInterface; final class ResolveVirtualFieldSubscriber implements EventSubscriberInterface @@ -82,7 +82,7 @@ public function persistExternalStorageField(ResolveMissingFieldEvent $event): vo { $field = $event->getField(); - if ($field && $field->id !== null) { + if ($field !== null && $field->id !== null) { // Not a virtual field return; } @@ -138,7 +138,7 @@ public function resolveVirtualExternalStorageField(ResolveMissingFieldEvent $eve { $field = $event->getField(); - if ($field && $field->id !== null) { + if ($field !== null && $field->id !== null) { // Not a virtual field return; } @@ -169,7 +169,7 @@ public function resolveVirtualExternalStorageField(ResolveMissingFieldEvent $eve } /** - * @throws \eZ\Publish\Core\Persistence\Legacy\Content\FieldValue\Converter\Exception\NotFound + * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException */ private function createEmptyField( VersionInfo $versionInfo, @@ -187,7 +187,7 @@ private function createEmptyField( } /** - * @throws \eZ\Publish\Core\Persistence\Legacy\Content\FieldValue\Converter\Exception\NotFound + * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException */ private function getDefaultValue(FieldDefinition $fieldDefinition): FieldValue { diff --git a/tests/lib/Persistence/Legacy/Content/Mapper/ResolveVirtualFieldSubscriberTest.php b/tests/lib/Persistence/Legacy/Content/Mapper/ResolveVirtualFieldSubscriberTest.php new file mode 100644 index 0000000000..b091612861 --- /dev/null +++ b/tests/lib/Persistence/Legacy/Content/Mapper/ResolveVirtualFieldSubscriberTest.php @@ -0,0 +1,381 @@ +getVersionInfo(); + + $content = new Content(); + $content->versionInfo = $versionInfo; + $content->fields = []; + + return $content; + } + + private function getVersionInfo(): VersionInfo + { + $versionInfo = new VersionInfo(); + $versionInfo->versionNo = 123; + + return $versionInfo; + } + + public function testResolveVirtualField(): void + { + $converterRegistry = $this->createMock(ConverterRegistry::class); + $converterRegistry->method('getConverter') + ->willReturn($this->createMock(Converter::class)); + + $storageRegistry = $this->createMock(StorageRegistry::class); + $storageRegistry->method('getStorage') + ->willReturn(new NullStorage()); + + $contentGateway = $this->createMock(ContentGateway::class); + $contentGateway->expects($this->never()) + ->method('insertNewField'); + + $eventDispatcher = new TraceableEventDispatcher( + new EventDispatcher(), + new Stopwatch() + ); + + $eventDispatcher->addSubscriber( + new ResolveVirtualFieldSubscriber( + $converterRegistry, + $storageRegistry, + $contentGateway + ) + ); + + $content = $this->getContent(); + $fieldDefinition = new FieldDefinition([ + 'id' => 123, + 'identifier' => 'example_field', + 'fieldType' => 'some_type', + 'defaultValue' => new Content\FieldValue(), + ]); + + $event = new ResolveMissingFieldEvent( + $content, + $fieldDefinition, + 'eng-GB' + ); + + $event = $eventDispatcher->dispatch($event); + + $expected = new Content\Field([ + 'id' => null, + 'fieldDefinitionId' => 123, + 'type' => 'some_type', + 'value' => new Content\FieldValue(), + 'languageCode' => 'eng-GB', + 'versionNo' => 123, + ]); + + self::assertEquals( + $expected, + $event->getField() + ); + + self::assertCount(3, $eventDispatcher->getCalledListeners()); + self::assertEquals( + [ + 'Ibexa\Core\Persistence\Legacy\Content\Mapper\ResolveVirtualFieldSubscriber::resolveVirtualField', + 'Ibexa\Core\Persistence\Legacy\Content\Mapper\ResolveVirtualFieldSubscriber::resolveVirtualExternalStorageField', + 'Ibexa\Core\Persistence\Legacy\Content\Mapper\ResolveVirtualFieldSubscriber::persistExternalStorageField', + ], + array_column($eventDispatcher->getCalledListeners(), 'pretty') + ); + } + + public function testResolveVirtualExternalStorageField(): void + { + $converterRegistry = $this->createMock(ConverterRegistry::class); + $converterRegistry->method('getConverter') + ->willReturn($this->createMock(Converter::class)); + + $storageRegistry = $this->createMock(StorageRegistry::class); + $storageRegistry->method('getStorage') + ->willReturn(new class() implements FieldStorage, DefaultDataFieldStorage { + public function getDefaultFieldData(VersionInfo $versionInfo, Field $field): void + { + $field->value->externalData = [ + 'some_default' => 'external_data', + ]; + } + + public function storeFieldData(VersionInfo $versionInfo, Field $field, array $context): void + { + } + + public function getFieldData(VersionInfo $versionInfo, Field $field, array $context): void + { + } + + public function deleteFieldData(VersionInfo $versionInfo, array $fieldIds, array $context): void + { + } + + public function hasFieldData(): void + { + } + + public function getIndexData(VersionInfo $versionInfo, Field $field, array $context): void + { + } + }); + + $eventDispatcher = new TraceableEventDispatcher( + new EventDispatcher(), + new Stopwatch() + ); + + $eventDispatcher->addSubscriber( + new ResolveVirtualFieldSubscriber( + $converterRegistry, + $storageRegistry, + $this->createMock(ContentGateway::class) + ) + ); + + $content = $this->getContent(); + $fieldDefinition = new FieldDefinition([ + 'id' => 123, + 'identifier' => 'example_field', + 'fieldType' => 'external_type_virtual', + 'defaultValue' => new Content\FieldValue(), + ]); + + $event = new ResolveMissingFieldEvent( + $content, + $fieldDefinition, + 'eng-GB' + ); + + $event = $eventDispatcher->dispatch($event); + + $expected = new Content\Field([ + 'id' => null, + 'fieldDefinitionId' => 123, + 'type' => 'external_type_virtual', + 'value' => new Content\FieldValue([ + 'externalData' => [ + 'some_default' => 'external_data', + ], + ]), + 'languageCode' => 'eng-GB', + 'versionNo' => 123, + ]); + + self::assertEquals( + $expected, + $event->getField() + ); + + self::assertCount(1, $eventDispatcher->getNotCalledListeners()); + self::assertEquals( + 'Ibexa\Core\Persistence\Legacy\Content\Mapper\ResolveVirtualFieldSubscriber::persistExternalStorageField', + $eventDispatcher->getNotCalledListeners()[0]['pretty'] + ); + } + + public function testPersistEmptyExternalStorageField(): void + { + $converterRegistry = $this->createMock(ConverterRegistry::class); + $converterRegistry->method('getConverter') + ->willReturn($this->createMock(Converter::class)); + + $storage = $this->createMock(FieldStorage::class); + $storage->expects($this->never()) + ->method('storeFieldData'); + + $storage->expects($this->once()) + ->method('getFieldData') + ->willReturnCallback(static function (VersionInfo $versionInfo, Field $field) { + $field->value->externalData = [ + 'some_default' => 'external_data', + ]; + }); + + $storageRegistry = $this->createMock(StorageRegistry::class); + $storageRegistry->method('getStorage') + ->willReturn($storage); + + $contentGateway = $this->createMock(ContentGateway::class); + $contentGateway->expects($this->once()) + ->method('insertNewField') + ->willReturn(567); + + $eventDispatcher = new TraceableEventDispatcher( + new EventDispatcher(), + new Stopwatch() + ); + + $eventDispatcher->addSubscriber( + new ResolveVirtualFieldSubscriber( + $converterRegistry, + $storageRegistry, + $contentGateway, + ) + ); + + $content = $this->getContent(); + $fieldDefinition = new FieldDefinition([ + 'id' => 123, + 'identifier' => 'example_field', + 'fieldType' => 'external_type', + 'defaultValue' => new Content\FieldValue(), + ]); + + $event = new ResolveMissingFieldEvent( + $content, + $fieldDefinition, + 'eng-GB' + ); + + $event = $eventDispatcher->dispatch($event); + + $expected = new Content\Field([ + 'id' => 567, + 'fieldDefinitionId' => 123, + 'type' => 'external_type', + 'value' => new Content\FieldValue([ + 'externalData' => [ + 'some_default' => 'external_data', + ], + ]), + 'languageCode' => 'eng-GB', + 'versionNo' => 123, + ]); + + self::assertEquals( + $expected, + $event->getField() + ); + + self::assertCount(3, $eventDispatcher->getCalledListeners()); + self::assertEquals( + [ + 'Ibexa\Core\Persistence\Legacy\Content\Mapper\ResolveVirtualFieldSubscriber::resolveVirtualField', + 'Ibexa\Core\Persistence\Legacy\Content\Mapper\ResolveVirtualFieldSubscriber::resolveVirtualExternalStorageField', + 'Ibexa\Core\Persistence\Legacy\Content\Mapper\ResolveVirtualFieldSubscriber::persistExternalStorageField', + ], + array_column($eventDispatcher->getCalledListeners(), 'pretty') + ); + } + + public function testPersistExternalStorageField(): void + { + $converterRegistry = $this->createMock(ConverterRegistry::class); + $converterRegistry->method('getConverter') + ->willReturn($this->createMock(Converter::class)); + + $storage = $this->createMock(FieldStorage::class); + $storage->expects($this->once()) + ->method('storeFieldData') + ->willReturnCallback(static function (VersionInfo $versionInfo, Field $field) { + $field->value->externalData = $field->value->data; + }); + + $storage->expects($this->once()) + ->method('getFieldData'); + + $storageRegistry = $this->createMock(StorageRegistry::class); + $storageRegistry->method('getStorage') + ->willReturn($storage); + + $contentGateway = $this->createMock(ContentGateway::class); + $contentGateway->expects($this->once()) + ->method('insertNewField') + ->willReturn(456); + + $eventDispatcher = new TraceableEventDispatcher( + new EventDispatcher(), + new Stopwatch() + ); + + $eventDispatcher->addSubscriber( + new ResolveVirtualFieldSubscriber( + $converterRegistry, + $storageRegistry, + $contentGateway, + ) + ); + + $content = $this->getContent(); + $fieldDefinition = new FieldDefinition([ + 'id' => 123, + 'identifier' => 'example_field', + 'fieldType' => 'external_type', + 'defaultValue' => new Content\FieldValue([ + 'data' => ['some_data' => 'to_be_stored'], + ]), + ]); + + $event = new ResolveMissingFieldEvent( + $content, + $fieldDefinition, + 'eng-GB' + ); + + $event = $eventDispatcher->dispatch($event); + + $expected = new Content\Field([ + 'id' => 456, + 'fieldDefinitionId' => 123, + 'type' => 'external_type', + 'value' => new Content\FieldValue([ + 'data' => [ + 'some_data' => 'to_be_stored', + ], + 'externalData' => [ + 'some_data' => 'to_be_stored', + ], + ]), + 'languageCode' => 'eng-GB', + 'versionNo' => 123, + ]); + + self::assertEquals( + $expected, + $event->getField() + ); + + self::assertCount(3, $eventDispatcher->getCalledListeners()); + self::assertEquals( + [ + 'Ibexa\Core\Persistence\Legacy\Content\Mapper\ResolveVirtualFieldSubscriber::resolveVirtualField', + 'Ibexa\Core\Persistence\Legacy\Content\Mapper\ResolveVirtualFieldSubscriber::resolveVirtualExternalStorageField', + 'Ibexa\Core\Persistence\Legacy\Content\Mapper\ResolveVirtualFieldSubscriber::persistExternalStorageField', + ], + array_column($eventDispatcher->getCalledListeners(), 'pretty') + ); + } +}