/** * Updates the form with default data. * * @param array $modelData The data formatted as expected for the underlying object * * @return Form The current form */ public function setData($modelData) { if ($this->bound) { throw new AlreadyBoundException('You cannot change the data of a bound form'); } // Don't allow modifications of the configured data if the data is locked if ($this->config->getDataLocked() && $modelData !== $this->config->getData()) { return $this; } if (is_object($modelData) && !$this->config->getByReference()) { $modelData = clone $modelData; } // Hook to change content of the data $event = new FormEvent($this, $modelData); $this->config->getEventDispatcher()->dispatch(FormEvents::PRE_SET_DATA, $event); // BC until 2.3 $this->config->getEventDispatcher()->dispatch(FormEvents::SET_DATA, $event); $modelData = $event->getData(); // Treat data as strings unless a value transformer exists if (!$this->config->getViewTransformers() && !$this->config->getModelTransformers() && is_scalar($modelData)) { $modelData = (string) $modelData; } // Synchronize representations - must not change the content! $normData = $this->modelToNorm($modelData); $viewData = $this->normToView($normData); // Validate if view data matches data class (unless empty) if (!FormUtil::isEmpty($viewData)) { $dataClass = $this->config->getDataClass(); $actualType = is_object($viewData) ? 'an instance of class ' . get_class($viewData) : ' a(n) ' . gettype($viewData); if (null === $dataClass && is_object($viewData) && !$viewData instanceof \ArrayAccess) { $expectedType = 'scalar, array or an instance of \\ArrayAccess'; throw new FormException('The form\'s view data is expected to be of type ' . $expectedType . ', ' . 'but is ' . $actualType . '. You ' . 'can avoid this error by setting the "data_class" option to ' . '"' . get_class($viewData) . '" or by adding a view transformer ' . 'that transforms ' . $actualType . ' to ' . $expectedType . '.'); } if (null !== $dataClass && !$viewData instanceof $dataClass) { throw new FormException('The form\'s view data is expected to be an instance of class ' . $dataClass . ', but is ' . $actualType . '. You can avoid this error ' . 'by setting the "data_class" option to null or by adding a view ' . 'transformer that transforms ' . $actualType . ' to an instance of ' . $dataClass . '.'); } } $this->modelData = $modelData; $this->normData = $normData; $this->viewData = $viewData; $this->synchronized = true; if ($this->config->getCompound()) { // Update child forms from the data $this->config->getDataMapper()->mapDataToForms($viewData, $this->children); } $event = new FormEvent($this, $modelData); $this->config->getEventDispatcher()->dispatch(FormEvents::POST_SET_DATA, $event); return $this; }
/** * {@inheritdoc} */ public function setData($modelData) { // If the form is submitted while disabled, it is set to submitted, but the data is not // changed. In such cases (i.e. when the form is not initialized yet) don't // abort this method. if ($this->submitted && $this->defaultDataSet) { throw new AlreadySubmittedException('You cannot change the data of a submitted form.'); } // If the form inherits its parent's data, disallow data setting to // prevent merge conflicts if ($this->config->getInheritData()) { throw new RuntimeException('You cannot change the data of a form inheriting its parent data.'); } // Don't allow modifications of the configured data if the data is locked if ($this->config->getDataLocked() && $modelData !== $this->config->getData()) { return $this; } if (is_object($modelData) && !$this->config->getByReference()) { $modelData = clone $modelData; } if ($this->lockSetData) { throw new RuntimeException('A cycle was detected. Listeners to the PRE_SET_DATA event must not call setData(). You should call setData() on the FormEvent object instead.'); } $this->lockSetData = true; $dispatcher = $this->config->getEventDispatcher(); // Hook to change content of the data if ($dispatcher->hasListeners(FormEvents::PRE_SET_DATA)) { $event = new FormEvent($this, $modelData); $dispatcher->dispatch(FormEvents::PRE_SET_DATA, $event); $modelData = $event->getData(); } // Treat data as strings unless a value transformer exists if (!$this->config->getViewTransformers() && !$this->config->getModelTransformers() && is_scalar($modelData)) { $modelData = (string) $modelData; } // Synchronize representations - must not change the content! $normData = $this->modelToNorm($modelData); $viewData = $this->normToView($normData); // Validate if view data matches data class (unless empty) if (!FormUtil::isEmpty($viewData)) { $dataClass = $this->config->getDataClass(); if (null !== $dataClass && !$viewData instanceof $dataClass) { $actualType = is_object($viewData) ? 'an instance of class ' . get_class($viewData) : 'a(n) ' . gettype($viewData); throw new LogicException('The form\'s view data is expected to be an instance of class ' . $dataClass . ', but is ' . $actualType . '. You can avoid this error ' . 'by setting the "data_class" option to null or by adding a view ' . 'transformer that transforms ' . $actualType . ' to an instance of ' . $dataClass . '.'); } } $this->modelData = $modelData; $this->normData = $normData; $this->viewData = $viewData; $this->defaultDataSet = true; $this->lockSetData = false; // It is not necessary to invoke this method if the form doesn't have children, // even if the form is compound. if (count($this->children) > 0) { // Update child forms from the data $iterator = new InheritDataAwareIterator($this->children); $iterator = new \RecursiveIteratorIterator($iterator); $this->config->getDataMapper()->mapDataToForms($viewData, $iterator); } if ($dispatcher->hasListeners(FormEvents::POST_SET_DATA)) { $event = new FormEvent($this, $modelData); $dispatcher->dispatch(FormEvents::POST_SET_DATA, $event); } return $this; }
/** * {@inheritdoc} */ public function setData($modelData) { // If the form is bound while disabled, it is set to bound, but the data is not // changed. In such cases (i.e. when the form is not initialized yet) don't // abort this method. if ($this->bound && $this->initialized) { throw new AlreadyBoundException('You cannot change the data of a bound form'); } // Don't allow modifications of the configured data if the data is locked if ($this->config->getDataLocked() && $modelData !== $this->config->getData()) { return $this; } if (is_object($modelData) && !$this->config->getByReference()) { $modelData = clone $modelData; } if ($this->lockSetData) { throw new Exception('A cycle was detected. Listeners to the PRE_SET_DATA event must not call setData(). You should call setData() on the FormEvent object instead.'); } $this->lockSetData = true; $dispatcher = $this->config->getEventDispatcher(); // Hook to change content of the data if ($dispatcher->hasListeners(FormEvents::PRE_SET_DATA) || $dispatcher->hasListeners(FormEvents::SET_DATA)) { $event = new FormEvent($this, $modelData); $dispatcher->dispatch(FormEvents::PRE_SET_DATA, $event); // BC until 2.3 if ($dispatcher->hasListeners(FormEvents::SET_DATA)) { trigger_error('The FormEvents::SET_DATA event is deprecated since 2.1 and will be removed in 2.3. Use the FormEvents::PRE_SET_DATA event instead.', E_USER_DEPRECATED); } $dispatcher->dispatch(FormEvents::SET_DATA, $event); $modelData = $event->getData(); } // Treat data as strings unless a value transformer exists if (!$this->config->getViewTransformers() && !$this->config->getModelTransformers() && is_scalar($modelData)) { $modelData = (string) $modelData; } // Synchronize representations - must not change the content! $normData = $this->modelToNorm($modelData); $viewData = $this->normToView($normData); // Validate if view data matches data class (unless empty) if (!FormUtil::isEmpty($viewData)) { $dataClass = $this->config->getDataClass(); $actualType = is_object($viewData) ? 'an instance of class ' . get_class($viewData) : ' a(n) ' . gettype($viewData); if (null === $dataClass && is_object($viewData) && !$viewData instanceof \ArrayAccess) { $expectedType = 'scalar, array or an instance of \\ArrayAccess'; throw new Exception('The form\'s view data is expected to be of type ' . $expectedType . ', ' . 'but is ' . $actualType . '. You ' . 'can avoid this error by setting the "data_class" option to ' . '"' . get_class($viewData) . '" or by adding a view transformer ' . 'that transforms ' . $actualType . ' to ' . $expectedType . '.'); } if (null !== $dataClass && !$viewData instanceof $dataClass) { throw new Exception('The form\'s view data is expected to be an instance of class ' . $dataClass . ', but is ' . $actualType . '. You can avoid this error ' . 'by setting the "data_class" option to null or by adding a view ' . 'transformer that transforms ' . $actualType . ' to an instance of ' . $dataClass . '.'); } } $this->modelData = $modelData; $this->normData = $normData; $this->viewData = $viewData; $this->initialized = true; $this->lockSetData = false; // It is not necessary to invoke this method if the form doesn't have children, // even if the form is compound. if (count($this->children) > 0) { // Update child forms from the data $this->config->getDataMapper()->mapDataToForms($viewData, $this->children); } if ($dispatcher->hasListeners(FormEvents::POST_SET_DATA)) { $event = new FormEvent($this, $modelData); $dispatcher->dispatch(FormEvents::POST_SET_DATA, $event); } return $this; }
/** * 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(); }