merged branch bschussek/dereference-all-2.3 (PR #8852)

This PR was merged into the 2.3 branch.

Discussion
----------

[2.3][Form] Dereferenced Form::&all() since it is not supported for PHP <= 5.3.3

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

see 00bc2708bc and #8851

Commits
-------

fd09484 [Form] Fixed Form::all() signature for PHP 5.3.3
This commit is contained in:
Fabien Potencier 2013-08-26 07:49:08 +02:00
commit c5514578d5
8 changed files with 861 additions and 226 deletions

View File

@ -167,7 +167,7 @@ class ViolationMapper implements ViolationMapperInterface
// Skip forms inheriting their parent data when iterating the children
$childIterator = new \RecursiveIteratorIterator(
new InheritDataAwareIterator($form->all())
new InheritDataAwareIterator($form)
);
// Make the path longer until we find a matching child

View File

@ -19,6 +19,7 @@ use Symfony\Component\Form\Exception\LogicException;
use Symfony\Component\Form\Exception\OutOfBoundsException;
use Symfony\Component\Form\Util\FormUtil;
use Symfony\Component\Form\Util\InheritDataAwareIterator;
use Symfony\Component\Form\Util\OrderedHashMap;
use Symfony\Component\PropertyAccess\PropertyPath;
/**
@ -73,9 +74,9 @@ class Form implements \IteratorAggregate, FormInterface
/**
* The children of this form
* @var FormInterface[] An array of FormInterface instances
* @var FormInterface[] A map of FormInterface instances
*/
private $children = array();
private $children;
/**
* The errors of this form
@ -164,6 +165,7 @@ class Form implements \IteratorAggregate, FormInterface
}
$this->config = $config;
$this->children = new OrderedHashMap();
}
public function __clone()
@ -370,9 +372,9 @@ class Form implements \IteratorAggregate, FormInterface
// even if the form is compound.
if (count($this->children) > 0) {
// Update child forms from the data
$childrenIterator = new InheritDataAwareIterator($this->children);
$childrenIterator = new \RecursiveIteratorIterator($childrenIterator);
$this->config->getDataMapper()->mapDataToForms($viewData, $childrenIterator);
$iterator = new InheritDataAwareIterator($this->children);
$iterator = new \RecursiveIteratorIterator($iterator);
$this->config->getDataMapper()->mapDataToForms($viewData, $iterator);
}
if ($dispatcher->hasListeners(FormEvents::POST_SET_DATA)) {
@ -536,10 +538,7 @@ class Form implements \IteratorAggregate, FormInterface
$submittedData = array();
}
for (reset($this->children); false !== current($this->children); next($this->children)) {
$child = current($this->children);
$name = key($this->children);
foreach ($this->children as $name => $child) {
if (array_key_exists($name, $submittedData) || $clearMissing) {
$child->submit(isset($submittedData[$name]) ? $submittedData[$name] : null, $clearMissing);
unset($submittedData[$name]);
@ -587,9 +586,9 @@ class Form implements \IteratorAggregate, FormInterface
// 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);
$iterator = new InheritDataAwareIterator($this->children);
$iterator = new \RecursiveIteratorIterator($iterator);
$this->config->getDataMapper()->mapFormsToData($iterator, $viewData);
}
$modelData = null;
@ -765,9 +764,9 @@ class Form implements \IteratorAggregate, FormInterface
/**
* {@inheritdoc}
*/
public function &all()
public function all()
{
return $this->children;
return iterator_to_array($this->children);
}
/**
@ -836,10 +835,9 @@ class Form implements \IteratorAggregate, FormInterface
$child->setParent($this);
if (!$this->lockSetData && $this->defaultDataSet && !$this->config->getInheritData()) {
$children = array($child);
$childrenIterator = new InheritDataAwareIterator($children);
$childrenIterator = new \RecursiveIteratorIterator($childrenIterator);
$this->config->getDataMapper()->mapDataToForms($viewData, $childrenIterator);
$iterator = new InheritDataAwareIterator(new \ArrayIterator(array($child)));
$iterator = new \RecursiveIteratorIterator($iterator);
$this->config->getDataMapper()->mapDataToForms($viewData, $iterator);
}
return $this;
@ -940,11 +938,11 @@ class Form implements \IteratorAggregate, FormInterface
/**
* Returns the iterator for this group.
*
* @return \ArrayIterator
* @return \Iterator
*/
public function getIterator()
{
return new \ArrayIterator($this->children);
return $this->children;
}
/**

View File

@ -1,122 +0,0 @@
<?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\Tests\Util;
use Symfony\Component\Form\Util\InheritDataAwareIterator;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class InheritDataAwareIteratorTest extends \PHPUnit_Framework_TestCase
{
public function testSupportDynamicModification()
{
$form = $this->getMockForm('form');
$formToBeAdded = $this->getMockForm('added');
$formToBeRemoved = $this->getMockForm('removed');
$forms = array('form' => $form, 'removed' => $formToBeRemoved);
$iterator = new InheritDataAwareIterator($forms);
$iterator->rewind();
$this->assertTrue($iterator->valid());
$this->assertSame('form', $iterator->key());
$this->assertSame($form, $iterator->current());
// dynamic modification
unset($forms['removed']);
$forms['added'] = $formToBeAdded;
// continue iteration
$iterator->next();
$this->assertTrue($iterator->valid());
$this->assertSame('added', $iterator->key());
$this->assertSame($formToBeAdded, $iterator->current());
// end of array
$iterator->next();
$this->assertFalse($iterator->valid());
}
public function testSupportDynamicModificationInRecursiveCall()
{
$inheritingForm = $this->getMockForm('inheriting');
$form = $this->getMockForm('form');
$formToBeAdded = $this->getMockForm('added');
$formToBeRemoved = $this->getMockForm('removed');
$inheritingForm->getConfig()->expects($this->any())
->method('getInheritData')
->will($this->returnValue(true));
$inheritingForm->add($form);
$inheritingForm->add($formToBeRemoved);
$forms = array('inheriting' => $inheritingForm);
$iterator = new InheritDataAwareIterator($forms);
$iterator->rewind();
$this->assertTrue($iterator->valid());
$this->assertSame('inheriting', $iterator->key());
$this->assertSame($inheritingForm, $iterator->current());
$this->assertTrue($iterator->hasChildren());
// enter nested iterator
$nestedIterator = $iterator->getChildren();
$this->assertSame('form', $nestedIterator->key());
$this->assertSame($form, $nestedIterator->current());
$this->assertFalse($nestedIterator->hasChildren());
// dynamic modification
$inheritingForm->remove('removed');
$inheritingForm->add($formToBeAdded);
// continue iteration - nested iterator discovers change in the form
$nestedIterator->next();
$this->assertTrue($nestedIterator->valid());
$this->assertSame('added', $nestedIterator->key());
$this->assertSame($formToBeAdded, $nestedIterator->current());
// end of array
$nestedIterator->next();
$this->assertFalse($nestedIterator->valid());
}
/**
* @param string $name
*
* @return \PHPUnit_Framework_MockObject_MockObject
*/
protected function getMockForm($name = 'name')
{
$config = $this->getMock('Symfony\Component\Form\FormConfigInterface');
$config->expects($this->any())
->method('getName')
->will($this->returnValue($name));
$config->expects($this->any())
->method('getCompound')
->will($this->returnValue(true));
$config->expects($this->any())
->method('getDataMapper')
->will($this->returnValue($this->getMock('Symfony\Component\Form\DataMapperInterface')));
$config->expects($this->any())
->method('getEventDispatcher')
->will($this->returnValue($this->getMock('Symfony\Component\EventDispatcher\EventDispatcher')));
return $this->getMockBuilder('Symfony\Component\Form\Form')
->setConstructorArgs(array($config))
->disableArgumentCloning()
->setMethods(array('getViewData'))
->getMock();
}
}

