Skip to content

Commit

Permalink
fix: External Storage
Browse files Browse the repository at this point in the history
  • Loading branch information
Nattfarinn committed Apr 9, 2024
1 parent 2485639 commit e24c72b
Show file tree
Hide file tree
Showing 4 changed files with 246 additions and 51 deletions.
66 changes: 15 additions & 51 deletions eZ/Publish/Core/Persistence/Legacy/Content/Mapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
use eZ\Publish\SPI\Persistence\Content\Language\Handler as LanguageHandler;
use eZ\Publish\SPI\Persistence\Content\Relation;
use eZ\Publish\SPI\Persistence\Content\Relation\CreateStruct as RelationCreateStruct;
use eZ\Publish\SPI\Persistence\Content\Type\FieldDefinition;
use eZ\Publish\SPI\Persistence\Content\Type\Handler as ContentTypeHandler;
use eZ\Publish\SPI\Persistence\Content\VersionInfo;
use Ibexa\Contracts\Core\Event\Mapper\ResolveMissingFieldEvent;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

/**
* Mapper for Content Handler.
Expand Down Expand Up @@ -79,20 +80,20 @@ class Mapper
private $contentTypeHandler;

/**
* @var StorageRegistry
* @var EventDispatcherInterface
*/
private $storageRegistry;
private $eventDispatcher;

public function __construct(
Registry $converterRegistry,
LanguageHandler $languageHandler,
ContentTypeHandler $contentTypeHandler,
StorageRegistry $storageRegistry
EventDispatcherInterface $eventDispatcher
) {
$this->converterRegistry = $converterRegistry;
$this->languageHandler = $languageHandler;
$this->contentTypeHandler = $contentTypeHandler;
$this->storageRegistry = $storageRegistry;
$this->eventDispatcher = $eventDispatcher;
}

/**
Expand Down Expand Up @@ -319,19 +320,19 @@ private function buildContentObjects(
$missingVersionFieldDefinitions = $missingFieldDefinitions[$contentId][$versionId];
foreach ($missingVersionFieldDefinitions as $languageCode => $versionFieldDefinitions) {
foreach ($versionFieldDefinitions as $fieldDefinition) {
$emptyField = $this->createEmptyField(
$versionInfo,
$fieldDefinition,
$languageCode
$event = $this->eventDispatcher->dispatch(
new ResolveMissingFieldEvent(
$content,
$fieldDefinition,
$languageCode
)
);

$externalStorage = $this->storageRegistry->getStorage($fieldDefinition->fieldType);
if ($externalStorage->hasFieldData()) {
$externalStorage->getFieldData($versionInfo, $emptyField, []);
$field = $event->getField();
if ($field !== null) {
$content->fields[] = $field;
}

$emptyField->id = null;
$content->fields[] = $emptyField;
}
}

Expand Down Expand Up @@ -722,41 +723,4 @@ public function createRelationFromCreateStruct(RelationCreateStruct $struct)

return $relation;
}

private function createEmptyField(VersionInfo $versionInfo, FieldDefinition $fieldDefinition, string $languageCode): Field
{
$field = new Field();
$field->id = self::EMPTY_FIELD_ID;
$field->fieldDefinitionId = $fieldDefinition->id;
$field->type = $fieldDefinition->fieldType;
$field->value = $this->getDefaultValue($fieldDefinition);
$field->languageCode = $languageCode;
$field->versionNo = $versionInfo->versionNo;

return $field;
}

private function getDefaultValue(FieldDefinition $fieldDefinition): FieldValue
{
$value = clone $fieldDefinition->defaultValue;
$storageValue = $this->getDefaultStorageValue();

$converter = $this->converterRegistry->getConverter($fieldDefinition->fieldType);
$converter->toStorageValue($value, $storageValue);
$converter->toFieldValue($storageValue, $value);

return $value;
}

private function getDefaultStorageValue(): StorageFieldValue
{
$storageValue = new StorageFieldValue();
$storageValue->dataFloat = null;
$storageValue->dataInt = null;
$storageValue->dataText = '';
$storageValue->sortKeyInt = 0;
$storageValue->sortKeyString = '';

return $storageValue;
}
}
8 changes: 8 additions & 0 deletions eZ/Publish/Core/settings/storage_engines/legacy/content.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@ services:
- "@ezpublish.persistence.legacy.field_value_converter.registry"
- "@ezpublish.spi.persistence.legacy.language.handler"
- '@ezpublish.spi.persistence.legacy.content_type.handler'
- "@event_dispatcher"

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"
tags:
- { name: kernel.event_subscriber }

ezpublish.persistence.legacy.content.gateway.inner:
class: eZ\Publish\Core\Persistence\Legacy\Content\Gateway\DoctrineDatabase
Expand Down
69 changes: 69 additions & 0 deletions src/contracts/Event/Mapper/ResolveMissingFieldEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

Check warning on line 1 in src/contracts/Event/Mapper/ResolveMissingFieldEvent.php

View workflow job for this annotation

GitHub Actions / Run code style check (8.0)

Found violation(s) of type: AdamWojs/phpdoc_force_fqcn_fixer

Check warning on line 1 in src/contracts/Event/Mapper/ResolveMissingFieldEvent.php

View workflow job for this annotation

GitHub Actions / Run code style check (8.0)

Found violation(s) of type: header_comment

Check warning on line 1 in src/contracts/Event/Mapper/ResolveMissingFieldEvent.php

View workflow job for this annotation

GitHub Actions / Run code style check (8.0)

Found violation(s) of type: single_blank_line_at_eof

namespace Ibexa\Contracts\Core\Event\Mapper;

use eZ\Publish\SPI\Persistence\Content;
use eZ\Publish\SPI\Persistence\Content\Field;
use eZ\Publish\SPI\Persistence\Content\Type\FieldDefinition;
use Symfony\Contracts\EventDispatcher\Event;

final class ResolveMissingFieldEvent extends Event
{
/** @var Content */
private $content;

