components-web-app/api-components-bundle

View on GitHub
src/Model/Form/FormView.php

Summary

Maintainability
A
35 mins
Test Coverage
<?php

/*
 * This file is part of the Silverback API Components Bundle Project
 *
 * (c) Daniel West <daniel@silverback.is>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

declare(strict_types=1);

namespace Silverback\ApiComponentsBundle\Model\Form;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection as DoctrineCollection;
use Silverback\ApiComponentsBundle\Helper\Form\FormSubmitHelper;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView as SymfonyFormView;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * @author Daniel West <daniel@silverback.is>
 */
class FormView
{
    private const ARRAY_OUTPUT_VARS = [
        'choices',
        'preferred_choices',
        'errors',
        'is_selected',
    ];

    private const OUTPUT_VARS = [
        'action',
        'attr',
        'block_prefixes',
        'checked',
        'disabled',
        'expanded',
        'full_name',
        'help',
        'id',
        'is_selected',
        'label',
        'label_attr',
        'multiple',
        'name',
        'placeholder',
        'placeholder_in_choices',
        FormSubmitHelper::FORM_POST_APP_PROXY,
        FormSubmitHelper::FORM_REALTIME_VALIDATE_DISABLED,
        FormSubmitHelper::FORM_API_DISABLED,
        'required',
        'submitted',
        'unique_block_prefix',
        'valid',
    ];

    #[Groups(['Form:cwa_resource:read'])]
    private array $vars;

    #[Groups(['Form:cwa_resource:read'])]
    private DoctrineCollection $children;

    #[Groups(['Form:cwa_resource:read'])]
    private bool $rendered;

    #[Groups(['Form:cwa_resource:read'])]
    private bool $methodRendered;

    private FormInterface $form;

    public function __construct(FormInterface $form, ?SymfonyFormView $formView = null, bool $children = true)
    {
        $isRoot = !$formView;
        if (!$formView) {
            $formView = $form->createView();
        }
        $this->init($formView, $form, $children, $isRoot);
    }

    private function init(SymfonyFormView $formView, FormInterface $form, bool $children = true, bool $isRoot = false): void
    {
        $this->form = $form;
        $this->rendered = $formView->isRendered();
        $this->methodRendered = $formView->isMethodRendered();
        $this->processViewVars($formView, $isRoot);
        if ($children) {
            $this->children = new ArrayCollection();
            foreach ($formView->getIterator() as $view) {
                $this->addChild($view);
            }
            if (\array_key_exists('prototype', $formView->vars)) {
                $this->addChild($formView->vars['prototype']);
            }
        }
    }

    private function processViewVars(SymfonyFormView $formView, $isRoot): void
    {
        $outputVars = array_merge(self::ARRAY_OUTPUT_VARS, self::OUTPUT_VARS);
        if (!$isRoot) {
            $outputVars[] = 'value';
        }
        foreach ($outputVars as $var) {
            if (isset($formView->vars[$var])) {
                $this->vars[$var] = $formView->vars[$var];
                $this->convertVarToArray($var);
            }
        }
    }

    private function convertVarToArray($var): void
    {
        if (\in_array($var, self::ARRAY_OUTPUT_VARS, true)) {
            /** @var iterable $choices */
            $choices = $this->vars[$var];
            $this->vars[$var] = [];
            foreach ($choices as $choice) {
                if (method_exists($choice, 'getMessage')) {
                    $this->vars[$var][] = $choice->getMessage();
                } else {
                    $this->vars[$var][] = (array) $choice;
                }
            }
        }
    }

    private function addChild(SymfonyFormView $symfonyFormView): void
    {
        $formView = new self($this->form, $symfonyFormView);
        $this->children->add($formView);
    }

    public function getVars(): array
    {
        return $this->vars;
    }

    public function getChildren(): DoctrineCollection
    {
        return $this->children;
    }

    public function isRendered(): bool
    {
        return $this->rendered;
    }

    public function isMethodRendered(): bool
    {
        return $this->methodRendered;
    }

    public function getForm(): FormInterface
    {
        return $this->form;
    }

    public function setForm(FormInterface $form): self
    {
        $this->init($form->createView(), $form, true);

        return $this;
    }
}