Ejemplo n.º 1
0
 /**
  * {@inheritdoc}
  */
 public function submit($submittedData, $clearMissing = true)
 {
     if ($this->submitted) {
         throw new AlreadySubmittedException('A form can only be submitted once');
     }
     // Initialize errors in the very beginning so that we don't lose any
     // errors added during listeners
     $this->errors = array();
     // Obviously, a disabled form should not change its data upon submission.
     if ($this->isDisabled()) {
         $this->submitted = true;
         return $this;
     }
     // The data must be initialized if it was not initialized yet.
     // This is necessary to guarantee that the *_SET_DATA listeners
     // are always invoked before submit() takes place.
     if (!$this->defaultDataSet) {
         $this->setData($this->config->getData());
     }
     // Treat false as NULL to support binding false to checkboxes.
     // Don't convert NULL to a string here in order to determine later
     // whether an empty value has been submitted or whether no value has
     // been submitted at all. This is important for processing checkboxes
     // and radio buttons with empty values.
     if (false === $submittedData) {
         $submittedData = null;
     } elseif (is_scalar($submittedData)) {
         $submittedData = (string) $submittedData;
     }
     $dispatcher = $this->config->getEventDispatcher();
     $modelData = null;
     $normData = null;
     $viewData = null;
     try {
         // Hook to change content of the data submitted by the browser
         if ($dispatcher->hasListeners(FormEvents::PRE_SUBMIT)) {
             $event = new FormEvent($this, $submittedData);
             $dispatcher->dispatch(FormEvents::PRE_SUBMIT, $event);
             $submittedData = $event->getData();
         }
         // Check whether the form is compound.
         // This check is preferable over checking the number of children,
         // since forms without children may also be compound.
         // (think of empty collection forms)
         if ($this->config->getCompound()) {
             if (null === $submittedData) {
                 $submittedData = array();
             }
             if (!is_array($submittedData)) {
                 throw new TransformationFailedException('Compound forms expect an array or NULL on submission.');
             }
             foreach ($this->children as $name => $child) {
                 $isSubmitted = array_key_exists($name, $submittedData);
                 if ($isSubmitted || $clearMissing) {
                     $child->submit($isSubmitted ? $submittedData[$name] : null, $clearMissing);
                     unset($submittedData[$name]);
                     if (null !== $this->clickedButton) {
                         continue;
                     }
                     if ($child instanceof ClickableInterface && $child->isClicked()) {
                         $this->clickedButton = $child;
                         continue;
                     }
                     if (method_exists($child, 'getClickedButton') && null !== $child->getClickedButton()) {
                         $this->clickedButton = $child->getClickedButton();
                     }
                 }
             }
             $this->extraData = $submittedData;
         }
         // Forms that inherit their parents' data also are not processed,
         // because then it would be too difficult to merge the changes in
         // the child and the parent form. Instead, the parent form also takes
         // changes in the grandchildren (i.e. children of the form that inherits
         // its parent's data) into account.
         // (see InheritDataAwareIterator below)
         if (!$this->config->getInheritData()) {
             // If the form is compound, the default data in view format
             // is reused. The data of the children is merged into this
             // default data using the data mapper.
             // If the form is not compound, the submitted data is also the data in view format.
             $viewData = $this->config->getCompound() ? $this->viewData : $submittedData;
             if (FormUtil::isEmpty($viewData)) {
                 $emptyData = $this->config->getEmptyData();
                 if ($emptyData instanceof \Closure) {
                     /* @var \Closure $emptyData */
                     $emptyData = $emptyData($this, $viewData);
                 }
                 $viewData = $emptyData;
             }
             // Merge form data from children into existing view data
             // It is not necessary to invoke this method if the form has no children,
             // even if it is compound.
             if (count($this->children) > 0) {
                 // Use InheritDataAwareIterator to process children of
                 // descendants that inherit this form's data.
                 // These descendants will not be submitted normally (see the check
                 // for $this->config->getInheritData() above)
                 $childrenIterator = new InheritDataAwareIterator($this->children);
                 $childrenIterator = new \RecursiveIteratorIterator($childrenIterator);
                 $this->config->getDataMapper()->mapFormsToData($childrenIterator, $viewData);
             }
             // Normalize data to unified representation
             $normData = $this->viewToNorm($viewData);
             // Hook to change content of the data in the normalized
             // representation
             if ($dispatcher->hasListeners(FormEvents::SUBMIT)) {
                 $event = new FormEvent($this, $normData);
                 $dispatcher->dispatch(FormEvents::SUBMIT, $event);
                 $normData = $event->getData();
             }
             // Synchronize representations - must not change the content!
             $modelData = $this->normToModel($normData);
             $viewData = $this->normToView($normData);
         }
     } catch (TransformationFailedException $e) {
         $this->transformationFailure = $e;
         // If $viewData was not yet set, set it to $submittedData so that
         // the erroneous data is accessible on the form.
         // Forms that inherit data never set any data, because the getters
         // forward to the parent form's getters anyway.
         if (null === $viewData && !$this->config->getInheritData()) {
             $viewData = $submittedData;
         }
     }
     $this->submitted = true;
     $this->modelData = $modelData;
     $this->normData = $normData;
     $this->viewData = $viewData;
     if ($dispatcher->hasListeners(FormEvents::POST_SUBMIT)) {
         $event = new FormEvent($this, $viewData);
         $dispatcher->dispatch(FormEvents::POST_SUBMIT, $event);
     }
     return $this;
 }