View File

@ -0,0 +1,487 @@
<?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\Tests\Util;
use Symfony\Component\Form\Util\OrderedHashMap;
/**
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class OrderedHashMapTest extends \PHPUnit_Framework_TestCase
{
public function testGet()
{
$map = new OrderedHashMap();
$map['first'] = 1;
$this->assertSame(1, $map['first']);
}
/**
* @expectedException \OutOfBoundsException
*/
public function testGetNonExistingFails()
{
$map = new OrderedHashMap();
$map['first'];
}
public function testInsertStringKeys()
{
$map = new OrderedHashMap();
$map['first'] = 1;
$map['second'] = 2;
$this->assertSame(array('first' => 1, 'second' => 2), iterator_to_array($map));
}
public function testInsertNullKeys()
{
$map = new OrderedHashMap();
$map[] = 1;
$map['foo'] = 2;
$map[] = 3;
$this->assertSame(array(0 => 1, 'foo' => 2, 1 => 3), iterator_to_array($map));
}
/**
* Updates should not change the position of an element, otherwise we could
* turn foreach loops into endless loops if they change the current
* element:
*
* foreach ($map as $index => $value) {
* $map[$index] = $value + 1;
* }
*
* And we don't want this, right? :)
*/
public function testUpdateDoesNotChangeElementPosition()
{
$map = new OrderedHashMap();
$map['first'] = 1;
$map['second'] = 2;
$map['first'] = 1;
$this->assertSame(array('first' => 1, 'second' => 2), iterator_to_array($map));
}
public function testIsset()
{
$map = new OrderedHashMap();
$map['first'] = 1;
$this->assertTrue(isset($map['first']));
}
public function testIssetReturnsFalseForNonExisting()
{
$map = new OrderedHashMap();
$this->assertFalse(isset($map['first']));
}
public function testIssetReturnsFalseForNull()
{
$map = new OrderedHashMap();
$map['first'] = null;
$this->assertFalse(isset($map['first']));
}
public function testUnset()
{
$map = new OrderedHashMap();
$map['first'] = 1;
$map['second'] = 2;
unset($map['first']);
$this->assertSame(array('second' => 2), iterator_to_array($map));
}
public function testUnsetNonExistingSucceeds()
{
$map = new OrderedHashMap();
unset($map['first']);
}
public function testEmptyIteration()
{
$map = new OrderedHashMap();
$it = $map->getIterator();
$it->rewind();
$this->assertFalse($it->valid());
$this->assertNull($it->key());
$this->assertNull($it->current());
}
public function testIterationSupportsInsertion()
{
$map = new OrderedHashMap(array('first' => 1));
$it = $map->getIterator();
$it->rewind();
$this->assertTrue($it->valid());
$this->assertSame('first', $it->key());
$this->assertSame(1, $it->current());
// dynamic modification
$map['added'] = 2;
// iterator is unchanged
$this->assertTrue($it->valid());
$this->assertSame('first', $it->key());
$this->assertSame(1, $it->current());
// continue iteration
$it->next();
$this->assertTrue($it->valid());
$this->assertSame('added', $it->key());
$this->assertSame(2, $it->current());
// end of map
$it->next();
$this->assertFalse($it->valid());
$this->assertNull($it->key());
$this->assertNull($it->current());
}
public function testIterationSupportsDeletionAndInsertion()
{
$map = new OrderedHashMap(array('first' => 1, 'removed' => 2));
$it = $map->getIterator();
$it->rewind();
$this->assertTrue($it->valid());
$this->assertSame('first', $it->key());
$this->assertSame(1, $it->current());
// dynamic modification
unset($map['removed']);
$map['added'] = 3;
// iterator is unchanged
$this->assertTrue($it->valid());
$this->assertSame('first', $it->key());
$this->assertSame(1, $it->current());
// continue iteration
$it->next();
$this->assertTrue($it->valid());
$this->assertSame('added', $it->key());
$this->assertSame(3, $it->current());
// end of map
$it->next();
$this->assertFalse($it->valid());
$this->assertNull($it->key());
$this->assertNull($it->current());
}
public function testIterationSupportsDeletionOfCurrentElement()
{
$map = new OrderedHashMap(array('removed' => 1, 'next' => 2));
$it = $map->getIterator();
$it->rewind();
$this->assertTrue($it->valid());
$this->assertSame('removed', $it->key());
$this->assertSame(1, $it->current());
unset($map['removed']);
// iterator is unchanged
$this->assertTrue($it->valid());
$this->assertSame('removed', $it->key());
$this->assertSame(1, $it->current());
// continue iteration
$it->next();
$this->assertTrue($it->valid());
$this->assertSame('next', $it->key());
$this->assertSame(2, $it->current());
// end of map
$it->next();
$this->assertFalse($it->valid());
$this->assertNull($it->key());
$this->assertNull($it->current());
}
public function testIterationIgnoresReplacementOfCurrentElement()
{
$map = new OrderedHashMap(array('replaced' => 1, 'next' => 2));
$it = $map->getIterator();
$it->rewind();
$this->assertTrue($it->valid());
$this->assertSame('replaced', $it->key());
$this->assertSame(1, $it->current());
$map['replaced'] = 3;
// iterator is unchanged
$this->assertTrue($it->valid());
$this->assertSame('replaced', $it->key());
$this->assertSame(1, $it->current());
// continue iteration
$it->next();
$this->assertTrue($it->valid());
$this->assertSame('next', $it->key());
$this->assertSame(2, $it->current());
// end of map
$it->next();
$this->assertFalse($it->valid());
$this->assertNull($it->key());
$this->assertNull($it->current());
}
public function testIterationSupportsDeletionOfCurrentAndLastElement()
{
$map = new OrderedHashMap(array('removed' => 1));
$it = $map->getIterator();
$it->rewind();
$this->assertTrue($it->valid());
$this->assertSame('removed', $it->key());
$this->assertSame(1, $it->current());
unset($map['removed']);
// iterator is unchanged
$this->assertTrue($it->valid());
$this->assertSame('removed', $it->key());
$this->assertSame(1, $it->current());
// end of map
$it->next();
$this->assertFalse($it->valid());
$this->assertNull($it->key());
$this->assertNull($it->current());
}
public function testIterationIgnoresReplacementOfCurrentAndLastElement()
{
$map = new OrderedHashMap(array('replaced' => 1));
$it = $map->getIterator();
$it->rewind();
$this->assertTrue($it->valid());
$this->assertSame('replaced', $it->key());
$this->assertSame(1, $it->current());
$map['replaced'] = 2;
// iterator is unchanged
$this->assertTrue($it->valid());
$this->assertSame('replaced', $it->key());
$this->assertSame(1, $it->current());
// end of map
$it->next();
$this->assertFalse($it->valid());
$this->assertNull($it->key());
$this->assertNull($it->current());
}
public function testIterationSupportsDeletionOfPreviousElement()
{
$map = new OrderedHashMap(array('removed' => 1, 'next' => 2, 'onemore' => 3));
$it = $map->getIterator();
$it->rewind();
$this->assertTrue($it->valid());
$this->assertSame('removed', $it->key());
$this->assertSame(1, $it->current());
// continue iteration
$it->next();
$this->assertTrue($it->valid());
$this->assertSame('next', $it->key());
$this->assertSame(2, $it->current());
unset($map['removed']);
// iterator is unchanged
$this->assertTrue($it->valid());
$this->assertSame('next', $it->key());
$this->assertSame(2, $it->current());
// continue iteration
$it->next();
$this->assertTrue($it->valid());
$this->assertSame('onemore', $it->key());
$this->assertSame(3, $it->current());
// end of map
$it->next();
$this->assertFalse($it->valid());
$this->assertNull($it->key());
$this->assertNull($it->current());
}
public function testIterationIgnoresReplacementOfPreviousElement()
{
$map = new OrderedHashMap(array('replaced' => 1, 'next' => 2, 'onemore' => 3));
$it = $map->getIterator();
$it->rewind();
$this->assertTrue($it->valid());
$this->assertSame('replaced', $it->key());
$this->assertSame(1, $it->current());
// continue iteration
$it->next();
$this->assertTrue($it->valid());
$this->assertSame('next', $it->key());
$this->assertSame(2, $it->current());
$map['replaced'] = 4;
// iterator is unchanged
$this->assertTrue($it->valid());
$this->assertSame('next', $it->key());
$this->assertSame(2, $it->current());
// continue iteration
$it->next();
$this->assertTrue($it->valid());
$this->assertSame('onemore', $it->key());
$this->assertSame(3, $it->current());
// end of map
$it->next();
$this->assertFalse($it->valid());
$this->assertNull($it->key());
$this->assertNull($it->current());
}
public function testIterationSupportsDeletionOfMultiplePreviousElements()
{
$map = new OrderedHashMap(array('removed' => 1, 'alsoremoved' => 2, 'next' => 3, 'onemore' => 4));
$it = $map->getIterator();
$it->rewind();
$this->assertTrue($it->valid());
$this->assertSame('removed', $it->key());
$this->assertSame(1, $it->current());
// continue iteration
$it->next();
$this->assertTrue($it->valid());
$this->assertSame('alsoremoved', $it->key());
$this->assertSame(2, $it->current());
// continue iteration
$it->next();
$this->assertTrue($it->valid());
$this->assertSame('next', $it->key());
$this->assertSame(3, $it->current());
unset($map['removed'], $map['alsoremoved']);
// iterator is unchanged
$this->assertTrue($it->valid());
$this->assertSame('next', $it->key());
$this->assertSame(3, $it->current());
// continue iteration
$it->next();
$this->assertTrue($it->valid());
$this->assertSame('onemore', $it->key());
$this->assertSame(4, $it->current());
// end of map
$it->next();
$this->assertFalse($it->valid());
$this->assertNull($it->key());
$this->assertNull($it->current());
}
public function testParallelIteration()
{
$map = new OrderedHashMap(array('first' => 1, 'second' => 2));
$it1 = $map->getIterator();
$it2 = $map->getIterator();
$it1->rewind();
$this->assertTrue($it1->valid());
$this->assertSame('first', $it1->key());
$this->assertSame(1, $it1->current());
$it2->rewind();
$this->assertTrue($it2->valid());
$this->assertSame('first', $it2->key());
$this->assertSame(1, $it2->current());
// 1: continue iteration
$it1->next();
$this->assertTrue($it1->valid());
$this->assertSame('second', $it1->key());
$this->assertSame(2, $it1->current());
// 2: remains unchanged
$this->assertTrue($it2->valid());
$this->assertSame('first', $it2->key());
$this->assertSame(1, $it2->current());
// 1: advance to end of map
$it1->next();
$this->assertFalse($it1->valid());
$this->assertNull($it1->key());
$this->assertNull($it1->current());
// 2: remains unchanged
$this->assertTrue($it2->valid());
$this->assertSame('first', $it2->key());
$this->assertSame(1, $it2->current());
// 2: continue iteration
$it2->next();
$this->assertTrue($it2->valid());
$this->assertSame('second', $it2->key());
$this->assertSame(2, $it2->current());
// 1: remains unchanged
$this->assertFalse($it1->valid());
$this->assertNull($it1->key());
$this->assertNull($it1->current());
// 2: advance to end of map
$it2->next();
$this->assertFalse($it2->valid());
$this->assertNull($it2->key());
$this->assertNull($it2->current());
// 1: remains unchanged
$this->assertFalse($it1->valid());
$this->assertNull($it1->key());
$this->assertNull($it1->current());
}
public function testCount()
{
$map = new OrderedHashMap();
$map[] = 1;
$map['foo'] = 2;
unset($map[0]);
$map[] = 3;
$this->assertSame(2, count($map));
}
}

