Skip to content

IBX-8753: Improved ModifyFieldDefinitions logic #1614

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: 4.6
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,44 @@

namespace Ibexa\AdminUi\Form\Type\Extension\EventSubscriber;

use Ibexa\AdminUi\Form\Data\FieldDefinitionData;
use Ibexa\AdminUi\Form\Type\FieldDefinition\FieldDefinitionType;
use Ibexa\Contracts\Core\Repository\Values\ContentType\ContentTypeDraft;
use Ibexa\Contracts\Core\Specification\SpecificationInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;

/**
* Modifies CT editing form by rebuilding field definition list with custom options on given field type.
* Rebuilds specific field definitions in the Content Type editing form with custom options for a given field type and set of field identifiers.
*/
final class ModifyFieldDefinitionFieldsSubscriber implements EventSubscriberInterface
{
private string $fieldTypeIdentifier;
private ?string $fieldTypeIdentifier;

/** @var string[] */
private array $fieldIdentifiers;

/** @var array<string, mixed> */
private array $modifiedOptions;

private ?SpecificationInterface $contentTypeSpecification;

/**
* @param array<string, mixed> $modifiedOptions
* @param array<string> $fieldIdentifiers
*/
public function __construct(string $fieldTypeIdentifier, array $modifiedOptions)
{
public function __construct(
?string $fieldTypeIdentifier,
array $modifiedOptions,
array $fieldIdentifiers = [],
?SpecificationInterface $contentTypeSpecification = null
) {
$this->fieldTypeIdentifier = $fieldTypeIdentifier;
$this->modifiedOptions = $modifiedOptions;
$this->fieldIdentifiers = $fieldIdentifiers;
$this->contentTypeSpecification = $contentTypeSpecification;
}

public static function getSubscribedEvents(): array
Expand All @@ -45,30 +61,75 @@ public function onPreSetData(FormEvent $event): void
$data = $event->getData();
$form = $event->getForm();

if (null === $data) {
if (empty($data)) {
return;
}

if (!$this->isApplicableToContentTypeDraft($this->getContentTypeDraft($data))) {
return;
}

foreach ($data as $fieldTypeIdentifier => $fieldTypeData) {
if ($this->fieldTypeIdentifier !== $fieldTypeData->fieldDefinition->fieldTypeIdentifier) {
foreach ($data as $fieldIdentifier => $fieldTypeData) {
if (!$form->has($fieldIdentifier)) {
continue;
}

if (!$form->has($fieldTypeIdentifier)) {
return;
if (!$this->acceptsFieldDefinition($fieldTypeData, $fieldIdentifier)) {
continue;
}

$baseFieldForm = $form->get($fieldTypeIdentifier);
$baseFieldFormName = $baseFieldForm->getName();
$this->rebuildFieldForm($form, $fieldIdentifier);
}
}

$form->remove($baseFieldFormName);
private function isApplicableToContentTypeDraft(?ContentTypeDraft $contentTypeDraft): bool
{
if ($this->contentTypeSpecification === null) {
return true;
}

$options = array_merge(
$baseFieldForm->getConfig()->getOptions(),
$this->modifiedOptions
);
if ($contentTypeDraft === null) {
return false;
}

$form->add($baseFieldFormName, FieldDefinitionType::class, $options);
return $this->contentTypeSpecification->isSatisfiedBy($contentTypeDraft);
}

/**
* @param array<string, \Ibexa\AdminUi\Form\Data\FieldDefinitionData> $data
*/
private function getContentTypeDraft(array $data): ?ContentTypeDraft
{
$firstField = reset($data);
if ($firstField instanceof FieldDefinitionData && isset($firstField->contentTypeData)) {
return $firstField->contentTypeData->contentTypeDraft ?? null;
}

return null;
}

private function acceptsFieldDefinition(FieldDefinitionData $field, string $identifier): bool
{
$matchesType = $this->fieldTypeIdentifier === $field->fieldDefinition->fieldTypeIdentifier;
$matchesIdentifier = in_array($identifier, $this->fieldIdentifiers, true);

return $matchesType || $matchesIdentifier;
}

/**
* @param \Symfony\Component\Form\FormInterface<\Ibexa\AdminUi\Form\Data\FieldDefinitionData[]> $form
*/
private function rebuildFieldForm(FormInterface $form, string $name): void
{
$baseFieldForm = $form->get($name);
$baseFieldFormName = $baseFieldForm->getName();

$options = array_merge(
$baseFieldForm->getConfig()->getOptions(),
$this->modifiedOptions
);

$form->remove($baseFieldFormName);
$form->add($baseFieldFormName, FieldDefinitionType::class, $options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use Ibexa\AdminUi\Form\Type\ContentType\FieldDefinitionsCollectionType;
use Ibexa\AdminUi\Form\Type\Extension\EventSubscriber\ModifyFieldDefinitionFieldsSubscriber;
use Ibexa\Contracts\Core\Specification\SpecificationInterface;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilderInterface;

Expand All @@ -20,24 +21,40 @@
*/
final class ModifyFieldDefinitionsCollectionTypeExtension extends AbstractTypeExtension
{
private string $fieldTypeIdentifier;
private ?string $fieldTypeIdentifier;

/** @var string[] */
private array $fieldIdentifiers;

/** @var array<string, mixed> */
private array $modifiedOptions;

private ?SpecificationInterface $contentTypeSpecification;

/**
* @param string $fieldTypeIdentifier
* @param array<string, mixed> $modifiedOptions
* @param array<string> $fieldIdentifiers
*/
public function __construct(string $fieldTypeIdentifier, array $modifiedOptions)
{
public function __construct(
?string $fieldTypeIdentifier,
array $modifiedOptions,
array $fieldIdentifiers = [],
?SpecificationInterface $contentTypeSpecification = null
) {
$this->fieldTypeIdentifier = $fieldTypeIdentifier;
$this->fieldIdentifiers = $fieldIdentifiers;
$this->modifiedOptions = $modifiedOptions;
$this->contentTypeSpecification = $contentTypeSpecification;
}

public function buildForm(FormBuilderInterface $builder, array $options): void
{
$subscriber = new ModifyFieldDefinitionFieldsSubscriber($this->fieldTypeIdentifier, $this->modifiedOptions);
$subscriber = new ModifyFieldDefinitionFieldsSubscriber(
$this->fieldTypeIdentifier,
$this->modifiedOptions,
$this->fieldIdentifiers,
$this->contentTypeSpecification
);

foreach ($builder->all() as $fieldTypeGroup) {
$fieldTypeGroup->addEventSubscriber($subscriber);
Expand Down
Loading