Ejemplo n.º 2
0
 /**
  * {@inheritdoc}
  */
 public function bind($submittedData)
 {
     if ($this->bound) {
         throw new AlreadyBoundException('A form can only be bound once');
     }
     if ($this->isDisabled()) {
         $this->bound = true;
         return $this;
     }
     // The data must be initialized if it was not initialized yet.
     // This is necessary to guarantee that the *_SET_DATA listeners
     // are always invoked before bind() takes place.
     if (!$this->initialized) {
         $this->setData($this->config->getData());
     }
     // Don't convert NULL to a string here in order to determine later
     // whether an empty value has been submitted or whether no value has
     // been submitted at all. This is important for processing checkboxes
     // and radio buttons with empty values.
     if (is_scalar($submittedData)) {
         $submittedData = (string) $submittedData;
     }
     // Initialize errors in the very beginning so that we don't lose any
     // errors added during listeners
     $this->errors = array();
     $dispatcher = $this->config->getEventDispatcher();
     $modelData = null;
     $normData = null;
     $viewData = null;
     try {
         // Hook to change content of the data bound by the browser
         if ($dispatcher->hasListeners(FormEvents::PRE_BIND) || $dispatcher->hasListeners(FormEvents::BIND_CLIENT_DATA)) {
             $event = new FormEvent($this, $submittedData);
             $dispatcher->dispatch(FormEvents::PRE_BIND, $event);
             // BC until 2.3
             if ($dispatcher->hasListeners(FormEvents::BIND_CLIENT_DATA)) {
                 trigger_error('The FormEvents::BIND_CLIENT_DATA event is deprecated since 2.1 and will be removed in 2.3. Use the FormEvents::PRE_BIND event instead.', E_USER_DEPRECATED);
             }
             $dispatcher->dispatch(FormEvents::BIND_CLIENT_DATA, $event);
             $submittedData = $event->getData();
         }
         // Check whether the form is compound.
         // This check is preferable over checking the number of children,
         // since forms without children may also be compound.
         // (think of empty collection forms)
         if ($this->config->getCompound()) {
             if (null === $submittedData) {
                 $submittedData = array();
             }
             if (!is_array($submittedData)) {
                 throw new TransformationFailedException('Compound forms expect an array or NULL on submission.');
             }
             for (reset($this->children); false !== current($this->children); next($this->children)) {
                 $child = current($this->children);
                 $name = key($this->children);
                 $child->bind(isset($submittedData[$name]) ? $submittedData[$name] : null);
                 unset($submittedData[$name]);
             }
             $this->extraData = $submittedData;
             // If the form is compound, the default data in view format
             // is reused. The data of the children is merged into this
             // default data using the data mapper.
             $viewData = $this->viewData;
         } else {
             // If the form is not compound, the submitted data is also the data in view format.
             $viewData = $submittedData;
         }
         if (FormUtil::isEmpty($viewData)) {
             $emptyData = $this->config->getEmptyData();
             if ($emptyData instanceof \Closure) {
                 /* @var \Closure $emptyData */
                 $emptyData = $emptyData($this, $viewData);
             }
             $viewData = $emptyData;
         }
         // Merge form data from children into existing view data
         // It is not necessary to invoke this method if the form has no children,
         // even if it is compound.
         if (count($this->children) > 0) {
             $this->config->getDataMapper()->mapFormsToData($this->children, $viewData);
         }
         // Normalize data to unified representation
         $normData = $this->viewToNorm($viewData);
         // Hook to change content of the data into the normalized
         // representation
         if ($dispatcher->hasListeners(FormEvents::BIND) || $dispatcher->hasListeners(FormEvents::BIND_NORM_DATA)) {
             $event = new FormEvent($this, $normData);
             $dispatcher->dispatch(FormEvents::BIND, $event);
             // BC until 2.3
             if ($dispatcher->hasListeners(FormEvents::BIND_NORM_DATA)) {
                 trigger_error('The FormEvents::BIND_NORM_DATA event is deprecated since 2.1 and will be removed in 2.3. Use the FormEvents::BIND event instead.', E_USER_DEPRECATED);
             }
             $dispatcher->dispatch(FormEvents::BIND_NORM_DATA, $event);
             $normData = $event->getData();
         }
         // Synchronize representations - must not change the content!
         $modelData = $this->normToModel($normData);
         $viewData = $this->normToView($normData);
     } catch (TransformationFailedException $e) {
         $this->synchronized = false;
         // If $viewData was not yet set, set it to $submittedData so that
         // the erroneous data is accessible on the form.
         if (null === $viewData) {
             $viewData = $submittedData;
         }
     }
     $this->bound = true;
     $this->modelData = $modelData;
     $this->normData = $normData;
     $this->viewData = $viewData;
     if ($dispatcher->hasListeners(FormEvents::POST_BIND)) {
         $event = new FormEvent($this, $viewData);
         $dispatcher->dispatch(FormEvents::POST_BIND, $event);
     }
     set_error_handler(array('Symfony\\Component\\Form\\Test\\DeprecationErrorHandler', 'handleBC'));
     $validators = $this->config->getValidators();
     restore_error_handler();
     foreach ($validators as $validator) {
         trigger_error(sprintf('FormConfigInterface::getValidators() is deprecated since 2.1 and will be removed in 2.3. Convert your %s class to a listener on the FormEvents::POST_BIND event.', get_class($validator)), E_USER_DEPRECATED);
         $validator->validate($this);
     }
     return $this;
 }
