Files
iTop/sources/Forms/FormBuilder/FormBuilder.php
2025-10-31 08:55:45 +01:00

546 lines
12 KiB
PHP

<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Forms\FormBuilder;
use Combodo\iTop\Forms\Block\AbstractFormBlock;
use Combodo\iTop\Forms\Block\Base\FormBlock;
use IteratorAggregate;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\DataMapperInterface;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormConfigInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\RequestHandlerInterface;
use Symfony\Component\Form\ResolvedFormTypeInterface;
use Symfony\Component\PropertyAccess\PropertyPathInterface;
use Traversable;
class FormBuilder implements FormBuilderInterface, IteratorAggregate
{
/** @var DependencyHandler|null */
private ?DependencyHandler $oDependencyHandler = null;
/** @var AbstractFormBlock */
private AbstractFormBlock $oFormBlock;
/** @var array sub blocks */
private array $aSubFormBlocks = [];
private readonly FormBuilderInterface $builder;
/**
* Constructor.
*
* @param FormBuilderInterface $builder
*
*/
public function __construct(FormBuilderInterface $builder)
{
$this->builder = $builder;
/** Get the corresponding form block @var AbstractFormBlock $oFormBlock */
$oFormBlock = $this->builder->getOption('form_block');
// Build the form
if ($oFormBlock instanceof FormBlock) {
$this->BuildForm($oFormBlock);
}
}
/**
* Build the form.
*
* @param FormBlock $oFormBlock
*
* @return void
*/
private function BuildForm(FormBlock $oFormBlock): void
{
// Hidden (ignore)
$aOptions = $this->builder->getOptions();
if (array_key_exists('prevent_form_build', $aOptions) && $aOptions['prevent_form_build']) {
return;
}
$aDependentBlocks = [];
/** Iterate throw the form sub blocks... @var FormBlock $oSubFormBlock */
foreach ($oFormBlock->GetChildren() as $oSubFormBlock) {
// Add to the sub blocks array
$this->aSubFormBlocks[$oSubFormBlock->getName()] = $oSubFormBlock;
// Handle sub block
$bHasDependency = $this->HandleSubBlock($oSubFormBlock);
// Add to the dependencies array
if ($bHasDependency) {
$aDependentBlocks[$oSubFormBlock->GetName()] = $oSubFormBlock;
}
}
// Create a dependency handler if needed
if (count($aDependentBlocks) > 0) {
$this->oDependencyHandler = new DependencyHandler($this->builder->getName(), $oFormBlock, $this, $this->aSubFormBlocks, $aDependentBlocks);
}
}
/**
* Add a sub block.
*
* @param AbstractFormBlock $oSubFormBlock
*
* @return bool
*/
private function HandleSubBlock(AbstractFormBlock $oSubFormBlock): bool
{
// Has dependencies blocks
if ($oSubFormBlock->HasDependenciesBlocks()) {
// Insert a hidden type to save the place
$this->builder->add($oSubFormBlock->GetName(), HiddenType::class, [
'form_block' => $oSubFormBlock,
'prevent_form_build' => true,
// 'mapped' => false,
// 'disabled' => true,
]);
return true;
} else {
// Directly insert the block corresponding form type
$this->add($oSubFormBlock->GetName(), $oSubFormBlock->GetFormType(), $oSubFormBlock->UpdateOptions());
$oSubFormBlock->SetAdded(true);
return false;
}
}
/**
* Get a sub form block.
*
* @param string $sName
*
* @return AbstractFormBlock|null
*/
public function GetSubFormBlock(string $sName): ?AbstractFormBlock
{
return $this->aSubFormBlocks[$sName] ?? null;
}
/**
* Return the dependency handler attached to this builder.
*
* @return DependencyHandler|null
*/
protected function GetDependencyHandler(): ?DependencyHandler
{
return $this->oDependencyHandler;
}
public function GetDependencyMap(): ?DependencyMap
{
return $this->oDependencyHandler?->GetMap();
}
// pure decoration of FormBuilderInterface
public function add(string|FormBuilderInterface $child, ?string $type = null, array $options = []): static
{
$this->builder->add($child, $type, $options);
return $this;
}
public function getIterator(): Traversable
{
return $this->builder->getIterator();
}
public function count(): int
{
return $this->builder->count();
}
public function create(string $name, ?string $type = null, array $options = []): FormBuilderInterface
{
return $this->builder->create($name, $type, $options);
}
public function get(string $name): FormBuilderInterface
{
return $this->builder->get($name);
}
public function remove(string $name): static
{
$this->builder->remove($name);
return $this;
}
public function has(string $name): bool
{
return $this->builder->has($name);
}
public function all(): array
{
return $this->builder->all();
}
public function getForm(): FormInterface
{
return $this->builder->getForm();
}
public function addEventListener(string $eventName, callable $listener, int $priority = 0): static
{
$this->builder->addEventListener($eventName, $listener, $priority);
return $this;
}
public function addEventSubscriber(EventSubscriberInterface $subscriber): static
{
$this->builder->addEventSubscriber($subscriber);
return $this;
}
public function addViewTransformer(DataTransformerInterface $viewTransformer, bool $forcePrepend = false): static
{
$this->builder->addViewTransformer($viewTransformer, $forcePrepend);
return $this;
}
public function resetViewTransformers(): static
{
$this->builder->resetViewTransformers();
return $this;
}
public function addModelTransformer(DataTransformerInterface $modelTransformer, bool $forceAppend = false): static
{
$this->builder->addModelTransformer($modelTransformer, $forceAppend);
return $this;
}
public function resetModelTransformers(): static
{
$this->builder->resetModelTransformers();
return $this;
}
public function setAttribute(string $name, mixed $value): static
{
$this->builder->setAttribute($name, $value);
return $this;
}
public function setAttributes(array $attributes): static
{
$this->builder->setAttributes($attributes);
return $this;
}
public function setDataMapper(?DataMapperInterface $dataMapper): static
{
$this->builder->setDataMapper($dataMapper);
return $this;
}
public function setDisabled(bool $disabled): static
{
$this->builder->setDisabled($disabled);
return $this;
}
public function setEmptyData(mixed $emptyData): static
{
$this->builder->setEmptyData($emptyData);
return $this;
}
public function setErrorBubbling(bool $errorBubbling): static
{
$this->builder->setErrorBubbling($errorBubbling);
return $this;
}
public function setRequired(bool $required): static
{
$this->builder->setRequired($required);
return $this;
}
public function setPropertyPath(PropertyPathInterface|string|null $propertyPath): static
{
$this->builder->setPropertyPath($propertyPath);
return $this;
}
public function setMapped(bool $mapped): static
{
$this->builder->setMapped($mapped);
return $this;
}
public function setByReference(bool $byReference): static
{
$this->builder->setByReference($byReference);
return $this;
}
public function setInheritData(bool $inheritData): static
{
$this->builder->setInheritData($inheritData);
return $this;
}
public function setCompound(bool $compound): static
{
$this->builder->setCompound($compound);
return $this;
}
public function setType(ResolvedFormTypeInterface $type): static
{
$this->builder->setType($type);
return $this;
}
public function setData(mixed $data): static
{
$this->builder->setData($data);
return $this;
}
public function setDataLocked(bool $locked): static
{
$this->builder->setDataLocked($locked);
return $this;
}
public function setFormFactory(FormFactoryInterface $formFactory)
{
$this->builder->setFormFactory($formFactory);
}
public function setAction(string $action): static
{
$this->builder->setAction($action);
return $this;
}
public function setMethod(string $method): static
{
$this->builder->setMethod($method);
return $this;
}
public function setRequestHandler(RequestHandlerInterface $requestHandler): static
{
$this->builder->setRequestHandler($requestHandler);
return $this;
}
public function setAutoInitialize(bool $initialize): static
{
$this->builder->setAutoInitialize($initialize);
return $this;
}
public function getFormConfig(): FormConfigInterface
{
return $this->builder->getFormConfig();
}
public function setIsEmptyCallback(?callable $isEmptyCallback): static
{
$this->builder->setIsEmptyCallback($isEmptyCallback);
return $this;
}
public function getEventDispatcher(): EventDispatcherInterface
{
return $this->builder->getEventDispatcher();
}
public function getName(): string
{
return $this->builder->getName();
}
public function getPropertyPath(): ?PropertyPathInterface
{
return $this->builder->getPropertyPath();
}
public function getMapped(): bool
{
return $this->builder->getMapped();
}
public function getByReference(): bool
{
return $this->builder->getByReference();
}
public function getInheritData(): bool
{
return $this->builder->getInheritData();
}
public function getCompound(): bool
{
return $this->builder->getCompound();
}
public function getType(): ResolvedFormTypeInterface
{
return $this->builder->getType();
}
public function getViewTransformers(): array
{
return $this->builder->getViewTransformers();
}
public function getModelTransformers(): array
{
return $this->builder->getModelTransformers();
}
public function getDataMapper(): ?DataMapperInterface
{
return $this->builder->getDataMapper();
}
public function getRequired(): bool
{
return $this->builder->getRequired();
}
public function getDisabled(): bool
{
return $this->builder->getDisabled();
}
public function getErrorBubbling(): bool
{
return $this->builder->getErrorBubbling();
}
public function getEmptyData(): mixed
{
return $this->builder->getEmptyData();
}
public function getAttributes(): array
{
return $this->builder->getAttributes();
}
public function hasAttribute(string $name): bool
{
return $this->builder->hasAttribute($name);
}
public function getAttribute(string $name, mixed $default = null): mixed
{
return $this->builder->getAttribute($name, $default);
}
public function getData(): mixed
{
return $this->builder->getData();
}
public function getDataClass(): ?string
{
return $this->builder->getDataClass();
}
public function getDataLocked(): bool
{
return $this->builder->getDataLocked();
}
public function getFormFactory(): FormFactoryInterface
{
return $this->builder->getFormFactory();
}
public function getAction(): string
{
return $this->builder->getAction();
}
public function getMethod(): string
{
return $this->builder->getMethod();
}
public function getRequestHandler(): RequestHandlerInterface
{
return $this->builder->getRequestHandler();
}
public function getAutoInitialize(): bool
{
return $this->builder->getAutoInitialize();
}
public function getOptions(): array
{
return $this->builder->getOptions();
}
public function hasOption(string $name): bool
{
return $this->builder->hasOption($name);
}
public function getOption(string $name, mixed $default = null): mixed
{
return $this->builder->getOption($name, $default);
}
public function getIsEmptyCallback(): ?callable
{
return $this->builder->getIsEmptyCallback();
}
}