View File

@ -0,0 +1,190 @@
<?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\Util;
/**
* A hash map which keeps track of deletions and additions.
*
* Like in associative arrays, elements can be mapped to integer or string keys.
* Unlike associative arrays, the map keeps track of the order in which keys
* were added and removed. This order is reflected during iteration.
*
* The map supports concurrent modification during iteration. That means that
* you can insert and remove elements from within a foreach loop and the
* iterator will reflect those changes accordingly.
*
* While elements that are added during the loop are recognized by the iterator,
* changed elements are not. Otherwise the loop could be infinite if each loop
* changes the current element:
*
* $map = new OrderedHashMap();
* $map[1] = 1;
* $map[2] = 2;
* $map[3] = 3;
*
* foreach ($map as $index => $value) {
* echo "$index: $value\n"
* if (1 === $index) {
* $map[1] = 4;
* $map[] = 5;
* }
* }
*
* print_r(iterator_to_array($map));
*
* // => 1: 1
* // 2: 2
* // 3: 3
* // 4: 5
* // Array
* // (
* // [1] => 4
* // [2] => 2
* // [3] => 3
* // [4] => 5
* // )
*
* The map also supports multiple parallel iterators. That means that you can
* nest foreach loops without affecting each other's iteration:
*
* foreach ($map as $index => $value) {
* foreach ($map as $index2 => $value2) {
* // ...
* }
* }
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @since 2.2.6
*/
class OrderedHashMap implements \ArrayAccess, \IteratorAggregate, \Countable
{
/**
* The elements of the map, indexed by their keys.
*
* @var array
*/
private $elements = array();
/**
* The keys of the map in the order in which they were inserted or changed.
*
* @var array
*/
private $orderedKeys = array();
/**
* References to the cursors of all open iterators.
*
* @var array
*/
private $managedCursors = array();
/**
* Creates a new map.
*
* @param array $elements The elements to insert initially.
*
* @since 2.2.6
*/
public function __construct(array $elements = array())
{
$this->elements = $elements;
$this->orderedKeys = array_keys($elements);
}
/**
* {@inheritdoc}
*
* @since 2.2.6
*/
public function offsetExists($key)
{
return isset($this->elements[$key]);
}
/**
* {@inheritdoc}
*
* @since 2.2.6
*/
public function offsetGet($key)
{
if (!isset($this->elements[$key])) {
throw new \OutOfBoundsException('The offset "' . $key . '" does not exist.');
}
return $this->elements[$key];
}
/**
* {@inheritdoc}
*
* @since 2.2.6
*/
public function offsetSet($key, $value)
{
if (null === $key || !isset($this->elements[$key])) {
if (null === $key) {
$key = array() === $this->orderedKeys
// If the array is empty, use 0 as key
? 0
// Imitate PHP's behavior of generating a key that equals
// the highest existing integer key + 1
: max($this->orderedKeys) + 1;
}
$this->orderedKeys[] = $key;
}
$this->elements[$key] = $value;
}
/**
* {@inheritdoc}
*
* @since 2.2.6
*/
public function offsetUnset($key)
{
if (false !== ($position = array_search($key, $this->orderedKeys))) {
array_splice($this->orderedKeys, $position, 1);
unset($this->elements[$key]);
foreach ($this->managedCursors as $i => $cursor) {
if ($cursor >= $position) {
--$this->managedCursors[$i];
}
}
}
}
/**
* {@inheritdoc}
*
* @since 2.2.6
*/
public function getIterator()
{
return new OrderedHashMapIterator($this->elements, $this->orderedKeys, $this->managedCursors);
}
/**
* {@inheritdoc}
*
* @since 2.2.6
*/
public function count()
{
return count($this->elements);
}
}