Ejemplo n.º 3
0
 /**
  * {@inheritdoc}
  */
 public function bind($submittedData)
 {
     if ($this->bound) {
         throw new AlreadyBoundException('A form can only be bound once');
     }
     if ($this->isDisabled()) {
         $this->bound = true;
         return $this;
     }
     // The data must be initialized if it was not initialized yet.
     // This is necessary to guarantee that the *_SET_DATA listeners
     // are always invoked before bind() takes place.
     if (!$this->initialized) {
         $this->setData($this->config->getData());
     }
     // Don't convert NULL to a string here in order to determine later
     // whether an empty value has been submitted or whether no value has
     // been submitted at all. This is important for processing checkboxes
     // and radio buttons with empty values.
     if (is_scalar($submittedData)) {
         $submittedData = (string) $submittedData;
     }
     // Initialize errors in the very beginning so that we don't lose any
     // errors added during listeners
     $this->errors = array();
     $dispatcher = $this->config->getEventDispatcher();
     // Hook to change content of the data bound by the browser
     if ($dispatcher->hasListeners(FormEvents::PRE_BIND) || $dispatcher->hasListeners(FormEvents::BIND_CLIENT_DATA)) {
         $event = new FormEvent($this, $submittedData);
         $dispatcher->dispatch(FormEvents::PRE_BIND, $event);
         // BC until 2.3
         $dispatcher->dispatch(FormEvents::BIND_CLIENT_DATA, $event);
         $submittedData = $event->getData();
     }
     // Check whether the form is compound.
     // This check is preferrable over checking the number of children,
     // since forms without children may also be compound.
     // (think of empty collection forms)
     if ($this->config->getCompound()) {
         if (!is_array($submittedData)) {
             $submittedData = array();
         }
         foreach ($this->children as $name => $child) {
             $child->bind(isset($submittedData[$name]) ? $submittedData[$name] : null);
             unset($submittedData[$name]);
         }
         $this->extraData = $submittedData;
         // If the form is compound, the default data in view format
         // is reused. The data of the children is merged into this
         // default data using the data mapper.
         $viewData = $this->viewData;
     } else {
         // If the form is not compound, the submitted data is also the data in view format.
         $viewData = $submittedData;
     }
     if (FormUtil::isEmpty($viewData)) {
         $emptyData = $this->config->getEmptyData();
         if ($emptyData instanceof \Closure) {
             /* @var \Closure $emptyData */
             $emptyData = $emptyData($this, $viewData);
         }
         $viewData = $emptyData;
     }
     // Merge form data from children into existing view data
     // It is not necessary to invoke this method if the form has no children,
     // even if it is compound.
     if (count($this->children) > 0) {
         $this->config->getDataMapper()->mapFormsToData($this->children, $viewData);
     }
     $modelData = null;
     $normData = null;
     try {
         // Normalize data to unified representation
         $normData = $this->viewToNorm($viewData);
         // Hook to change content of the data into the normalized
         // representation
         if ($dispatcher->hasListeners(FormEvents::BIND) || $dispatcher->hasListeners(FormEvents::BIND_NORM_DATA)) {
             $event = new FormEvent($this, $normData);
             $dispatcher->dispatch(FormEvents::BIND, $event);
             // BC until 2.3
             $dispatcher->dispatch(FormEvents::BIND_NORM_DATA, $event);
             $normData = $event->getData();
         }
         // Synchronize representations - must not change the content!
         $modelData = $this->normToModel($normData);
         $viewData = $this->normToView($normData);
     } catch (TransformationFailedException $e) {
         $this->synchronized = false;
     }
     $this->bound = true;
     $this->modelData = $modelData;
     $this->normData = $normData;
     $this->viewData = $viewData;
     if ($dispatcher->hasListeners(FormEvents::POST_BIND)) {
         $event = new FormEvent($this, $viewData);
         $dispatcher->dispatch(FormEvents::POST_BIND, $event);
     }
     foreach ($this->config->getValidators() as $validator) {
         $validator->validate($this);
     }
     return $this;
 }
