vendor/symfony/form/Extension/Core/Type/FormType.php line 171

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Form\Extension\Core\Type;
  11. use Symfony\Component\Form\Exception\LogicException;
  12. use Symfony\Component\Form\Extension\Core\DataAccessor\CallbackAccessor;
  13. use Symfony\Component\Form\Extension\Core\DataAccessor\ChainAccessor;
  14. use Symfony\Component\Form\Extension\Core\DataAccessor\PropertyPathAccessor;
  15. use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper;
  16. use Symfony\Component\Form\Extension\Core\EventListener\TrimListener;
  17. use Symfony\Component\Form\FormBuilderInterface;
  18. use Symfony\Component\Form\FormConfigBuilderInterface;
  19. use Symfony\Component\Form\FormInterface;
  20. use Symfony\Component\Form\FormView;
  21. use Symfony\Component\OptionsResolver\Options;
  22. use Symfony\Component\OptionsResolver\OptionsResolver;
  23. use Symfony\Component\PropertyAccess\PropertyAccess;
  24. use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
  25. use Symfony\Component\Translation\TranslatableMessage;
  26. class FormType extends BaseType
  27. {
  28.     private $dataMapper;
  29.     public function __construct(PropertyAccessorInterface $propertyAccessor null)
  30.     {
  31.         $this->dataMapper = new DataMapper(new ChainAccessor([
  32.             new CallbackAccessor(),
  33.             new PropertyPathAccessor($propertyAccessor ?? PropertyAccess::createPropertyAccessor()),
  34.         ]));
  35.     }
  36.     /**
  37.      * {@inheritdoc}
  38.      */
  39.     public function buildForm(FormBuilderInterface $builder, array $options)
  40.     {
  41.         parent::buildForm($builder$options);
  42.         $isDataOptionSet \array_key_exists('data'$options);
  43.         $builder
  44.             ->setRequired($options['required'])
  45.             ->setErrorBubbling($options['error_bubbling'])
  46.             ->setEmptyData($options['empty_data'])
  47.             ->setPropertyPath($options['property_path'])
  48.             ->setMapped($options['mapped'])
  49.             ->setByReference($options['by_reference'])
  50.             ->setInheritData($options['inherit_data'])
  51.             ->setCompound($options['compound'])
  52.             ->setData($isDataOptionSet $options['data'] : null)
  53.             ->setDataLocked($isDataOptionSet)
  54.             ->setDataMapper($options['compound'] ? $this->dataMapper null)
  55.             ->setMethod($options['method'])
  56.             ->setAction($options['action']);
  57.         if ($options['trim']) {
  58.             $builder->addEventSubscriber(new TrimListener());
  59.         }
  60.         if (!method_exists($builder'setIsEmptyCallback')) {
  61.             trigger_deprecation('symfony/form''5.1''Not implementing the "%s::setIsEmptyCallback()" method in "%s" is deprecated.'FormConfigBuilderInterface::class, get_debug_type($builder));
  62.             return;
  63.         }
  64.         $builder->setIsEmptyCallback($options['is_empty_callback']);
  65.     }
  66.     /**
  67.      * {@inheritdoc}
  68.      */
  69.     public function buildView(FormView $viewFormInterface $form, array $options)
  70.     {
  71.         parent::buildView($view$form$options);
  72.         $name $form->getName();
  73.         $helpTranslationParameters $options['help_translation_parameters'];
  74.         if ($view->parent) {
  75.             if ('' === $name) {
  76.                 throw new LogicException('Form node with empty name can be used only as root form node.');
  77.             }
  78.             // Complex fields are read-only if they themselves or their parents are.
  79.             if (!isset($view->vars['attr']['readonly']) && isset($view->parent->vars['attr']['readonly']) && false !== $view->parent->vars['attr']['readonly']) {
  80.                 $view->vars['attr']['readonly'] = true;
  81.             }
  82.             $helpTranslationParameters array_merge($view->parent->vars['help_translation_parameters'], $helpTranslationParameters);
  83.             $rootFormAttrOption $form->getRoot()->getConfig()->getOption('form_attr');
  84.             if ($options['form_attr'] || $rootFormAttrOption) {
  85.                 $view->vars['attr']['form'] = \is_string($rootFormAttrOption) ? $rootFormAttrOption $form->getRoot()->getName();
  86.                 if (empty($view->vars['attr']['form'])) {
  87.                     throw new LogicException('"form_attr" option must be a string identifier on root form when it has no id.');
  88.                 }
  89.             }
  90.         } elseif (\is_string($options['form_attr'])) {
  91.             $view->vars['id'] = $options['form_attr'];
  92.         }
  93.         $formConfig $form->getConfig();
  94.         $view->vars array_replace($view->vars, [
  95.             'errors' => $form->getErrors(),
  96.             'valid' => $form->isSubmitted() ? $form->isValid() : true,
  97.             'value' => $form->getViewData(),
  98.             'data' => $form->getNormData(),
  99.             'required' => $form->isRequired(),
  100.             'size' => null,
  101.             'label_attr' => $options['label_attr'],
  102.             'help' => $options['help'],
  103.             'help_attr' => $options['help_attr'],
  104.             'help_html' => $options['help_html'],
  105.             'help_translation_parameters' => $helpTranslationParameters,
  106.             'compound' => $formConfig->getCompound(),
  107.             'method' => $formConfig->getMethod(),
  108.             'action' => $formConfig->getAction(),
  109.             'submitted' => $form->isSubmitted(),
  110.         ]);
  111.     }
  112.     /**
  113.      * {@inheritdoc}
  114.      */
  115.     public function finishView(FormView $viewFormInterface $form, array $options)
  116.     {
  117.         $multipart false;
  118.         foreach ($view->children as $child) {
  119.             if ($child->vars['multipart']) {
  120.                 $multipart true;
  121.                 break;
  122.             }
  123.         }
  124.         $view->vars['multipart'] = $multipart;
  125.     }
  126.     /**
  127.      * {@inheritdoc}
  128.      */
  129.     public function configureOptions(OptionsResolver $resolver)
  130.     {
  131.         parent::configureOptions($resolver);
  132.         // Derive "data_class" option from passed "data" object
  133.         $dataClass = function (Options $options) {
  134.             return isset($options['data']) && \is_object($options['data']) ? \get_class($options['data']) : null;
  135.         };
  136.         // Derive "empty_data" closure from "data_class" option
  137.         $emptyData = function (Options $options) {
  138.             $class $options['data_class'];
  139.             if (null !== $class) {
  140.                 return function (FormInterface $form) use ($class) {
  141.                     return $form->isEmpty() && !$form->isRequired() ? null : new $class();
  142.                 };
  143.             }
  144.             return function (FormInterface $form) {
  145.                 return $form->getConfig()->getCompound() ? [] : '';
  146.             };
  147.         };
  148.         // Wrap "post_max_size_message" in a closure to translate it lazily
  149.         $uploadMaxSizeMessage = function (Options $options) {
  150.             return function () use ($options) {
  151.                 return $options['post_max_size_message'];
  152.             };
  153.         };
  154.         // For any form that is not represented by a single HTML control,
  155.         // errors should bubble up by default
  156.         $errorBubbling = function (Options $options) {
  157.             return $options['compound'] && !$options['inherit_data'];
  158.         };
  159.         // If data is given, the form is locked to that data
  160.         // (independent of its value)
  161.         $resolver->setDefined([
  162.             'data',
  163.         ]);
  164.         $resolver->setDefaults([
  165.             'data_class' => $dataClass,
  166.             'empty_data' => $emptyData,
  167.             'trim' => true,
  168.             'required' => true,
  169.             'property_path' => null,
  170.             'mapped' => true,
  171.             'by_reference' => true,
  172.             'error_bubbling' => $errorBubbling,
  173.             'label_attr' => [],
  174.             'inherit_data' => false,
  175.             'compound' => true,
  176.             'method' => 'POST',
  177.             // According to RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt)
  178.             // section 4.2., empty URIs are considered same-document references
  179.             'action' => '',
  180.             'attr' => [],
  181.             'post_max_size_message' => 'The uploaded file was too large. Please try to upload a smaller file.',
  182.             'upload_max_size_message' => $uploadMaxSizeMessage// internal
  183.             'allow_file_upload' => false,
  184.             'help' => null,
  185.             'help_attr' => [],
  186.             'help_html' => false,
  187.             'help_translation_parameters' => [],
  188.             'invalid_message' => 'This value is not valid.',
  189.             'invalid_message_parameters' => [],
  190.             'is_empty_callback' => null,
  191.             'getter' => null,
  192.             'setter' => null,
  193.             'form_attr' => false,
  194.         ]);
  195.         $resolver->setAllowedTypes('label_attr''array');
  196.         $resolver->setAllowedTypes('action''string');
  197.         $resolver->setAllowedTypes('upload_max_size_message', ['callable']);
  198.         $resolver->setAllowedTypes('help', ['string''null'TranslatableMessage::class]);
  199.         $resolver->setAllowedTypes('help_attr''array');
  200.         $resolver->setAllowedTypes('help_html''bool');
  201.         $resolver->setAllowedTypes('is_empty_callback', ['null''callable']);
  202.         $resolver->setAllowedTypes('getter', ['null''callable']);
  203.         $resolver->setAllowedTypes('setter', ['null''callable']);
  204.         $resolver->setAllowedTypes('form_attr', ['bool''string']);
  205.         $resolver->setInfo('getter''A callable that accepts two arguments (the view data and the current form field) and must return a value.');
  206.         $resolver->setInfo('setter''A callable that accepts three arguments (a reference to the view data, the submitted value and the current form field).');
  207.     }
  208.     /**
  209.      * {@inheritdoc}
  210.      */
  211.     public function getParent()
  212.     {
  213.         return null;
  214.     }
  215.     /**
  216.      * {@inheritdoc}
  217.      */
  218.     public function getBlockPrefix()
  219.     {
  220.         return 'form';
  221.     }
  222. }