View File

@ -0,0 +1,163 @@
<?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\Util;
/**
* Iterator for {@link OrderedHashMap} objects.
*
* This class is internal and should not be used.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @since 2.2.6
*/
class OrderedHashMapIterator implements \Iterator
{
/**
* @var array
*/
private $elements;
/**
* @var array
*/
private $orderedKeys;
/**
* @var integer
*/
private $cursor;
/**
* @var integer
*/
private $cursorId;
/**
* @var array
*/
private $managedCursors;
/**
* @var string|integer|null
*/
private $key;
/**
* @var mixed
*/
private $current;
/**
* Creates a new iterator.
*
* @param array $elements The elements of the map, indexed by their
* keys.
* @param array $orderedKeys The keys of the map in the order in which
* they should be iterated.
* @param array $managedCursors An array from which to reference the
* iterator's cursor as long as it is alive.
* This array is managed by the corresponding
* {@link OrderedHashMap} instance to support
* recognizing the deletion of elements.
*
* @since 2.2.6
*/
public function __construct(array &$elements, array &$orderedKeys, array &$managedCursors)
{
$this->elements = &$elements;
$this->orderedKeys = &$orderedKeys;
$this->managedCursors = &$managedCursors;
$this->cursorId = count($managedCursors);
$this->managedCursors[$this->cursorId] = &$this->cursor;
}
/**
* Removes the iterator's cursors from the managed cursors of the
* corresponding {@link OrderedHashMap} instance.
*
* @since 2.2.6
*/
public function __destruct()
{
// Use array_splice() instead of isset() to prevent holes in the
// array indices, which would break the initialization of $cursorId
array_splice($this->managedCursors, $this->cursorId, 1);
}
/**
*{@inheritdoc}
*
* @since 2.2.6
*/
public function current()
{
return $this->current;
}
/**
* {@inheritdoc}
*
* @since 2.2.6
*/
public function next()
{
++$this->cursor;
if (isset($this->orderedKeys[$this->cursor])) {
$this->key = $this->orderedKeys[$this->cursor];
$this->current = $this->elements[$this->key];
} else {
$this->key = null;
$this->current = null;
}
}
/**
*{@inheritdoc}
*
* @since 2.2.6
*/
public function key()
{
return $this->key;
}
/**
*{@inheritdoc}
*
* @since 2.2.6
*/
public function valid()
{
return null !== $this->key;
}
/**
*{@inheritdoc}
*
* @since 2.2.6
*/
public function rewind()
{
$this->cursor = 0;
if (isset($this->orderedKeys[0])) {
$this->key = $this->orderedKeys[0];
$this->current = $this->elements[$this->key];
} else {
$this->key = null;
$this->current = null;
}
}
}

