2010-06-24 09:40:05 +01:00
< ? php
/*
2011-01-15 13:29:43 +00:00
* This file is part of the Symfony package .
2010-10-02 11:38:11 +01:00
*
2011-03-06 11:40:06 +00:00
* ( c ) Fabien Potencier < fabien @ symfony . com >
2010-06-24 09:40:05 +01:00
*
2011-01-15 13:29:43 +00:00
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
2010-06-24 09:40:05 +01:00
*/
2011-01-15 13:29:43 +00:00
namespace Symfony\Component\Form ;
2013-01-05 13:26:33 +00:00
use Symfony\Component\Form\Exception\RuntimeException ;
2012-12-14 15:05:05 +00:00
use Symfony\Component\Form\Exception\UnexpectedTypeException ;
2013-04-20 16:32:55 +01:00
use Symfony\Component\Form\Exception\AlreadySubmittedException ;
2011-04-22 16:41:21 +01:00
use Symfony\Component\Form\Exception\TransformationFailedException ;
2013-04-15 21:11:02 +01:00
use Symfony\Component\Form\Exception\LogicException ;
use Symfony\Component\Form\Exception\OutOfBoundsException ;
2012-07-06 15:46:24 +01:00
use Symfony\Component\Form\Util\FormUtil ;
2013-01-05 13:26:33 +00:00
use Symfony\Component\Form\Util\InheritDataAwareIterator ;
2013-08-24 16:43:39 +01:00
use Symfony\Component\Form\Util\OrderedHashMap ;
2013-01-07 08:19:31 +00:00
use Symfony\Component\PropertyAccess\PropertyPath ;
2010-10-02 11:38:11 +01:00
2010-06-24 09:40:05 +01:00
/**
* Form represents a form .
*
2011-03-20 12:35:19 +00:00
* To implement your own form fields , you need to have a thorough understanding
2012-05-27 20:41:59 +01:00
* of the data flow within a form . A form stores its data in three different
* representations :
2011-03-20 12:35:19 +00:00
*
2012-05-27 20:41:59 +01:00
* ( 1 ) the " model " format required by the form ' s object
* ( 2 ) the " normalized " format for internal processing
* ( 3 ) the " view " format used for display
2011-03-20 12:35:19 +00:00
*
* A date field , for example , may store a date as " Y-m-d " string ( 1 ) in the
* object . To facilitate processing in the field , this value is normalized
* to a DateTime object ( 2 ) . In the HTML representation of your form , a
* localized string ( 3 ) is presented to and modified by the user .
*
* In most cases , format ( 1 ) and format ( 2 ) will be the same . For example ,
2012-05-27 20:41:59 +01:00
* a checkbox field uses a Boolean value for both internal processing and
2011-03-20 12:35:19 +00:00
* storage in the object . In these cases you simply need to set a value
* transformer to convert between formats ( 2 ) and ( 3 ) . You can do this by
2012-05-27 20:41:59 +01:00
* calling addViewTransformer () .
2011-03-20 12:35:19 +00:00
*
* In some cases though it makes sense to make format ( 1 ) configurable . To
* demonstrate this , let ' s extend our above date field to store the value
* either as " Y-m-d " string or as timestamp . Internally we still want to
* use a DateTime object for processing . To convert the data from string / integer
* to DateTime you can set a normalization transformer by calling
2012-05-27 20:41:59 +01:00
* addNormTransformer () . The normalized data is then converted to the displayed
* data as described before .
*
* The conversions ( 1 ) -> ( 2 ) -> ( 3 ) use the transform methods of the transformers .
* The conversions ( 3 ) -> ( 2 ) -> ( 1 ) use the reverseTransform methods of the transformers .
2011-03-20 12:35:19 +00:00
*
2011-03-06 11:40:06 +00:00
* @ author Fabien Potencier < fabien @ symfony . com >
2012-05-26 08:48:33 +01:00
* @ author Bernhard Schussek < bschussek @ gmail . com >
2010-06-24 09:40:05 +01:00
*/
2011-03-20 12:35:19 +00:00
class Form implements \IteratorAggregate , FormInterface
2010-06-24 09:40:05 +01:00
{
2011-01-25 08:56:37 +00:00
/**
2012-05-16 18:25:27 +01:00
* The form ' s configuration
* @ var FormConfigInterface
2011-03-31 14:23:33 +01:00
*/
2012-05-16 18:25:27 +01:00
private $config ;
2011-03-31 14:23:33 +01:00
/**
2011-05-10 14:32:14 +01:00
* The parent of this form
2011-03-31 14:23:33 +01:00
* @ var FormInterface
*/
private $parent ;
/**
* The children of this form
2013-08-24 16:43:39 +01:00
* @ var FormInterface [] A map of FormInterface instances
2011-01-25 08:56:37 +00:00
*/
2013-08-24 16:43:39 +01:00
private $children ;
2011-03-20 12:35:19 +00:00
2011-03-31 14:23:33 +01:00
/**
* The errors of this form
2012-11-01 15:08:59 +00:00
* @ var FormError [] An array of FormError instances
2011-03-31 14:23:33 +01:00
*/
2011-03-20 12:35:19 +00:00
private $errors = array ();
2011-03-31 14:23:33 +01:00
/**
2013-04-20 16:32:55 +01:00
* Whether this form was submitted
2014-04-16 11:30:19 +01:00
* @ var bool
2011-03-31 14:23:33 +01:00
*/
2013-04-20 16:32:55 +01:00
private $submitted = false ;
2011-03-31 14:23:33 +01:00
2013-11-09 15:25:41 +00:00
/**
* The button that was used to submit the form
* @ var Button
*/
private $clickedButton ;
2011-03-31 14:23:33 +01:00
/**
2012-05-23 19:21:34 +01:00
* The form data in model format
2011-03-31 14:23:33 +01:00
* @ var mixed
*/
2012-05-23 19:21:34 +01:00
private $modelData ;
2011-03-31 14:23:33 +01:00
/**
* The form data in normalized format
* @ var mixed
*/
2011-03-20 12:35:19 +00:00
private $normData ;
2011-03-31 14:23:33 +01:00
/**
2012-05-23 19:21:34 +01:00
* The form data in view format
2011-03-31 14:23:33 +01:00
* @ var mixed
*/
2012-05-23 19:21:34 +01:00
private $viewData ;
2011-01-29 21:39:36 +00:00
/**
2013-04-20 16:32:55 +01:00
* The submitted values that don ' t belong to any children
2011-01-29 21:39:36 +00:00
* @ var array
*/
2011-03-20 11:00:19 +00:00
private $extraData = array ();
2010-06-24 10:24:08 +01:00
2011-03-31 14:23:33 +01:00
/**
2012-05-23 19:21:34 +01:00
* Whether the data in model , normalized and view format is
2011-03-31 14:23:33 +01:00
* synchronized . Data may not be synchronized if transformation errors
* occur .
2014-04-16 11:30:19 +01:00
* @ var bool
2011-03-31 14:23:33 +01:00
*/
2011-03-22 01:03:22 +00:00
private $synchronized = true ;
2011-03-31 14:23:33 +01:00
2012-07-16 11:47:05 +01:00
/**
* Whether the form ' s data has been initialized .
*
* When the data is initialized with its default value , that default value
* is passed through the transformer chain in order to synchronize the
* model , normalized and view format for the first time . This is done
* lazily in order to save performance when { @ link setData ()} is called
* manually , making the initialization with the configured default value
* superfluous .
*
2014-04-16 11:30:19 +01:00
* @ var bool
2012-07-16 11:47:05 +01:00
*/
2013-01-05 13:26:33 +00:00
private $defaultDataSet = false ;
2012-07-16 11:47:05 +01:00
/**
* Whether setData () is currently being called .
2014-04-16 11:30:19 +01:00
* @ var bool
2012-07-16 11:47:05 +01:00
*/
private $lockSetData = false ;
2011-03-31 14:23:33 +01:00
/**
2012-05-16 18:25:27 +01:00
* Creates a new form based on the given configuration .
*
* @ param FormConfigInterface $config The form configuration .
2012-08-27 01:03:52 +01:00
*
2013-04-15 21:11:02 +01:00
* @ throws LogicException if a data mapper is not provided for a compound form
2011-03-31 14:23:33 +01:00
*/
2012-05-16 18:25:27 +01:00
public function __construct ( FormConfigInterface $config )
2011-03-01 13:19:28 +00:00
{
2012-07-06 14:33:06 +01:00
// Compound forms always need a data mapper, otherwise calls to
// `setData` and `add` will not lead to the correct population of
// the child forms.
if ( $config -> getCompound () && ! $config -> getDataMapper ()) {
2013-04-15 21:11:02 +01:00
throw new LogicException ( 'Compound forms need a data mapper' );
2012-07-06 14:33:06 +01:00
}
2013-01-05 13:26:33 +00:00
// If the form inherits the data from its parent, it is not necessary
// to call setData() with the default data.
if ( $config -> getInheritData ()) {
$this -> defaultDataSet = true ;
}
2012-05-16 18:25:27 +01:00
$this -> config = $config ;
2013-08-24 16:43:39 +01:00
$this -> children = new OrderedHashMap ();
2011-03-01 13:19:28 +00:00
}
2011-03-21 21:10:53 +00:00
public function __clone ()
2011-01-29 21:39:36 +00:00
{
2013-10-30 22:44:30 +00:00
$this -> children = clone $this -> children ;
2013-11-22 17:29:47 +00:00
2011-03-21 21:10:53 +00:00
foreach ( $this -> children as $key => $child ) {
$this -> children [ $key ] = clone $child ;
}
2011-03-18 11:50:26 +00:00
}
2011-01-29 21:39:36 +00:00
2012-05-16 18:25:27 +01:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2012-05-16 18:25:27 +01:00
*/
public function getConfig ()
{
return $this -> config ;
}
2011-03-20 12:35:19 +00:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
public function getName ()
2011-03-18 11:50:26 +00:00
{
2012-05-16 18:25:27 +01:00
return $this -> config -> getName ();
2011-03-20 12:35:19 +00:00
}
2011-01-29 21:39:36 +00:00
2012-05-17 15:09:13 +01:00
/**
* { @ inheritdoc }
*/
public function getPropertyPath ()
{
2012-05-18 10:20:03 +01:00
if ( null !== $this -> config -> getPropertyPath ()) {
2012-05-17 15:09:13 +01:00
return $this -> config -> getPropertyPath ();
}
if ( null === $this -> getName () || '' === $this -> getName ()) {
2014-04-16 08:15:58 +01:00
return ;
2012-05-17 15:09:13 +01:00
}
2013-01-05 13:26:33 +00:00
$parent = $this -> parent ;
while ( $parent && $parent -> getConfig () -> getInheritData ()) {
$parent = $parent -> getParent ();
}
if ( $parent && null === $parent -> getConfig () -> getDataClass ()) {
2013-04-02 10:39:57 +01:00
return new PropertyPath ( '[' . $this -> getName () . ']' );
2012-05-17 15:09:13 +01:00
}
return new PropertyPath ( $this -> getName ());
}
2011-03-20 12:35:19 +00:00
/**
2012-05-16 18:25:27 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
public function isRequired ()
{
if ( null === $this -> parent || $this -> parent -> isRequired ()) {
2012-05-16 18:25:27 +01:00
return $this -> config -> getRequired ();
2011-03-20 12:35:19 +00:00
}
2011-01-29 21:39:36 +00:00
2011-03-20 12:35:19 +00:00
return false ;
}
2011-01-29 21:39:36 +00:00
2011-03-20 12:35:19 +00:00
/**
2014-04-15 06:57:34 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
2012-01-26 15:54:42 +00:00
public function isDisabled ()
2011-03-20 12:35:19 +00:00
{
2012-01-26 15:54:42 +00:00
if ( null === $this -> parent || ! $this -> parent -> isDisabled ()) {
2012-05-16 18:25:27 +01:00
return $this -> config -> getDisabled ();
2011-01-29 21:39:36 +00:00
}
2011-03-20 12:35:19 +00:00
return true ;
2011-01-29 21:39:36 +00:00
}
2011-03-20 12:35:19 +00:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
public function setParent ( FormInterface $parent = null )
2011-01-29 21:39:36 +00:00
{
2013-04-20 16:32:55 +01:00
if ( $this -> submitted ) {
throw new AlreadySubmittedException ( 'You cannot set the parent of a submitted form' );
2012-02-10 12:47:43 +00:00
}
2012-08-26 20:13:38 +01:00
if ( null !== $parent && '' === $this -> config -> getName ()) {
2013-04-15 21:11:02 +01:00
throw new LogicException ( 'A form with an empty name cannot have a parent form.' );
2012-01-07 14:14:50 +00:00
}
2011-03-20 12:35:19 +00:00
$this -> parent = $parent ;
2011-01-29 21:39:36 +00:00
2011-03-20 12:35:19 +00:00
return $this ;
2011-01-29 21:39:36 +00:00
}
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-01-29 21:39:36 +00:00
*/
2011-03-20 12:35:19 +00:00
public function getParent ()
2011-01-29 21:39:36 +00:00
{
2011-03-20 12:35:19 +00:00
return $this -> parent ;
2011-01-29 21:39:36 +00:00
}
2011-03-20 12:35:19 +00:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
public function getRoot ()
{
return $this -> parent ? $this -> parent -> getRoot () : $this ;
2011-01-29 21:39:36 +00:00
}
2011-03-20 12:35:19 +00:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
public function isRoot ()
2011-01-29 21:39:36 +00:00
{
2012-08-26 19:17:24 +01:00
return null === $this -> parent ;
2011-03-20 12:35:19 +00:00
}
2011-03-18 11:50:26 +00:00
2011-03-20 12:35:19 +00:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
2012-05-23 19:21:34 +01:00
public function setData ( $modelData )
2011-03-20 12:35:19 +00:00
{
2013-04-20 16:32:55 +01:00
// If the form is submitted while disabled, it is set to submitted, but the data is not
2012-07-16 11:47:05 +01:00
// changed. In such cases (i.e. when the form is not initialized yet) don't
// abort this method.
2013-04-20 16:32:55 +01:00
if ( $this -> submitted && $this -> defaultDataSet ) {
throw new AlreadySubmittedException ( 'You cannot change the data of a submitted form.' );
2013-01-05 13:26:33 +00:00
}
// 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.' );
2012-02-10 12:47:43 +00:00
}
2012-07-09 20:04:24 +01:00
// Don't allow modifications of the configured data if the data is locked
if ( $this -> config -> getDataLocked () && $modelData !== $this -> config -> getData ()) {
return $this ;
}
2012-05-23 19:21:34 +01:00
if ( is_object ( $modelData ) && ! $this -> config -> getByReference ()) {
$modelData = clone $modelData ;
2012-05-23 13:51:26 +01:00
}
2012-07-16 11:47:05 +01:00
if ( $this -> lockSetData ) {
2013-01-05 13:26:33 +00:00
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.' );
2012-07-16 11:47:05 +01:00
}
$this -> lockSetData = true ;
2012-07-28 07:47:13 +01:00
$dispatcher = $this -> config -> getEventDispatcher ();
2012-07-16 11:47:05 +01:00
2011-03-20 12:35:19 +00:00
// Hook to change content of the data
2013-03-01 09:41:59 +00:00
if ( $dispatcher -> hasListeners ( FormEvents :: PRE_SET_DATA )) {
2012-07-28 07:47:13 +01:00
$event = new FormEvent ( $this , $modelData );
$dispatcher -> dispatch ( FormEvents :: PRE_SET_DATA , $event );
$modelData = $event -> getData ();
}
2011-03-20 12:35:19 +00:00
2011-03-27 22:09:46 +01:00
// Treat data as strings unless a value transformer exists
2012-05-23 19:21:34 +01:00
if ( ! $this -> config -> getViewTransformers () && ! $this -> config -> getModelTransformers () && is_scalar ( $modelData )) {
$modelData = ( string ) $modelData ;
2011-03-18 11:50:26 +00:00
}
2011-03-20 12:35:19 +00:00
// Synchronize representations - must not change the content!
2012-05-23 19:21:34 +01:00
$normData = $this -> modelToNorm ( $modelData );
$viewData = $this -> normToView ( $normData );
2011-03-20 12:35:19 +00:00
2012-05-23 19:21:34 +01:00
// Validate if view data matches data class (unless empty)
2012-07-06 15:46:24 +01:00
if ( ! FormUtil :: isEmpty ( $viewData )) {
2012-05-17 15:09:13 +01:00
$dataClass = $this -> config -> getDataClass ();
2013-04-02 10:39:57 +01:00
$actualType = is_object ( $viewData ) ? 'an instance of class ' . get_class ( $viewData ) : ' a(n) ' . gettype ( $viewData );
2012-06-12 14:56:59 +01:00
2012-05-23 19:21:34 +01:00
if ( null === $dataClass && is_object ( $viewData ) && ! $viewData instanceof \ArrayAccess ) {
2012-05-22 17:24:59 +01:00
$expectedType = 'scalar, array or an instance of \ArrayAccess' ;
2012-05-20 10:18:31 +01:00
2013-04-15 21:11:02 +01:00
throw new LogicException (
2013-04-02 10:39:57 +01:00
'The form\'s view data is expected to be of type ' . $expectedType . ', ' .
'but is ' . $actualType . '. You ' .
2012-05-20 10:18:31 +01:00
'can avoid this error by setting the "data_class" option to ' .
2013-04-02 10:39:57 +01:00
'"' . get_class ( $viewData ) . '" or by adding a view transformer ' .
'that transforms ' . $actualType . ' to ' . $expectedType . '.'
2012-05-20 10:18:31 +01:00
);
2012-05-17 15:09:13 +01:00
}
2012-05-23 19:21:34 +01:00
if ( null !== $dataClass && ! $viewData instanceof $dataClass ) {
2013-04-15 21:11:02 +01:00
throw new LogicException (
2012-05-23 19:21:34 +01:00
'The form\'s view data is expected to be an instance of class ' .
2013-04-02 10:39:57 +01:00
$dataClass . ', but is ' . $actualType . '. You can avoid this error ' .
2012-06-12 14:56:59 +01:00
'by setting the "data_class" option to null or by adding a view ' .
2013-04-02 10:39:57 +01:00
'transformer that transforms ' . $actualType . ' to an instance of ' .
$dataClass . '.'
2012-05-20 10:18:31 +01:00
);
2012-05-17 15:09:13 +01:00
}
}
2012-05-23 19:21:34 +01:00
$this -> modelData = $modelData ;
2011-03-20 12:35:19 +00:00
$this -> normData = $normData ;
2012-05-23 19:21:34 +01:00
$this -> viewData = $viewData ;
2013-01-05 13:26:33 +00:00
$this -> defaultDataSet = true ;
2012-07-16 11:47:05 +01:00
$this -> lockSetData = false ;
2011-03-20 12:35:19 +00:00
2012-07-16 11:47:05 +01:00
// 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 ) {
2011-03-20 12:35:19 +00:00
// Update child forms from the data
2013-08-24 16:43:39 +01:00
$iterator = new InheritDataAwareIterator ( $this -> children );
$iterator = new \RecursiveIteratorIterator ( $iterator );
$this -> config -> getDataMapper () -> mapDataToForms ( $viewData , $iterator );
2011-03-20 12:35:19 +00:00
}
2012-07-28 07:47:13 +01:00
if ( $dispatcher -> hasListeners ( FormEvents :: POST_SET_DATA )) {
$event = new FormEvent ( $this , $modelData );
$dispatcher -> dispatch ( FormEvents :: POST_SET_DATA , $event );
}
2011-03-20 12:35:19 +00:00
return $this ;
2011-01-29 21:39:36 +00:00
}
2011-03-20 12:35:19 +00:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-05-10 14:32:14 +01:00
*/
public function getData ()
{
2013-01-05 13:26:33 +00:00
if ( $this -> config -> getInheritData ()) {
if ( ! $this -> parent ) {
throw new RuntimeException ( 'The form is configured to inherit its parent\'s data, but does not have a parent.' );
}
return $this -> parent -> getData ();
}
if ( ! $this -> defaultDataSet ) {
2012-07-16 11:47:05 +01:00
$this -> setData ( $this -> config -> getData ());
}
2012-05-23 19:21:34 +01:00
return $this -> modelData ;
2011-05-10 14:32:14 +01:00
}
2012-07-16 11:47:05 +01:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2012-07-16 11:47:05 +01:00
*/
public function getNormData ()
{
2013-01-05 13:26:33 +00:00
if ( $this -> config -> getInheritData ()) {
if ( ! $this -> parent ) {
throw new RuntimeException ( 'The form is configured to inherit its parent\'s data, but does not have a parent.' );
}
return $this -> parent -> getNormData ();
}
if ( ! $this -> defaultDataSet ) {
2012-07-16 11:47:05 +01:00
$this -> setData ( $this -> config -> getData ());
}
return $this -> normData ;
}
2011-05-10 14:32:14 +01:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-05-10 14:32:14 +01:00
*/
2012-05-23 19:21:34 +01:00
public function getViewData ()
{
2013-01-05 13:26:33 +00:00
if ( $this -> config -> getInheritData ()) {
if ( ! $this -> parent ) {
throw new RuntimeException ( 'The form is configured to inherit its parent\'s data, but does not have a parent.' );
}
return $this -> parent -> getViewData ();
}
if ( ! $this -> defaultDataSet ) {
2012-07-16 11:47:05 +01:00
$this -> setData ( $this -> config -> getData ());
}
2012-05-23 19:21:34 +01:00
return $this -> viewData ;
}
2011-05-10 14:32:14 +01:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-05-10 14:32:14 +01:00
*/
public function getExtraData ()
{
return $this -> extraData ;
}
2013-04-29 16:31:30 +01:00
/**
* { @ inheritdoc }
*/
public function initialize ()
{
if ( null !== $this -> parent ) {
throw new RuntimeException ( 'Only root forms should be initialized.' );
}
// Guarantee that the *_SET_DATA events have been triggered once the
// form is initialized. This makes sure that dynamically added or
// removed fields are already visible after initialization.
if ( ! $this -> defaultDataSet ) {
$this -> setData ( $this -> config -> getData ());
}
return $this ;
}
2012-12-30 15:38:36 +00:00
/**
* { @ inheritdoc }
*/
2013-04-20 14:56:42 +01:00
public function handleRequest ( $request = null )
2012-12-30 15:38:36 +00:00
{
2013-04-20 14:56:42 +01:00
$this -> config -> getRequestHandler () -> handleRequest ( $this , $request );
2012-12-30 15:38:36 +00:00
return $this ;
}
2011-05-10 14:32:14 +01:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
2013-04-25 15:08:09 +01:00
public function submit ( $submittedData , $clearMissing = true )
2011-03-01 13:19:28 +00:00
{
2013-04-20 16:32:55 +01:00
if ( $this -> submitted ) {
throw new AlreadySubmittedException ( 'A form can only be submitted once' );
2012-02-10 12:47:43 +00:00
}
2013-01-05 13:26:33 +00:00
// Initialize errors in the very beginning so that we don't lose any
// errors added during listeners
$this -> errors = array ();
2013-04-20 16:32:55 +01:00
// Obviously, a disabled form should not change its data upon submission.
2012-01-26 15:54:42 +00:00
if ( $this -> isDisabled ()) {
2013-04-20 16:32:55 +01:00
$this -> submitted = true ;
2011-05-19 00:24:28 +01:00
2011-05-11 16:08:53 +01:00
return $this ;
2011-04-02 10:39:15 +01:00
}
2012-07-26 09:55:40 +01:00
// The data must be initialized if it was not initialized yet.
// This is necessary to guarantee that the *_SET_DATA listeners
2013-04-20 16:32:55 +01:00
// are always invoked before submit() takes place.
2013-01-05 13:26:33 +00:00
if ( ! $this -> defaultDataSet ) {
2012-07-26 09:55:40 +01:00
$this -> setData ( $this -> config -> getData ());
}
2013-04-22 13:33:42 +01:00
// Treat false as NULL to support binding false to checkboxes.
2012-04-10 10:51:28 +01:00
// 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.
2013-04-22 13:33:42 +01:00
if ( false === $submittedData ) {
$submittedData = null ;
} elseif ( is_scalar ( $submittedData )) {
2012-05-23 19:21:34 +01:00
$submittedData = ( string ) $submittedData ;
2011-03-20 12:35:19 +00:00
}
2011-03-16 17:20:13 +00:00
2012-07-28 07:47:13 +01:00
$dispatcher = $this -> config -> getEventDispatcher ();
2011-03-20 12:35:19 +00:00
2013-05-05 23:28:29 +01:00
$modelData = null ;
$normData = null ;
$viewData = null ;
2012-05-23 19:21:34 +01:00
2013-05-05 23:28:29 +01:00
try {
2013-09-10 21:24:28 +01:00
// Hook to change content of the data submitted by the browser
if ( $dispatcher -> hasListeners ( FormEvents :: PRE_SUBMIT )) {
2013-05-05 23:28:29 +01:00
$event = new FormEvent ( $this , $submittedData );
2013-09-10 21:24:28 +01:00
$dispatcher -> dispatch ( FormEvents :: PRE_SUBMIT , $event );
2013-05-05 23:28:29 +01:00
$submittedData = $event -> getData ();
2011-03-20 12:35:19 +00:00
}
2013-05-05 23:28:29 +01:00
// 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 ();
2013-04-25 15:08:09 +01:00
}
2013-01-05 13:26:33 +00:00
2013-05-05 23:28:29 +01:00
if ( ! is_array ( $submittedData )) {
throw new TransformationFailedException ( 'Compound forms expect an array or NULL on submission.' );
}
2011-03-20 12:35:19 +00:00
2013-09-10 21:24:28 +01:00
foreach ( $this -> children as $name => $child ) {
2014-03-28 09:30:00 +00:00
$isSubmitted = array_key_exists ( $name , $submittedData );
if ( $isSubmitted || $clearMissing ) {
$child -> submit ( $isSubmitted ? $submittedData [ $name ] : null , $clearMissing );
2013-09-10 21:24:28 +01:00
unset ( $submittedData [ $name ]);
2013-11-09 15:25:41 +00:00
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 ();
}
2013-09-10 21:24:28 +01:00
}
2013-01-05 13:26:33 +00:00
}
2011-03-27 22:07:30 +01:00
2013-05-05 23:28:29 +01:00
$this -> extraData = $submittedData ;
2011-03-20 12:35:19 +00:00
}
2012-04-10 10:51:28 +01:00
2013-09-10 21:24:28 +01:00
// 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 ()) {
2013-05-05 23:28:29 +01:00
// 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.
2013-09-10 21:24:28 +01:00
$viewData = $this -> config -> getCompound () ? $this -> viewData : $submittedData ;
if ( FormUtil :: isEmpty ( $viewData )) {
$emptyData = $this -> config -> getEmptyData ();
2012-04-10 10:51:28 +01:00
2013-09-10 21:24:28 +01:00
if ( $emptyData instanceof \Closure ) {
/* @var \Closure $emptyData */
$emptyData = $emptyData ( $this , $viewData );
}
2011-03-19 14:06:54 +00:00
2013-09-10 21:24:28 +01:00
$viewData = $emptyData ;
2013-05-05 23:28:29 +01:00
}
2011-03-19 14:06:54 +00:00
2013-09-10 21:24:28 +01:00
// 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 );
}
2011-04-02 11:00:19 +01:00
2013-01-05 13:26:33 +00:00
// Normalize data to unified representation
$normData = $this -> viewToNorm ( $viewData );
2012-08-25 00:14:13 +01:00
2013-09-10 21:24:28 +01:00
// Hook to change content of the data in the normalized
2013-01-05 13:26:33 +00:00
// representation
2013-04-20 16:32:55 +01:00
if ( $dispatcher -> hasListeners ( FormEvents :: SUBMIT )) {
2013-01-05 13:26:33 +00:00
$event = new FormEvent ( $this , $normData );
2013-04-20 16:32:55 +01:00
$dispatcher -> dispatch ( FormEvents :: SUBMIT , $event );
2013-01-05 13:26:33 +00:00
$normData = $event -> getData ();
}
2011-03-01 13:19:28 +00:00
2013-01-05 13:26:33 +00:00
// Synchronize representations - must not change the content!
$modelData = $this -> normToModel ( $normData );
$viewData = $this -> normToView ( $normData );
2012-07-28 07:47:13 +01:00
}
2012-07-11 15:49:59 +01:00
} catch ( TransformationFailedException $e ) {
2012-08-25 00:14:13 +01:00
$this -> synchronized = false ;
2013-05-05 23:28:29 +01:00
// If $viewData was not yet set, set it to $submittedData so that
// the erroneous data is accessible on the form.
2013-09-10 21:24:28 +01:00
// 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 ()) {
2013-05-05 23:28:29 +01:00
$viewData = $submittedData ;
}
2013-01-05 13:26:33 +00:00
}
2011-03-19 18:53:39 +00:00
2013-09-10 21:24:28 +01:00
$this -> submitted = true ;
2012-05-23 19:21:34 +01:00
$this -> modelData = $modelData ;
2011-03-20 12:35:19 +00:00
$this -> normData = $normData ;
2012-05-23 19:21:34 +01:00
$this -> viewData = $viewData ;
2011-03-19 18:53:39 +00:00
2013-04-20 16:32:55 +01:00
if ( $dispatcher -> hasListeners ( FormEvents :: POST_SUBMIT )) {
2012-07-28 07:47:13 +01:00
$event = new FormEvent ( $this , $viewData );
2013-04-20 16:32:55 +01:00
$dispatcher -> dispatch ( FormEvents :: POST_SUBMIT , $event );
2012-07-28 07:47:13 +01:00
}
2011-03-20 12:35:19 +00:00
2011-05-10 13:40:20 +01:00
return $this ;
2011-03-20 12:35:19 +00:00
}
2011-03-01 13:19:28 +00:00
2013-04-20 16:32:55 +01:00
/**
* Alias of { @ link submit ()} .
*
* @ deprecated Deprecated since version 2.3 , to be removed in 3.0 . Use
* { @ link submit ()} instead .
*/
public function bind ( $submittedData )
{
return $this -> submit ( $submittedData );
}
2011-03-20 12:35:19 +00:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
2011-03-21 20:01:14 +00:00
public function addError ( FormError $error )
2011-03-20 12:35:19 +00:00
{
2012-12-14 22:17:14 +00:00
if ( $this -> parent && $this -> config -> getErrorBubbling ()) {
2014-01-10 10:44:16 +00:00
if ( null === $error -> getOrigin ()) {
$error -> setOrigin ( $this );
}
2011-03-21 21:10:53 +00:00
$this -> parent -> addError ( $error );
} else {
$this -> errors [] = $error ;
}
2011-05-10 13:40:20 +01:00
return $this ;
2011-03-21 21:10:53 +00:00
}
2011-03-20 12:35:19 +00:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
2013-04-20 16:32:55 +01:00
public function isSubmitted ()
{
return $this -> submitted ;
}
/**
* Alias of { @ link isSubmitted ()} .
*
* @ deprecated Deprecated since version 2.3 , to be removed in 3.0 . Use
* { @ link isSubmitted ()} instead .
*/
2011-03-20 12:35:19 +00:00
public function isBound ()
{
2013-04-20 16:32:55 +01:00
return $this -> submitted ;
2011-03-20 12:35:19 +00:00
}
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
2011-03-22 01:03:22 +00:00
public function isSynchronized ()
2011-03-20 12:35:19 +00:00
{
2011-03-22 01:03:22 +00:00
return $this -> synchronized ;
2011-03-20 12:35:19 +00:00
}
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
public function isEmpty ()
{
foreach ( $this -> children as $child ) {
if ( ! $child -> isEmpty ()) {
return false ;
}
}
2012-12-13 14:18:14 +00:00
return FormUtil :: isEmpty ( $this -> modelData ) ||
// arrays, countables
0 === count ( $this -> modelData ) ||
// traversables that are not countable
( $this -> modelData instanceof \Traversable && 0 === iterator_count ( $this -> modelData ));
2011-03-20 12:35:19 +00:00
}
2011-01-29 21:39:36 +00:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-01-29 21:39:36 +00:00
*/
public function isValid ()
{
2013-04-20 16:32:55 +01:00
if ( ! $this -> submitted ) {
2012-12-30 15:38:36 +00:00
return false ;
2011-06-28 20:18:02 +01:00
}
2013-08-01 17:06:16 +01:00
if ( $this -> isDisabled ()) {
return true ;
}
2014-03-28 09:30:00 +00:00
if ( count ( $this -> getErrors ( true )) > 0 ) {
return false ;
2011-01-29 21:39:36 +00:00
}
return true ;
}
2013-11-09 15:25:41 +00:00
/**
* Returns the button that was used to submit the form .
*
* @ return Button | null The clicked button or NULL if the form was not
* submitted
*/
public function getClickedButton ()
{
if ( $this -> clickedButton ) {
return $this -> clickedButton ;
}
if ( $this -> parent && method_exists ( $this -> parent , 'getClickedButton' )) {
return $this -> parent -> getClickedButton ();
}
}
2011-01-29 21:39:36 +00:00
2011-03-20 12:35:19 +00:00
/**
2012-08-26 07:28:19 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
2014-01-10 12:53:52 +00:00
public function getErrors ( $deep = false , $flatten = true )
2011-03-20 12:35:19 +00:00
{
2014-03-11 15:57:35 +00:00
$errors = $this -> errors ;
// Copy the errors of nested forms to the $errors array
if ( $deep ) {
foreach ( $this as $child ) {
/** @var FormInterface $child */
if ( $child -> isSubmitted () && $child -> isValid ()) {
continue ;
}
$iterator = $child -> getErrors ( true , $flatten );
if ( 0 === count ( $iterator )) {
continue ;
}
if ( $flatten ) {
foreach ( $iterator as $error ) {
$errors [] = $error ;
}
} else {
$errors [] = $iterator ;
}
}
}
return new FormErrorIterator ( $this , $errors );
2011-03-20 12:35:19 +00:00
}
2011-09-25 13:31:31 +01:00
/**
* Returns a string representation of all form errors ( including children errors ) .
*
* This method should only be used to help debug a form .
*
2014-04-12 18:54:57 +01:00
* @ param int $level The indentation level ( used internally )
2011-09-25 13:31:31 +01:00
*
* @ return string A string representation of all errors
2013-12-31 16:24:28 +00:00
*
* @ deprecated Deprecated since version 2.5 , to be removed in 3.0 . Use
* { @ link getErrors ()} instead and cast the result to a string .
2011-09-25 13:31:31 +01:00
*/
public function getErrorsAsString ( $level = 0 )
{
2014-01-10 12:53:52 +00:00
return self :: indent (( string ) $this -> getErrors ( true , false ), $level );
2011-09-25 13:31:31 +01:00
}
2012-05-24 13:24:28 +01:00
/**
* { @ inheritdoc }
*/
2013-08-24 16:43:39 +01:00
public function all ()
2012-05-24 13:24:28 +01:00
{
2013-08-24 16:43:39 +01:00
return iterator_to_array ( $this -> children );
2012-05-24 13:24:28 +01:00
}
2011-05-10 14:32:14 +01:00
/**
2012-05-16 18:25:27 +01:00
* { @ inheritdoc }
2011-05-10 14:32:14 +01:00
*/
2012-12-14 15:05:05 +00:00
public function add ( $child , $type = null , array $options = array ())
2011-03-20 12:35:19 +00:00
{
2013-04-20 16:32:55 +01:00
if ( $this -> submitted ) {
throw new AlreadySubmittedException ( 'You cannot add children to a submitted form' );
2012-02-10 12:47:43 +00:00
}
2012-07-03 18:09:41 +01:00
if ( ! $this -> config -> getCompound ()) {
2013-04-15 21:11:02 +01:00
throw new LogicException ( 'You cannot add children to a simple form. Maybe you should set the option "compound" to true?' );
2012-07-03 18:09:41 +01:00
}
2012-07-16 11:47:05 +01:00
// Obtain the view data
$viewData = null ;
// If setData() is currently being called, there is no need to call
// mapDataToForms() here, as mapDataToForms() is called at the end
// of setData() anyway. Not doing this check leads to an endless
// recursion when initializing the form lazily and an event listener
// (such as ResizeFormListener) adds fields depending on the data:
//
// * setData() is called, the form is not initialized yet
// * add() is called by the listener (setData() is not complete, so
// the form is still not initialized)
// * getViewData() is called
// * setData() is called since the form is not initialized yet
// * ... endless recursion ...
2013-04-29 16:31:30 +01:00
//
// Also skip data mapping if setData() has not been called yet.
// setData() will be called upon form initialization and data mapping
// will take place by then.
if ( ! $this -> lockSetData && $this -> defaultDataSet && ! $this -> config -> getInheritData ()) {
2012-07-16 11:47:05 +01:00
$viewData = $this -> getViewData ();
}
2012-12-14 15:05:05 +00:00
if ( ! $child instanceof FormInterface ) {
2012-12-14 18:27:28 +00:00
if ( ! is_string ( $child ) && ! is_int ( $child )) {
throw new UnexpectedTypeException ( $child , 'string, integer or Symfony\Component\Form\FormInterface' );
2012-12-14 15:05:05 +00:00
}
if ( null !== $type && ! is_string ( $type ) && ! $type instanceof FormTypeInterface ) {
throw new UnexpectedTypeException ( $type , 'string or Symfony\Component\Form\FormTypeInterface' );
}
2013-04-29 16:31:30 +01:00
// Never initialize child forms automatically
$options [ 'auto_initialize' ] = false ;
2012-12-14 15:05:05 +00:00
if ( null === $type ) {
$child = $this -> config -> getFormFactory () -> createForProperty ( $this -> config -> getDataClass (), $child , null , $options );
} else {
$child = $this -> config -> getFormFactory () -> createNamed ( $child , $type , null , $options );
}
2013-04-29 16:31:30 +01:00
} elseif ( $child -> getConfig () -> getAutoInitialize ()) {
throw new RuntimeException ( sprintf (
'Automatic initialization is only supported on root forms. You ' .
'should set the "auto_initialize" option to false on the field "%s".' ,
$child -> getName ()
));
2012-12-14 15:05:05 +00:00
}
2011-03-20 12:35:19 +00:00
$this -> children [ $child -> getName ()] = $child ;
$child -> setParent ( $this );
2013-04-29 16:31:30 +01:00
if ( ! $this -> lockSetData && $this -> defaultDataSet && ! $this -> config -> getInheritData ()) {
2013-08-24 16:43:39 +01:00
$iterator = new InheritDataAwareIterator ( new \ArrayIterator ( array ( $child )));
$iterator = new \RecursiveIteratorIterator ( $iterator );
$this -> config -> getDataMapper () -> mapDataToForms ( $viewData , $iterator );
2012-07-16 11:47:05 +01:00
}
2011-05-10 13:40:20 +01:00
return $this ;
2011-03-20 12:35:19 +00:00
}
2011-05-10 14:32:14 +01:00
/**
2012-05-16 18:25:27 +01:00
* { @ inheritdoc }
2011-05-10 14:32:14 +01:00
*/
2011-03-20 12:35:19 +00:00
public function remove ( $name )
{
2013-04-20 16:32:55 +01:00
if ( $this -> submitted ) {
throw new AlreadySubmittedException ( 'You cannot remove children from a submitted form' );
2012-02-10 12:47:43 +00:00
}
2011-03-20 12:35:19 +00:00
if ( isset ( $this -> children [ $name ])) {
2013-12-14 14:36:37 +00:00
if ( ! $this -> children [ $name ] -> isSubmitted ()) {
$this -> children [ $name ] -> setParent ( null );
}
2011-03-20 12:35:19 +00:00
unset ( $this -> children [ $name ]);
}
2011-05-10 13:40:20 +01:00
return $this ;
2011-03-20 12:35:19 +00:00
}
/**
2012-05-16 18:25:27 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
public function has ( $name )
{
return isset ( $this -> children [ $name ]);
}
/**
2012-05-16 18:25:27 +01:00
* { @ inheritdoc }
2011-03-20 12:35:19 +00:00
*/
public function get ( $name )
{
if ( isset ( $this -> children [ $name ])) {
return $this -> children [ $name ];
}
2013-04-15 21:11:02 +01:00
throw new OutOfBoundsException ( sprintf ( 'Child "%s" does not exist.' , $name ));
2011-03-20 12:35:19 +00:00
}
/**
2012-08-26 07:28:19 +01:00
* Returns whether a child with the given name exists ( implements the \ArrayAccess interface ) .
2011-03-20 12:35:19 +00:00
*
* @ param string $name The name of the child
2011-01-29 21:39:36 +00:00
*
2014-04-16 11:30:19 +01:00
* @ return bool
2011-01-29 21:39:36 +00:00
*/
2011-03-17 10:03:10 +00:00
public function offsetExists ( $name )
2011-01-29 21:39:36 +00:00
{
2011-03-17 10:03:10 +00:00
return $this -> has ( $name );
2011-01-29 21:39:36 +00:00
}
/**
2012-08-26 07:28:19 +01:00
* Returns the child with the given name ( implements the \ArrayAccess interface ) .
*
* @ param string $name The name of the child
2011-01-29 21:39:36 +00:00
*
2012-08-26 07:28:19 +01:00
* @ return FormInterface The child form
2011-01-29 21:39:36 +00:00
*
2012-08-26 08:47:56 +01:00
* @ throws \OutOfBoundsException If the named child does not exist .
2011-01-29 21:39:36 +00:00
*/
2011-03-17 10:03:10 +00:00
public function offsetGet ( $name )
2011-01-29 21:39:36 +00:00
{
2011-03-17 10:03:10 +00:00
return $this -> get ( $name );
2011-01-29 21:39:36 +00:00
}
/**
2011-03-31 14:23:33 +01:00
* Adds a child to the form ( implements the \ArrayAccess interface ) .
2011-01-29 21:39:36 +00:00
*
2012-05-15 21:19:31 +01:00
* @ param string $name Ignored . The name of the child is used .
2012-08-26 07:28:19 +01:00
* @ param FormInterface $child The child to be added .
*
2013-04-20 16:32:55 +01:00
* @ throws AlreadySubmittedException If the form has already been submitted .
* @ throws LogicException When trying to add a child to a non - compound form .
2012-08-26 07:28:19 +01:00
*
* @ see self :: add ()
2011-01-29 21:39:36 +00:00
*/
2011-03-20 12:35:19 +00:00
public function offsetSet ( $name , $child )
2011-01-29 21:39:36 +00:00
{
2011-03-31 14:23:33 +01:00
$this -> add ( $child );
2011-01-29 21:39:36 +00:00
}
/**
2011-03-31 14:23:33 +01:00
* Removes the child with the given name from the form ( implements the \ArrayAccess interface ) .
2011-01-29 21:39:36 +00:00
*
2012-08-26 07:28:19 +01:00
* @ param string $name The name of the child to remove
*
2013-04-20 16:32:55 +01:00
* @ throws AlreadySubmittedException If the form has already been submitted .
2011-01-29 21:39:36 +00:00
*/
2011-03-17 10:03:10 +00:00
public function offsetUnset ( $name )
2011-01-29 21:39:36 +00:00
{
2011-03-31 14:23:33 +01:00
$this -> remove ( $name );
2011-01-29 21:39:36 +00:00
}
/**
* Returns the iterator for this group .
*
2013-09-03 23:28:35 +01:00
* @ return \Traversable
2011-01-29 21:39:36 +00:00
*/
public function getIterator ()
{
2013-08-24 16:43:39 +01:00
return $this -> children ;
2011-01-29 21:39:36 +00:00
}
/**
2011-03-20 12:35:19 +00:00
* Returns the number of form children ( implements the \Countable interface ) .
2011-01-29 21:39:36 +00:00
*
2014-04-16 11:30:19 +01:00
* @ return int The number of embedded form children
2011-01-29 21:39:36 +00:00
*/
public function count ()
{
2011-03-20 12:35:19 +00:00
return count ( $this -> children );
}
2011-05-06 11:48:43 +01:00
/**
2012-05-24 14:20:49 +01:00
* { @ inheritdoc }
2011-05-06 11:48:43 +01:00
*/
2012-07-16 13:57:09 +01:00
public function createView ( FormView $parent = null )
2011-05-06 11:48:43 +01:00
{
if ( null === $parent && $this -> parent ) {
$parent = $this -> parent -> createView ();
}
2013-09-17 10:39:17 +01:00
$type = $this -> config -> getType ();
$options = $this -> config -> getOptions ();
// The methods createView(), buildView() and finishView() are called
// explicitly here in order to be able to override either of them
// in a custom resolved form type.
$view = $type -> createView ( $this , $parent );
$type -> buildView ( $view , $this , $options );
foreach ( $this -> children as $name => $child ) {
$view -> children [ $name ] = $child -> createView ( $view );
}
$type -> finishView ( $view , $this , $options );
return $view ;
2011-05-06 11:48:43 +01:00
}
2011-03-20 12:35:19 +00:00
/**
2011-05-10 14:32:14 +01:00
* Normalizes the value if a normalization transformer is set .
2011-03-20 12:35:19 +00:00
*
2012-05-15 21:19:31 +01:00
* @ param mixed $value The value to transform
2011-05-10 14:32:14 +01:00
*
2012-08-26 07:28:19 +01:00
* @ return mixed
2011-03-20 12:35:19 +00:00
*/
2012-05-23 19:21:34 +01:00
private function modelToNorm ( $value )
2011-03-20 12:35:19 +00:00
{
2012-05-23 19:21:34 +01:00
foreach ( $this -> config -> getModelTransformers () as $transformer ) {
2011-04-02 15:39:19 +01:00
$value = $transformer -> transform ( $value );
2011-03-20 12:35:19 +00:00
}
2011-04-02 15:39:19 +01:00
return $value ;
2011-03-20 12:35:19 +00:00
}
/**
* Reverse transforms a value if a normalization transformer is set .
*
2012-05-15 21:19:31 +01:00
* @ param string $value The value to reverse transform
2011-05-10 14:32:14 +01:00
*
2011-03-20 12:35:19 +00:00
* @ return mixed
*/
2012-05-23 19:21:34 +01:00
private function normToModel ( $value )
2011-03-20 12:35:19 +00:00
{
2012-05-23 19:21:34 +01:00
$transformers = $this -> config -> getModelTransformers ();
2012-05-16 18:25:27 +01:00
for ( $i = count ( $transformers ) - 1 ; $i >= 0 ; -- $i ) {
$value = $transformers [ $i ] -> reverseTransform ( $value );
2011-03-20 12:35:19 +00:00
}
2011-04-02 15:39:19 +01:00
return $value ;
2011-03-20 12:35:19 +00:00
}
/**
* Transforms the value if a value transformer is set .
*
2012-05-15 21:19:31 +01:00
* @ param mixed $value The value to transform
2011-05-10 14:32:14 +01:00
*
2012-08-26 07:28:19 +01:00
* @ return mixed
2011-03-20 12:35:19 +00:00
*/
2012-05-23 19:21:34 +01:00
private function normToView ( $value )
2011-03-20 12:35:19 +00:00
{
2012-07-06 15:46:24 +01:00
// Scalar values should be converted to strings to
// facilitate differentiation between empty ("") and zero (0).
// Only do this for simple forms, as the resulting value in
// compound forms is passed to the data mapper and thus should
// not be converted to a string before.
if ( ! $this -> config -> getViewTransformers () && ! $this -> config -> getCompound ()) {
2011-05-10 14:32:14 +01:00
return null === $value || is_scalar ( $value ) ? ( string ) $value : $value ;
2011-03-20 12:35:19 +00:00
}
2012-05-23 19:21:34 +01:00
foreach ( $this -> config -> getViewTransformers () as $transformer ) {
2011-04-02 15:39:19 +01:00
$value = $transformer -> transform ( $value );
}
return $value ;
2011-03-20 12:35:19 +00:00
}
/**
* Reverse transforms a value if a value transformer is set .
*
2012-05-15 21:19:31 +01:00
* @ param string $value The value to reverse transform
2011-05-10 14:32:14 +01:00
*
2011-03-20 12:35:19 +00:00
* @ return mixed
*/
2012-05-23 19:21:34 +01:00
private function viewToNorm ( $value )
2011-03-20 12:35:19 +00:00
{
2012-05-23 19:21:34 +01:00
$transformers = $this -> config -> getViewTransformers ();
2012-05-16 18:25:27 +01:00
if ( ! $transformers ) {
2011-03-20 12:35:19 +00:00
return '' === $value ? null : $value ;
}
2012-05-16 18:25:27 +01:00
for ( $i = count ( $transformers ) - 1 ; $i >= 0 ; -- $i ) {
$value = $transformers [ $i ] -> reverseTransform ( $value );
2011-04-02 15:39:19 +01:00
}
return $value ;
2011-01-29 21:39:36 +00:00
}
2013-12-31 16:24:28 +00:00
/**
* Utility function for indenting multi - line strings .
*
* @ param string $string The string
2014-04-16 09:09:01 +01:00
* @ param int $level The number of spaces to use for indentation
2013-12-31 16:24:28 +00:00
*
* @ return string The indented string
*/
private static function indent ( $string , $level )
{
$indentation = str_repeat ( ' ' , $level );
return rtrim ( $indentation . str_replace ( " \n " , " \n " . $indentation , $string ), ' ' );
}
2010-06-24 09:40:05 +01:00
}