Ejemplo n.º 4
0
 /**
  * Creates an unmodifiable copy of a given configuration.
  *
  * @param  FormConfigInterface $config The configuration to copy.
  */
 public function __construct(FormConfigInterface $config)
 {
     $dispatcher = $config->getEventDispatcher();
     if (!$dispatcher instanceof UnmodifiableEventDispatcher) {
         $dispatcher = new UnmodifiableEventDispatcher($dispatcher);
     }
     $this->dispatcher = $dispatcher;
     $this->name = $config->getName();
     $this->propertyPath = $config->getPropertyPath();
     $this->mapped = $config->getMapped();
     $this->byReference = $config->getByReference();
     $this->virtual = $config->getVirtual();
     $this->compound = $config->getCompound();
     $this->types = $config->getTypes();
     $this->viewTransformers = $config->getViewTransformers();
     $this->modelTransformers = $config->getModelTransformers();
     $this->dataMapper = $config->getDataMapper();
     $this->validators = $config->getValidators();
     $this->required = $config->getRequired();
     $this->disabled = $config->getDisabled();
     $this->errorBubbling = $config->getErrorBubbling();
     $this->emptyData = $config->getEmptyData();
     $this->attributes = $config->getAttributes();
     $this->data = $config->getData();
     $this->dataClass = $config->getDataClass();
     $this->options = $config->getOptions();
 }