View File

@ -1,78 +0,0 @@
<?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\Util;
/**
* Iterator that traverses an array.
*
* Contrary to {@link \ArrayIterator}, this iterator recognizes changes in the
* original array during iteration.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/
class ReferencingArrayIterator implements \Iterator
{
/**
* @var array
*/
private $array;
/**
* Creates a new iterator.
*
* @param array $array An array
*/
public function __construct(array &$array)
{
$this->array = &$array;
}
/**
*{@inheritdoc}
*/
public function current()
{
return current($this->array);
}
/**
*{@inheritdoc}
*/
public function next()
{
next($this->array);
}
/**
*{@inheritdoc}
*/
public function key()
{
return key($this->array);
}
/**
*{@inheritdoc}
*/
public function valid()
{
return null !== key($this->array);
}
/**
*{@inheritdoc}
*/
public function rewind()
{
reset($this->array);
}
}

View File

@ -14,9 +14,6 @@ namespace Symfony\Component\Form\Util;
/**
* Iterator that traverses an array of forms.
*
* Contrary to {@link \ArrayIterator}, this iterator recognizes changes in the
* original array during iteration.
*
* You can wrap the iterator into a {@link \RecursiveIterator} in order to
* enter any child form that inherits its parent's data and iterate the children
* of that form as well.
@ -26,14 +23,14 @@ namespace Symfony\Component\Form\Util;
* @deprecated Deprecated since version 2.3, to be removed in 3.0. Use
* {@link InheritDataAwareIterator} instead.
*/
class VirtualFormAwareIterator extends ReferencingArrayIterator implements \RecursiveIterator
class VirtualFormAwareIterator extends \IteratorIterator implements \RecursiveIterator
{
/**
* {@inheritdoc}
*/
public function getChildren()
{
return new static($this->current()->all());
return new static($this->current());
}
/**