/** @var FieldDefinition */
private $fieldDefinition;

/** @var string */
private $languageCode;

/** @var array */
private $context;

/** @var Field|null */
private $field;

public function __construct(
Content $content,
FieldDefinition $fieldDefinition,
string $languageCode,
array $context = []
) {
$this->content = $content;
$this->fieldDefinition = $fieldDefinition;
$this->languageCode = $languageCode;
$this->context = $context;
$this->field = null;
}

public function getContent(): Content
{
return $this->content;
}

public function getFieldDefinition(): FieldDefinition
{
return $this->fieldDefinition;
}

public function getLanguageCode(): string
{
return $this->languageCode;
}

public function getContext(): array
{
return $this->context;
}

public function setField(?Field $field): void
{
$this->field = $field;
}

public function getField(): ?Field
{
return $this->field;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
<?php

Check warning on line 1 in src/lib/Persistence/Legacy/Content/Mapper/ResolveVirtualFieldSubscriber.php

View workflow job for this annotation

GitHub Actions / Run code style check (8.0)

Found violation(s) of type: trailing_comma_in_multiline

Check warning on line 1 in src/lib/Persistence/Legacy/Content/Mapper/ResolveVirtualFieldSubscriber.php

View workflow job for this annotation

GitHub Actions / Run code style check (8.0)

Found violation(s) of type: AdamWojs/phpdoc_force_fqcn_fixer

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Core\Persistence\Legacy\Content\Mapper;

use eZ\Publish\Core\FieldType\NullStorage;
use eZ\Publish\Core\Persistence\Legacy\Content\FieldValue\Converter\Exception\NotFound;
use eZ\Publish\Core\Persistence\Legacy\Content\FieldValue\ConverterRegistry;
use eZ\Publish\Core\Persistence\Legacy\Content\Gateway as ContentGateway;
use eZ\Publish\Core\Persistence\Legacy\Content\StorageFieldValue;
use eZ\Publish\Core\Persistence\Legacy\Content\StorageRegistry;
use eZ\Publish\SPI\Persistence\Content\Field;
use eZ\Publish\SPI\Persistence\Content\FieldValue;
use eZ\Publish\SPI\Persistence\Content\Type\FieldDefinition;
use eZ\Publish\SPI\Persistence\Content\VersionInfo;
use Ibexa\Contracts\Core\Event\Mapper\ResolveMissingFieldEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

final class ResolveVirtualFieldSubscriber implements EventSubscriberInterface
{
/** @var ConverterRegistry */
private $converterRegistry;

/** @var StorageRegistry */
private $storageRegistry;

/** @var ContentGateway */
private $contentGateway;

public function __construct(
ConverterRegistry $converterRegistry,
StorageRegistry $storageRegistry,
ContentGateway $contentGateway
) {
$this->converterRegistry = $converterRegistry;
$this->storageRegistry = $storageRegistry;
$this->contentGateway = $contentGateway;
}

public static function getSubscribedEvents(): array
{
return [
ResolveMissingFieldEvent::class => [
['persistExternalStorageField', -100],
['resolveVirtualField', 0],
]
];
}

public function resolveVirtualField(ResolveMissingFieldEvent $event): void
{
if ($event->getField()) {
return;
}

$content = $event->getContent();

try {
$emptyField = $this->createEmptyField(
$content->versionInfo,
$event->getFieldDefinition(),
$event->getLanguageCode()
);

$event->setField($emptyField);
} catch (NotFound $exception) {
return;
}
}

public function persistExternalStorageField(ResolveMissingFieldEvent $event): void
{
$field = $event->getField();

if ($field && $field->id !== null) {
// Not a virtual field
return;
}

$fieldDefinition = $event->getFieldDefinition();
$storage = $this->storageRegistry->getStorage($fieldDefinition->fieldType);

if ($storage instanceof NullStorage) {
// Not an external storage
return;
}

$content = $event->getContent();

$field->id = $this->contentGateway->insertNewField(
$content,
$field,
$this->getDefaultStorageValue()
);

$storage->getFieldData(
$content->versionInfo,
$field,
$event->getContext()
);

$event->setField($field);
}

/**
* @throws NotFound
*/
private function createEmptyField(
VersionInfo $versionInfo,
FieldDefinition $fieldDefinition,
string $languageCode
): Field {
$field = new Field();
$field->fieldDefinitionId = $fieldDefinition->id;
$field->type = $fieldDefinition->fieldType;
$field->value = $this->getDefaultValue($fieldDefinition);
$field->languageCode = $languageCode;
$field->versionNo = $versionInfo->versionNo;

return $field;
}

/**
* @throws NotFound
*/
private function getDefaultValue(FieldDefinition $fieldDefinition): FieldValue
{
$value = clone $fieldDefinition->defaultValue;
$storageValue = $this->getDefaultStorageValue();

$converter = $this->converterRegistry->getConverter($fieldDefinition->fieldType);
$converter->toStorageValue($value, $storageValue);
$converter->toFieldValue($storageValue, $value);

return $value;
}

private function getDefaultStorageValue(): StorageFieldValue
{
$storageValue = new StorageFieldValue();
$storageValue->dataFloat = null;
$storageValue->dataInt = null;
$storageValue->dataText = '';
$storageValue->sortKeyInt = 0;
$storageValue->sortKeyString = '';

return $storageValue;
}
}

0 comments on commit e24c72b

Please sign in to comment.