vendor/symfony/form/FormConfigBuilder.php line 112

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;
  11. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  12. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  13. use Symfony\Component\EventDispatcher\ImmutableEventDispatcher;
  14. use Symfony\Component\Form\Exception\BadMethodCallException;
  15. use Symfony\Component\Form\Exception\InvalidArgumentException;
  16. use Symfony\Component\PropertyAccess\PropertyPath;
  17. use Symfony\Component\PropertyAccess\PropertyPathInterface;
  18. /**
  19.  * A basic form configuration.
  20.  *
  21.  * @author Bernhard Schussek <bschussek@gmail.com>
  22.  */
  23. class FormConfigBuilder implements FormConfigBuilderInterface
  24. {
  25.     /**
  26.      * Caches a globally unique {@link NativeRequestHandler} instance.
  27.      *
  28.      * @var NativeRequestHandler
  29.      */
  30.     private static $nativeRequestHandler;
  31.     protected $locked false;
  32.     private $dispatcher;
  33.     private $name;
  34.     /**
  35.      * @var PropertyPathInterface|string|null
  36.      */
  37.     private $propertyPath;
  38.     private $mapped true;
  39.     private $byReference true;
  40.     private $inheritData false;
  41.     private $compound false;
  42.     /**
  43.      * @var ResolvedFormTypeInterface
  44.      */
  45.     private $type;
  46.     private $viewTransformers = [];
  47.     private $modelTransformers = [];
  48.     /**
  49.      * @var DataMapperInterface|null
  50.      */
  51.     private $dataMapper;
  52.     private $required true;
  53.     private $disabled false;
  54.     private $errorBubbling false;
  55.     /**
  56.      * @var mixed
  57.      */
  58.     private $emptyData;
  59.     private $attributes = [];
  60.     /**
  61.      * @var mixed
  62.      */
  63.     private $data;
  64.     /**
  65.      * @var string|null
  66.      */
  67.     private $dataClass;
  68.     private $dataLocked false;
  69.     /**
  70.      * @var FormFactoryInterface|null
  71.      */
  72.     private $formFactory;
  73.     private $action '';
  74.     private $method 'POST';
  75.     /**
  76.      * @var RequestHandlerInterface|null
  77.      */
  78.     private $requestHandler;
  79.     private $autoInitialize false;
  80.     private $options;
  81.     private $isEmptyCallback;
  82.     /**
  83.      * Creates an empty form configuration.
  84.      *
  85.      * @param string|null $name      The form name
  86.      * @param string|null $dataClass The class of the form's data
  87.      *
  88.      * @throws InvalidArgumentException if the data class is not a valid class or if
  89.      *                                  the name contains invalid characters
  90.      */
  91.     public function __construct(?string $name, ?string $dataClassEventDispatcherInterface $dispatcher, array $options = [])
  92.     {
  93.         self::validateName($name);
  94.         if (null !== $dataClass && !class_exists($dataClass) && !interface_exists($dataClassfalse)) {
  95.             throw new InvalidArgumentException(sprintf('Class "%s" not found. Is the "data_class" form option set correctly?'$dataClass));
  96.         }
  97.         $this->name = (string) $name;
  98.         $this->dataClass $dataClass;
  99.         $this->dispatcher $dispatcher;
  100.         $this->options $options;
  101.     }
  102.     /**
  103.      * {@inheritdoc}
  104.      */
  105.     public function addEventListener(string $eventName, callable $listenerint $priority 0)
  106.     {
  107.         if ($this->locked) {
  108.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  109.         }
  110.         $this->dispatcher->addListener($eventName$listener$priority);
  111.         return $this;
  112.     }
  113.     /**
  114.      * {@inheritdoc}
  115.      */
  116.     public function addEventSubscriber(EventSubscriberInterface $subscriber)
  117.     {
  118.         if ($this->locked) {
  119.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  120.         }
  121.         $this->dispatcher->addSubscriber($subscriber);
  122.         return $this;
  123.     }
  124.     /**
  125.      * {@inheritdoc}
  126.      */
  127.     public function addViewTransformer(DataTransformerInterface $viewTransformerbool $forcePrepend false)
  128.     {
  129.         if ($this->locked) {
  130.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  131.         }
  132.         if ($forcePrepend) {
  133.             array_unshift($this->viewTransformers$viewTransformer);
  134.         } else {
  135.             $this->viewTransformers[] = $viewTransformer;
  136.         }
  137.         return $this;
  138.     }
  139.     /**
  140.      * {@inheritdoc}
  141.      */
  142.     public function resetViewTransformers()
  143.     {
  144.         if ($this->locked) {
  145.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  146.         }
  147.         $this->viewTransformers = [];
  148.         return $this;
  149.     }
  150.     /**
  151.      * {@inheritdoc}
  152.      */
  153.     public function addModelTransformer(DataTransformerInterface $modelTransformerbool $forceAppend false)
  154.     {
  155.         if ($this->locked) {
  156.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  157.         }
  158.         if ($forceAppend) {
  159.             $this->modelTransformers[] = $modelTransformer;
  160.         } else {
  161.             array_unshift($this->modelTransformers$modelTransformer);
  162.         }
  163.         return $this;
  164.     }
  165.     /**
  166.      * {@inheritdoc}
  167.      */
  168.     public function resetModelTransformers()
  169.     {
  170.         if ($this->locked) {
  171.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  172.         }
  173.         $this->modelTransformers = [];
  174.         return $this;
  175.     }
  176.     /**
  177.      * {@inheritdoc}
  178.      */
  179.     public function getEventDispatcher()
  180.     {
  181.         if ($this->locked && !$this->dispatcher instanceof ImmutableEventDispatcher) {
  182.             $this->dispatcher = new ImmutableEventDispatcher($this->dispatcher);
  183.         }
  184.         return $this->dispatcher;
  185.     }
  186.     /**
  187.      * {@inheritdoc}
  188.      */
  189.     public function getName()
  190.     {
  191.         return $this->name;
  192.     }
  193.     /**
  194.      * {@inheritdoc}
  195.      */
  196.     public function getPropertyPath()
  197.     {
  198.         return $this->propertyPath;
  199.     }
  200.     /**
  201.      * {@inheritdoc}
  202.      */
  203.     public function getMapped()
  204.     {
  205.         return $this->mapped;
  206.     }
  207.     /**
  208.      * {@inheritdoc}
  209.      */
  210.     public function getByReference()
  211.     {
  212.         return $this->byReference;
  213.     }
  214.     /**
  215.      * {@inheritdoc}
  216.      */
  217.     public function getInheritData()
  218.     {
  219.         return $this->inheritData;
  220.     }
  221.     /**
  222.      * {@inheritdoc}
  223.      */
  224.     public function getCompound()
  225.     {
  226.         return $this->compound;
  227.     }
  228.     /**
  229.      * {@inheritdoc}
  230.      */
  231.     public function getType()
  232.     {
  233.         return $this->type;
  234.     }
  235.     /**
  236.      * {@inheritdoc}
  237.      */
  238.     public function getViewTransformers()
  239.     {
  240.         return $this->viewTransformers;
  241.     }
  242.     /**
  243.      * {@inheritdoc}
  244.      */
  245.     public function getModelTransformers()
  246.     {
  247.         return $this->modelTransformers;
  248.     }
  249.     /**
  250.      * {@inheritdoc}
  251.      */
  252.     public function getDataMapper()
  253.     {
  254.         return $this->dataMapper;
  255.     }
  256.     /**
  257.      * {@inheritdoc}
  258.      */
  259.     public function getRequired()
  260.     {
  261.         return $this->required;
  262.     }
  263.     /**
  264.      * {@inheritdoc}
  265.      */
  266.     public function getDisabled()
  267.     {
  268.         return $this->disabled;
  269.     }
  270.     /**
  271.      * {@inheritdoc}
  272.      */
  273.     public function getErrorBubbling()
  274.     {
  275.         return $this->errorBubbling;
  276.     }
  277.     /**
  278.      * {@inheritdoc}
  279.      */
  280.     public function getEmptyData()
  281.     {
  282.         return $this->emptyData;
  283.     }
  284.     /**
  285.      * {@inheritdoc}
  286.      */
  287.     public function getAttributes()
  288.     {
  289.         return $this->attributes;
  290.     }
  291.     /**
  292.      * {@inheritdoc}
  293.      */
  294.     public function hasAttribute(string $name)
  295.     {
  296.         return \array_key_exists($name$this->attributes);
  297.     }
  298.     /**
  299.      * {@inheritdoc}
  300.      */
  301.     public function getAttribute(string $name$default null)
  302.     {
  303.         return \array_key_exists($name$this->attributes) ? $this->attributes[$name] : $default;
  304.     }
  305.     /**
  306.      * {@inheritdoc}
  307.      */
  308.     public function getData()
  309.     {
  310.         return $this->data;
  311.     }
  312.     /**
  313.      * {@inheritdoc}
  314.      */
  315.     public function getDataClass()
  316.     {
  317.         return $this->dataClass;
  318.     }
  319.     /**
  320.      * {@inheritdoc}
  321.      */
  322.     public function getDataLocked()
  323.     {
  324.         return $this->dataLocked;
  325.     }
  326.     /**
  327.      * {@inheritdoc}
  328.      */
  329.     public function getFormFactory()
  330.     {
  331.         if (!isset($this->formFactory)) {
  332.             throw new BadMethodCallException('The form factory must be set before retrieving it.');
  333.         }
  334.         return $this->formFactory;
  335.     }
  336.     /**
  337.      * {@inheritdoc}
  338.      */
  339.     public function getAction()
  340.     {
  341.         return $this->action;
  342.     }
  343.     /**
  344.      * {@inheritdoc}
  345.      */
  346.     public function getMethod()
  347.     {
  348.         return $this->method;
  349.     }
  350.     /**
  351.      * {@inheritdoc}
  352.      */
  353.     public function getRequestHandler()
  354.     {
  355.         if (null === $this->requestHandler) {
  356.             if (null === self::$nativeRequestHandler) {
  357.                 self::$nativeRequestHandler = new NativeRequestHandler();
  358.             }
  359.             $this->requestHandler self::$nativeRequestHandler;
  360.         }
  361.         return $this->requestHandler;
  362.     }
  363.     /**
  364.      * {@inheritdoc}
  365.      */
  366.     public function getAutoInitialize()
  367.     {
  368.         return $this->autoInitialize;
  369.     }
  370.     /**
  371.      * {@inheritdoc}
  372.      */
  373.     public function getOptions()
  374.     {
  375.         return $this->options;
  376.     }
  377.     /**
  378.      * {@inheritdoc}
  379.      */
  380.     public function hasOption(string $name)
  381.     {
  382.         return \array_key_exists($name$this->options);
  383.     }
  384.     /**
  385.      * {@inheritdoc}
  386.      */
  387.     public function getOption(string $name$default null)
  388.     {
  389.         return \array_key_exists($name$this->options) ? $this->options[$name] : $default;
  390.     }
  391.     /**
  392.      * {@inheritdoc}
  393.      */
  394.     public function getIsEmptyCallback(): ?callable
  395.     {
  396.         return $this->isEmptyCallback;
  397.     }
  398.     /**
  399.      * {@inheritdoc}
  400.      */
  401.     public function setAttribute(string $name$value)
  402.     {
  403.         if ($this->locked) {
  404.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  405.         }
  406.         $this->attributes[$name] = $value;
  407.         return $this;
  408.     }
  409.     /**
  410.      * {@inheritdoc}
  411.      */
  412.     public function setAttributes(array $attributes)
  413.     {
  414.         if ($this->locked) {
  415.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  416.         }
  417.         $this->attributes $attributes;
  418.         return $this;
  419.     }
  420.     /**
  421.      * {@inheritdoc}
  422.      */
  423.     public function setDataMapper(?DataMapperInterface $dataMapper null)
  424.     {
  425.         if ($this->locked) {
  426.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  427.         }
  428.         $this->dataMapper $dataMapper;
  429.         return $this;
  430.     }
  431.     /**
  432.      * {@inheritdoc}
  433.      */
  434.     public function setDisabled(bool $disabled)
  435.     {
  436.         if ($this->locked) {
  437.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  438.         }
  439.         $this->disabled $disabled;
  440.         return $this;
  441.     }
  442.     /**
  443.      * {@inheritdoc}
  444.      */
  445.     public function setEmptyData($emptyData)
  446.     {
  447.         if ($this->locked) {
  448.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  449.         }
  450.         $this->emptyData $emptyData;
  451.         return $this;
  452.     }
  453.     /**
  454.      * {@inheritdoc}
  455.      */
  456.     public function setErrorBubbling(bool $errorBubbling)
  457.     {
  458.         if ($this->locked) {
  459.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  460.         }
  461.         $this->errorBubbling $errorBubbling;
  462.         return $this;
  463.     }
  464.     /**
  465.      * {@inheritdoc}
  466.      */
  467.     public function setRequired(bool $required)
  468.     {
  469.         if ($this->locked) {
  470.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  471.         }
  472.         $this->required $required;
  473.         return $this;
  474.     }
  475.     /**
  476.      * {@inheritdoc}
  477.      */
  478.     public function setPropertyPath($propertyPath)
  479.     {
  480.         if ($this->locked) {
  481.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  482.         }
  483.         if (null !== $propertyPath && !$propertyPath instanceof PropertyPathInterface) {
  484.             $propertyPath = new PropertyPath($propertyPath);
  485.         }
  486.         $this->propertyPath $propertyPath;
  487.         return $this;
  488.     }
  489.     /**
  490.      * {@inheritdoc}
  491.      */
  492.     public function setMapped(bool $mapped)
  493.     {
  494.         if ($this->locked) {
  495.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  496.         }
  497.         $this->mapped $mapped;
  498.         return $this;
  499.     }
  500.     /**
  501.      * {@inheritdoc}
  502.      */
  503.     public function setByReference(bool $byReference)
  504.     {
  505.         if ($this->locked) {
  506.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  507.         }
  508.         $this->byReference $byReference;
  509.         return $this;
  510.     }
  511.     /**
  512.      * {@inheritdoc}
  513.      */
  514.     public function setInheritData(bool $inheritData)
  515.     {
  516.         if ($this->locked) {
  517.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  518.         }
  519.         $this->inheritData $inheritData;
  520.         return $this;
  521.     }
  522.     /**
  523.      * {@inheritdoc}
  524.      */
  525.     public function setCompound(bool $compound)
  526.     {
  527.         if ($this->locked) {
  528.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  529.         }
  530.         $this->compound $compound;
  531.         return $this;
  532.     }
  533.     /**
  534.      * {@inheritdoc}
  535.      */
  536.     public function setType(ResolvedFormTypeInterface $type)
  537.     {
  538.         if ($this->locked) {
  539.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  540.         }
  541.         $this->type $type;
  542.         return $this;
  543.     }
  544.     /**
  545.      * {@inheritdoc}
  546.      */
  547.     public function setData($data)
  548.     {
  549.         if ($this->locked) {
  550.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  551.         }
  552.         $this->data $data;
  553.         return $this;
  554.     }
  555.     /**
  556.      * {@inheritdoc}
  557.      */
  558.     public function setDataLocked(bool $locked)
  559.     {
  560.         if ($this->locked) {
  561.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  562.         }
  563.         $this->dataLocked $locked;
  564.         return $this;
  565.     }
  566.     /**
  567.      * {@inheritdoc}
  568.      */
  569.     public function setFormFactory(FormFactoryInterface $formFactory)
  570.     {
  571.         if ($this->locked) {
  572.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  573.         }
  574.         $this->formFactory $formFactory;
  575.         return $this;
  576.     }
  577.     /**
  578.      * {@inheritdoc}
  579.      */
  580.     public function setAction(string $action)
  581.     {
  582.         if ($this->locked) {
  583.             throw new BadMethodCallException('The config builder cannot be modified anymore.');
  584.         }
  585.         $this->action $action;
  586.         return $this;
  587.     }
  588.     /**
  589.      * {@inheritdoc}
  590.      */
  591.     public function setMethod(string $method)
  592.     {
  593.         if ($this->locked) {
  594.             throw new BadMethodCallException('The config builder cannot be modified anymore.');
  595.         }
  596.         $this->method strtoupper($method);
  597.         return $this;
  598.     }
  599.     /**
  600.      * {@inheritdoc}
  601.      */
  602.     public function setRequestHandler(RequestHandlerInterface $requestHandler)
  603.     {
  604.         if ($this->locked) {
  605.             throw new BadMethodCallException('The config builder cannot be modified anymore.');
  606.         }
  607.         $this->requestHandler $requestHandler;
  608.         return $this;
  609.     }
  610.     /**
  611.      * {@inheritdoc}
  612.      */
  613.     public function setAutoInitialize(bool $initialize)
  614.     {
  615.         if ($this->locked) {
  616.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  617.         }
  618.         $this->autoInitialize $initialize;
  619.         return $this;
  620.     }
  621.     /**
  622.      * {@inheritdoc}
  623.      */
  624.     public function getFormConfig()
  625.     {
  626.         if ($this->locked) {
  627.             throw new BadMethodCallException('FormConfigBuilder methods cannot be accessed anymore once the builder is turned into a FormConfigInterface instance.');
  628.         }
  629.         // This method should be idempotent, so clone the builder
  630.         $config = clone $this;
  631.         $config->locked true;
  632.         return $config;
  633.     }
  634.     /**
  635.      * {@inheritdoc}
  636.      */
  637.     public function setIsEmptyCallback(?callable $isEmptyCallback)
  638.     {
  639.         $this->isEmptyCallback $isEmptyCallback;
  640.         return $this;
  641.     }
  642.     /**
  643.      * Validates whether the given variable is a valid form name.
  644.      *
  645.      * @throws InvalidArgumentException if the name contains invalid characters
  646.      *
  647.      * @internal
  648.      */
  649.     final public static function validateName(?string $name)
  650.     {
  651.         if (!self::isValidName($name)) {
  652.             throw new InvalidArgumentException(sprintf('The name "%s" contains illegal characters. Names should start with a letter, digit or underscore and only contain letters, digits, numbers, underscores ("_"), hyphens ("-") and colons (":").'$name));
  653.         }
  654.     }
  655.     /**
  656.      * Returns whether the given variable contains a valid form name.
  657.      *
  658.      * A name is accepted if it
  659.      *
  660.      *   * is empty
  661.      *   * starts with a letter, digit or underscore
  662.      *   * contains only letters, digits, numbers, underscores ("_"),
  663.      *     hyphens ("-") and colons (":")
  664.      */
  665.     final public static function isValidName(?string $name): bool
  666.     {
  667.         return '' === $name || null === $name || preg_match('/^[a-zA-Z0-9_][a-zA-Z0-9_\-:]*$/D'$name);
  668.     }
  669. }