2013-12-31 16:24:28 +00:00
< ? php
/*
* This file is part of the Symfony package .
*
* ( c ) Fabien Potencier < fabien @ symfony . com >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Symfony\Component\Form ;
2018-07-26 10:03:18 +01:00
use Symfony\Component\Form\Exception\BadMethodCallException ;
2014-03-11 15:57:35 +00:00
use Symfony\Component\Form\Exception\InvalidArgumentException ;
2013-12-31 16:24:28 +00:00
use Symfony\Component\Form\Exception\OutOfBoundsException ;
2016-08-01 09:29:35 +01:00
use Symfony\Component\Validator\ConstraintViolation ;
2013-12-31 16:24:28 +00:00
/**
* Iterates over the errors of a form .
*
2018-12-14 10:34:58 +00:00
* This class supports recursive iteration . In order to iterate recursively ,
* pass a structure of { @ link FormError } and { @ link FormErrorIterator } objects
* to the $errors constructor argument .
2013-12-31 16:24:28 +00:00
*
* You can also wrap the iterator into a { @ link \RecursiveIteratorIterator } to
* flatten the recursive structure into a flat list of errors .
*
* @ author Bernhard Schussek < bschussek @ gmail . com >
*/
class FormErrorIterator implements \RecursiveIterator , \SeekableIterator , \ArrayAccess , \Countable
{
/**
* The prefix used for indenting nested error messages .
*/
const INDENTATION = ' ' ;
private $form ;
2014-03-11 15:57:35 +00:00
private $errors ;
2013-12-31 16:24:28 +00:00
/**
2019-03-12 20:16:42 +00:00
* @ param FormError [] | self [] $errors An array of form errors and instances
* of FormErrorIterator
2014-03-11 15:57:35 +00:00
*
* @ throws InvalidArgumentException If the errors are invalid
2013-12-31 16:24:28 +00:00
*/
2014-03-11 15:57:35 +00:00
public function __construct ( FormInterface $form , array $errors )
2013-12-31 16:24:28 +00:00
{
2014-03-11 15:57:35 +00:00
foreach ( $errors as $error ) {
if ( ! ( $error instanceof FormError || $error instanceof self )) {
2018-09-08 13:44:02 +01:00
throw new InvalidArgumentException ( sprintf ( 'The errors must be instances of "Symfony\Component\Form\FormError" or "%s". Got: "%s".' , __CLASS__ , \is_object ( $error ) ? \get_class ( $error ) : \gettype ( $error )));
2014-03-11 15:57:35 +00:00
}
}
2013-12-31 16:24:28 +00:00
2014-03-11 15:57:35 +00:00
$this -> form = $form ;
$this -> errors = $errors ;
2013-12-31 16:24:28 +00:00
}
/**
* Returns all iterated error messages as string .
*
* @ return string The iterated error messages
*/
public function __toString ()
{
$string = '' ;
2014-03-11 15:57:35 +00:00
foreach ( $this -> errors as $error ) {
if ( $error instanceof FormError ) {
$string .= 'ERROR: ' . $error -> getMessage () . " \n " ;
2013-12-31 16:24:28 +00:00
} else {
2019-07-31 20:19:25 +01:00
/* @var self $error */
2014-03-11 15:57:35 +00:00
$string .= $error -> form -> getName () . " : \n " ;
$string .= self :: indent (( string ) $error );
2013-12-31 16:24:28 +00:00
}
}
return $string ;
}
/**
* Returns the iterated form .
*
2016-06-28 06:50:50 +01:00
* @ return FormInterface The form whose errors are iterated by this object
2013-12-31 16:24:28 +00:00
*/
public function getForm ()
{
return $this -> form ;
}
/**
* Returns the current element of the iterator .
*
2019-03-12 20:16:42 +00:00
* @ return FormError | self An error or an iterator containing nested errors
2013-12-31 16:24:28 +00:00
*/
public function current ()
{
2014-03-11 15:57:35 +00:00
return current ( $this -> errors );
2013-12-31 16:24:28 +00:00
}
/**
* Advances the iterator to the next position .
*/
public function next ()
{
2014-03-11 15:57:35 +00:00
next ( $this -> errors );
2013-12-31 16:24:28 +00:00
}
/**
* Returns the current position of the iterator .
*
2016-06-28 06:50:50 +01:00
* @ return int The 0 - indexed position
2013-12-31 16:24:28 +00:00
*/
public function key ()
{
2014-03-11 15:57:35 +00:00
return key ( $this -> errors );
2013-12-31 16:24:28 +00:00
}
/**
* Returns whether the iterator ' s position is valid .
*
2016-06-28 06:50:50 +01:00
* @ return bool Whether the iterator is valid
2013-12-31 16:24:28 +00:00
*/
public function valid ()
{
2014-03-11 15:57:35 +00:00
return null !== key ( $this -> errors );
2013-12-31 16:24:28 +00:00
}
/**
* Sets the iterator ' s position to the beginning .
*
* This method detects if errors have been added to the form since the
* construction of the iterator .
*/
public function rewind ()
{
2014-03-11 15:57:35 +00:00
reset ( $this -> errors );
2013-12-31 16:24:28 +00:00
}
/**
* Returns whether a position exists in the iterator .
*
2014-12-04 20:26:11 +00:00
* @ param int $position The position
2013-12-31 16:24:28 +00:00
*
2014-12-04 20:26:11 +00:00
* @ return bool Whether that position exists
2013-12-31 16:24:28 +00:00
*/
public function offsetExists ( $position )
{
2014-03-11 15:57:35 +00:00
return isset ( $this -> errors [ $position ]);
2013-12-31 16:24:28 +00:00
}
/**
* Returns the element at a position in the iterator .
*
2014-12-04 20:26:11 +00:00
* @ param int $position The position
2013-12-31 16:24:28 +00:00
*
* @ return FormError | FormErrorIterator The element at the given position
*
* @ throws OutOfBoundsException If the given position does not exist
*/
public function offsetGet ( $position )
{
2014-03-11 15:57:35 +00:00
if ( ! isset ( $this -> errors [ $position ])) {
2013-12-31 16:24:28 +00:00
throw new OutOfBoundsException ( 'The offset ' . $position . ' does not exist.' );
}
2014-03-11 15:57:35 +00:00
return $this -> errors [ $position ];
2013-12-31 16:24:28 +00:00
}
/**
* Unsupported method .
*
* @ throws BadMethodCallException
*/
public function offsetSet ( $position , $value )
{
throw new BadMethodCallException ( 'The iterator doesn\'t support modification of elements.' );
}
/**
* Unsupported method .
*
* @ throws BadMethodCallException
*/
public function offsetUnset ( $position )
{
throw new BadMethodCallException ( 'The iterator doesn\'t support modification of elements.' );
}
/**
* Returns whether the current element of the iterator can be recursed
* into .
*
2014-12-04 20:26:11 +00:00
* @ return bool Whether the current element is an instance of this class
2013-12-31 16:24:28 +00:00
*/
public function hasChildren ()
{
2014-03-11 15:57:35 +00:00
return current ( $this -> errors ) instanceof self ;
2013-12-31 16:24:28 +00:00
}
/**
* Alias of { @ link current ()} .
*/
public function getChildren ()
{
2014-03-11 15:57:35 +00:00
return current ( $this -> errors );
2013-12-31 16:24:28 +00:00
}
/**
* Returns the number of elements in the iterator .
*
* Note that this is not the total number of errors , if the constructor
* parameter $deep was set to true ! In that case , you should wrap the
* iterator into a { @ link \RecursiveIteratorIterator } with the standard mode
* { @ link \RecursiveIteratorIterator :: LEAVES_ONLY } and count the result .
*
* $iterator = new \RecursiveIteratorIterator ( $form -> getErrors ( true ));
* $count = count ( iterator_to_array ( $iterator ));
*
* Alternatively , set the constructor argument $flatten to true as well .
*
* $count = count ( $form -> getErrors ( true , true ));
*
2014-12-04 20:26:11 +00:00
* @ return int The number of iterated elements
2013-12-31 16:24:28 +00:00
*/
public function count ()
{
2018-07-05 12:24:53 +01:00
return \count ( $this -> errors );
2013-12-31 16:24:28 +00:00
}
/**
* Sets the position of the iterator .
*
2014-12-04 20:26:11 +00:00
* @ param int $position The new position
2013-12-31 16:24:28 +00:00
*
* @ throws OutOfBoundsException If the position is invalid
*/
public function seek ( $position )
{
2014-03-11 15:57:35 +00:00
if ( ! isset ( $this -> errors [ $position ])) {
2013-12-31 16:24:28 +00:00
throw new OutOfBoundsException ( 'The offset ' . $position . ' does not exist.' );
}
2014-03-11 15:57:35 +00:00
reset ( $this -> errors );
2013-12-31 16:24:28 +00:00
2014-03-11 15:57:35 +00:00
while ( $position !== key ( $this -> errors )) {
next ( $this -> errors );
2013-12-31 16:24:28 +00:00
}
}
2016-08-01 09:29:35 +01:00
/**
* Creates iterator for errors with specific codes .
*
* @ param string | string [] $codes The codes to find
*
2017-09-11 22:23:01 +01:00
* @ return static new instance which contains only specific errors
2016-08-01 09:29:35 +01:00
*/
public function findByCodes ( $codes )
{
$codes = ( array ) $codes ;
2019-01-16 09:39:14 +00:00
$errors = [];
2016-08-01 09:29:35 +01:00
foreach ( $this as $error ) {
$cause = $error -> getCause ();
2018-07-26 09:45:46 +01:00
if ( $cause instanceof ConstraintViolation && \in_array ( $cause -> getCode (), $codes , true )) {
2016-08-01 09:29:35 +01:00
$errors [] = $error ;
}
}
return new static ( $this -> form , $errors );
}
2013-12-31 16:24:28 +00:00
/**
* Utility function for indenting multi - line strings .
*/
2019-08-06 16:03:31 +01:00
private static function indent ( string $string ) : string
2013-12-31 16:24:28 +00:00
{
return rtrim ( self :: INDENTATION . str_replace ( " \n " , " \n " . self :: INDENTATION , $string ), ' ' );
}
}