Ejemplo n.º 5
0
 /**
  * Binds data to the form, transforms and validates it.
  *
  * @param string|array $submittedData The data
  *
  * @return Form The current form
  *
  * @throws UnexpectedTypeException
  */
 public function bind($submittedData)
 {
     if ($this->bound) {
         throw new AlreadyBoundException('A form can only be bound once');
     }
     if ($this->isDisabled()) {
         $this->bound = true;
         return $this;
     }
     // Don't convert NULL to a string here in order to determine later
     // whether an empty value has been submitted or whether no value has
     // been submitted at all. This is important for processing checkboxes
     // and radio buttons with empty values.
     if (is_scalar($submittedData)) {
         $submittedData = (string) $submittedData;
     }
     // Initialize errors in the very beginning so that we don't lose any
     // errors added during listeners
     $this->errors = array();
     $modelData = null;
     $normData = null;
     $extraData = array();
     $synchronized = false;
     // Hook to change content of the data bound by the browser
     $event = new FormEvent($this, $submittedData);
     $this->config->getEventDispatcher()->dispatch(FormEvents::PRE_BIND, $event);
     // BC until 2.3
     $this->config->getEventDispatcher()->dispatch(FormEvents::BIND_CLIENT_DATA, $event);
     $submittedData = $event->getData();
     // Check whether the form is compound.
     // This check is preferrable over checking the number of children,
     // since forms without children may also be compound.
     // (think of empty collection forms)
     if ($this->config->getCompound()) {
         if (null === $submittedData || '' === $submittedData) {
             $submittedData = array();
         }
         if (!is_array($submittedData)) {
             throw new UnexpectedTypeException($submittedData, 'array');
         }
         foreach ($this->children as $name => $child) {
             if (!isset($submittedData[$name])) {
                 $submittedData[$name] = null;
             }
         }
         foreach ($submittedData as $name => $value) {
             if ($this->has($name)) {
                 $this->children[$name]->bind($value);
             } else {
                 $extraData[$name] = $value;
             }
         }
     }
     // By default, the submitted data is also the data in view format
     $viewData = $submittedData;
     // If the form is compound, the default data in view format
     // is reused. The data of the children is merged into this
     // default data using the data mapper.
     if ($this->config->getCompound() && $this->config->getDataMapper()) {
         $viewData = $this->getViewData();
     }
     if (null === $viewData || '' === $viewData) {
         $emptyData = $this->config->getEmptyData();
         if ($emptyData instanceof \Closure) {
             /* @var \Closure $emptyData */
             $emptyData = $emptyData($this, $viewData);
         }
         $viewData = $emptyData;
     }
     // Merge form data from children into existing view data
     if ($this->config->getCompound() && $this->config->getDataMapper() && null !== $viewData) {
         $this->config->getDataMapper()->mapFormsToData($this->children, $viewData);
     }
     try {
         // Normalize data to unified representation
         $normData = $this->viewToNorm($viewData);
         $synchronized = true;
     } catch (TransformationFailedException $e) {
     }
     if ($synchronized) {
         // Hook to change content of the data into the normalized
         // representation
         $event = new FormEvent($this, $normData);
         $this->config->getEventDispatcher()->dispatch(FormEvents::BIND, $event);
         // BC until 2.3
         $this->config->getEventDispatcher()->dispatch(FormEvents::BIND_NORM_DATA, $event);
         $normData = $event->getData();
         // Synchronize representations - must not change the content!
         $modelData = $this->normToModel($normData);
         $viewData = $this->normToView($normData);
     }
     $this->bound = true;
     $this->modelData = $modelData;
     $this->normData = $normData;
     $this->viewData = $viewData;
     $this->extraData = $extraData;
     $this->synchronized = $synchronized;
     $event = new FormEvent($this, $viewData);
     $this->config->getEventDispatcher()->dispatch(FormEvents::POST_BIND, $event);
     foreach ($this->config->getValidators() as $validator) {
         $validator->validate($this);
     }
     return $this;
 }