From d6dec8add0074b048f43800a83b660f2a58023e8 Mon Sep 17 00:00:00 2001 From: Evgeniy Sokolov Date: Wed, 18 Nov 2015 09:28:32 +0100 Subject: [PATCH] Allow choices with duplicated content --- .../Form/ChoiceList/ArrayChoiceList.php | 66 +++++++++++- .../Form/ChoiceList/ArrayKeyChoiceList.php | 14 ++- .../Form/ChoiceList/ChoiceListInterface.php | 21 ++++ .../Factory/DefaultChoiceListFactory.php | 65 +++++------ .../Form/ChoiceList/LazyChoiceList.php | 36 +++++++ .../ChoiceList/LegacyChoiceListAdapter.php | 24 +++++ .../Factory/DefaultChoiceListFactoryTest.php | 102 ++++++++++++++++++ 7 files changed, 291 insertions(+), 37 deletions(-) diff --git a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php index 156735b81751e..54c54baedca68 100644 --- a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php +++ b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php @@ -53,6 +53,27 @@ class ArrayChoiceList implements ChoiceListInterface */ protected $valueCallback; + /** + * The raw choice of the choices array. + * + * @var array + */ + protected $rawChoices; + + /** + * The raw choice values of the choices array. + * + * @var array + */ + protected $rawChoiceValues; + + /** + * The raw keys of the choices array. + * + * @var int[]|string[] + */ + protected $rawKeys; + /** * Creates a list with the given choices and values. * @@ -63,6 +84,8 @@ class ArrayChoiceList implements ChoiceListInterface * for a choice. If `null` is passed, * incrementing integers are used as * values + * + * @throws UnexpectedTypeException */ public function __construct($choices, $value = null) { @@ -88,11 +111,14 @@ public function __construct($choices, $value = null) // If the choices are given as recursive array (i.e. with explicit // choice groups), flatten the array. The grouping information is needed // in the view only. - $this->flatten($choices, $value, $choicesByValues, $keysByValues, $structuredValues); + $this->flatten($choices, $value, $choicesByValues, $keysByValues, $structuredValues, $rawChoices, $rawChoiceValues, $rawKeys); $this->choices = $choicesByValues; $this->originalKeys = $keysByValues; $this->structuredValues = $structuredValues; + $this->rawChoices = $rawChoices; + $this->rawChoiceValues = $rawChoiceValues; + $this->rawKeys = $rawKeys; } /** @@ -127,6 +153,30 @@ public function getOriginalKeys() return $this->originalKeys; } + /** + * {@inheritdoc} + */ + public function getRawChoices() + { + return $this->rawChoices; + } + + /** + * {@inheritdoc} + */ + public function getRawChoiceValues() + { + return $this->rawChoiceValues; + } + + /** + * {@inheritdoc} + */ + public function getRawKeys() + { + return $this->rawKeys; + } + /** * {@inheritdoc} */ @@ -183,20 +233,27 @@ public function getValuesForChoices(array $choices) * corresponding values * @param array $keysByValues The original keys indexed by the * corresponding values + * @param $structuredValues + * @param $rawChoices + * @param $rawChoiceValues + * @param $rawKeys * * @internal Must not be used by user-land code */ - protected function flatten(array $choices, $value, &$choicesByValues, &$keysByValues, &$structuredValues) + protected function flatten(array $choices, $value, &$choicesByValues, &$keysByValues, &$structuredValues, &$rawChoices, &$rawChoiceValues, &$rawKeys) { if (null === $choicesByValues) { $choicesByValues = array(); $keysByValues = array(); $structuredValues = array(); + $rawChoices = array(); + $rawChoiceValues = array(); + $rawKeys = array(); } foreach ($choices as $key => $choice) { if (is_array($choice)) { - $this->flatten($choice, $value, $choicesByValues, $keysByValues, $structuredValues[$key]); + $this->flatten($choice, $value, $choicesByValues, $keysByValues, $structuredValues[$key], $rawChoices[$key], $rawChoiceValues[$key], $rawKeys[$key]); continue; } @@ -205,6 +262,9 @@ protected function flatten(array $choices, $value, &$choicesByValues, &$keysByVa $choicesByValues[$choiceValue] = $choice; $keysByValues[$choiceValue] = $key; $structuredValues[$key] = $choiceValue; + $rawChoices[$key] = $choice; + $rawChoiceValues[$key] = $choiceValue; + $rawKeys[$key] = $key; } } } diff --git a/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php b/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php index 7c3c107d0f720..361353b1b98dd 100644 --- a/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php +++ b/src/Symfony/Component/Form/ChoiceList/ArrayKeyChoiceList.php @@ -159,20 +159,27 @@ public function getValuesForChoices(array $choices) * corresponding values * @param array $keysByValues The original keys indexed by the * corresponding values + * @param $structuredValues + * @param $rawChoices + * @param $rawChoiceValues + * @param $rawKeys * * @internal Must not be used by user-land code */ - protected function flatten(array $choices, $value, &$choicesByValues, &$keysByValues, &$structuredValues) + protected function flatten(array $choices, $value, &$choicesByValues, &$keysByValues, &$structuredValues, &$rawChoices, &$rawChoiceValues, &$rawKeys) { if (null === $choicesByValues) { $choicesByValues = array(); $keysByValues = array(); $structuredValues = array(); + $rawChoices = array(); + $rawChoiceValues = array(); + $rawKeys = array(); } foreach ($choices as $choice => $key) { if (is_array($key)) { - $this->flatten($key, $value, $choicesByValues, $keysByValues, $structuredValues[$choice]); + $this->flatten($key, $value, $choicesByValues, $keysByValues, $structuredValues[$choice], $rawChoices[$choice], $rawChoiceValues[$choice], $rawKeys[$choice]); continue; } @@ -181,6 +188,9 @@ protected function flatten(array $choices, $value, &$choicesByValues, &$keysByVa $choicesByValues[$choiceValue] = $choice; $keysByValues[$choiceValue] = $key; $structuredValues[$key] = $choiceValue; + $rawChoices[$choice] = $choiceValue; + $rawChoiceValues[$choice] = $choiceValue; + $rawKeys[$choice] = $key; } } } diff --git a/src/Symfony/Component/Form/ChoiceList/ChoiceListInterface.php b/src/Symfony/Component/Form/ChoiceList/ChoiceListInterface.php index b59e77bf795a5..ac13a22cf82f9 100644 --- a/src/Symfony/Component/Form/ChoiceList/ChoiceListInterface.php +++ b/src/Symfony/Component/Form/ChoiceList/ChoiceListInterface.php @@ -88,6 +88,27 @@ public function getStructuredValues(); */ public function getOriginalKeys(); + /** + * Returns the raw choices. + * + * @return array The raw choices + */ + public function getRawChoices(); + + /** + * Returns the raw choice values. + * + * @return array The raw choice values + */ + public function getRawChoiceValues(); + + /** + * Returns the raw keys. + * + * @return int[]|string[] The raw choice keys + */ + public function getRawKeys(); + /** * Returns the choices corresponding to the given values. * diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php b/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php index ef93ffdd76336..3dd97b973be5b 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php @@ -103,12 +103,14 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null, // choice is not added to any group if (is_callable($groupBy)) { foreach ($choices as $value => $choice) { + $stringValue = (string) $value; + self::addChoiceViewGroupedBy( $groupBy, $choice, - (string) $value, + $stringValue, $label, - $keys, + $keys[$stringValue], $index, $attr, $preferredChoices, @@ -118,11 +120,11 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null, } } else { // Otherwise use the original structure of the choices - self::addChoiceViewsGroupedBy( - $list->getStructuredValues(), + self::addChoiceViews( + $list->getRawChoices(), + $list->getRawChoiceValues(), $label, - $choices, - $keys, + $list->getRawKeys(), $index, $attr, $preferredChoices, @@ -148,48 +150,47 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null, return new ChoiceListView($otherViews, $preferredViews); } - private static function addChoiceView($choice, $value, $label, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews) + private static function addChoiceView($data, $value, $labelCallback, $label, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews) { // $value may be an integer or a string, since it's stored in the array // keys. We want to guarantee it's a string though. - $key = $keys[$value]; - $nextIndex = is_int($index) ? $index++ : call_user_func($index, $choice, $key, $value); + $nextIndex = is_int($index) ? $index++ : call_user_func($index, $data, $label, $value); $view = new ChoiceView( - $choice, + $data, $value, // If the labels are null, use the original choice key by default - null === $label ? (string) $key : (string) call_user_func($label, $choice, $key, $value), + null === $labelCallback ? (string) $label : (string) call_user_func($labelCallback, $data, $label, $value), // The attributes may be a callable or a mapping from choice indices // to nested arrays - is_callable($attr) ? call_user_func($attr, $choice, $key, $value) : (isset($attr[$key]) ? $attr[$key] : array()) + is_callable($attr) ? call_user_func($attr, $data, $label, $value) : (isset($attr[$label]) ? $attr[$label] : array()) ); // $isPreferred may be null if no choices are preferred - if ($isPreferred && call_user_func($isPreferred, $choice, $key, $value)) { + if ($isPreferred && call_user_func($isPreferred, $data, $label, $value)) { $preferredViews[$nextIndex] = $view; } else { $otherViews[$nextIndex] = $view; } } - private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews) + private static function addChoiceViews($dataValues, $values, $labelCallback, $labels, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews) { - foreach ($groupBy as $key => $value) { - if (null === $value) { + foreach ($dataValues as $key => $data) { + if (null === $data) { continue; } // Add the contents of groups to new ChoiceGroupView instances - if (is_array($value)) { + if (is_array($data)) { $preferredViewsForGroup = array(); $otherViewsForGroup = array(); - self::addChoiceViewsGroupedBy( - $value, - $label, - $choices, - $keys, + self::addChoiceViews( + $data, + $values[$key], + $labelCallback, + $labels[$key], $index, $attr, $isPreferred, @@ -210,10 +211,10 @@ private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $key // Add ungrouped items directly self::addChoiceView( - $choices[$value], - $value, - $label, - $keys, + $data, + $values[$key], + $labelCallback, + $labels[$key], $index, $attr, $isPreferred, @@ -223,17 +224,17 @@ private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $key } } - private static function addChoiceViewGroupedBy($groupBy, $choice, $value, $label, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews) + private static function addChoiceViewGroupedBy($groupBy, $data, $value, $labelCallback, $label, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews) { - $groupLabel = call_user_func($groupBy, $choice, $keys[$value], $value); + $groupLabel = call_user_func($groupBy, $data, $label, $value); if (null === $groupLabel) { // If the callable returns null, don't group the choice self::addChoiceView( - $choice, + $data, $value, + $labelCallback, $label, - $keys, $index, $attr, $isPreferred, @@ -254,10 +255,10 @@ private static function addChoiceViewGroupedBy($groupBy, $choice, $value, $label } self::addChoiceView( - $choice, + $data, $value, + $labelCallback, $label, - $keys, $index, $attr, $isPreferred, diff --git a/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php b/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php index f691d71330715..11a699e0e4ab7 100644 --- a/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php +++ b/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php @@ -101,6 +101,42 @@ public function getStructuredValues() return $this->loadedList->getStructuredValues(); } + /** + * {@inheritdoc} + */ + public function getRawChoices() + { + if (!$this->loadedList) { + $this->loadedList = $this->loader->loadChoiceList($this->value); + } + + return $this->loadedList->getRawChoices(); + } + + /** + * {@inheritdoc} + */ + public function getRawChoiceValues() + { + if (!$this->loadedList) { + $this->loadedList = $this->loader->loadChoiceList($this->value); + } + + return $this->loadedList->getRawChoiceValues(); + } + + /** + * {@inheritdoc} + */ + public function getRawKeys() + { + if (!$this->loadedList) { + $this->loadedList = $this->loader->loadChoiceList($this->value); + } + + return $this->loadedList->getRawKeys(); + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Form/ChoiceList/LegacyChoiceListAdapter.php b/src/Symfony/Component/Form/ChoiceList/LegacyChoiceListAdapter.php index 929ef8c290ded..46afd8d2c2ab7 100644 --- a/src/Symfony/Component/Form/ChoiceList/LegacyChoiceListAdapter.php +++ b/src/Symfony/Component/Form/ChoiceList/LegacyChoiceListAdapter.php @@ -101,6 +101,30 @@ public function getOriginalKeys() return array_flip($this->structuredValues); } + /** + * {@inheritdoc} + */ + public function getRawChoices() + { + throw new \BadMethodCallException('Raw choices not support by LegacyChoiceList'); + } + + /** + * {@inheritdoc} + */ + public function getRawChoiceValues() + { + throw new \BadMethodCallException('Raw choice values not support by LegacyChoiceList'); + } + + /** + * {@inheritdoc} + */ + public function getRawKeys() + { + throw new \BadMethodCallException('Raw keys not support by LegacyChoiceList'); + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php index 741cde5b43921..32fa0790b6dd6 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form\Tests\ChoiceList\Factory; use Symfony\Component\Form\ChoiceList\ArrayChoiceList; +use Symfony\Component\Form\ChoiceList\ArrayKeyChoiceList; use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory; use Symfony\Component\Form\ChoiceList\LazyChoiceList; @@ -574,6 +575,107 @@ public function testCreateViewFlatGroupByOriginalStructure() $this->assertGroupedView($view); } + public function testCreateViewDuplicateArrayChoiceListValues() + { + $list = new ArrayChoiceList( + array( + 'A' => 'a', + 'AA' => 'a', + 'Group 1' => array( + 'E' => 'e', + 'EE' => 'e', + 'A' => 'abc', + ), + 'Group 2' => array( + 'B' => 'b', + 'E' => 'e', + ), + 'AAA' => 'a', + ), + function ($choice) { + return $choice; + } + ); + + $view = $this->factory->createView($list); + + $this->assertEquals( + new ChoiceListView( + array( + 0 => new ChoiceView('a', 'a', 'A'), + 1 => new ChoiceView('a', 'a', 'AA'), + 'Group 1' => new ChoiceGroupView( + 'Group 1', + array( + 2 => new ChoiceView('e', 'e', 'E'), + 3 => new ChoiceView('e', 'e', 'EE'), + 4 => new ChoiceView('abc', 'abc', 'A'), + ) + ), + 'Group 2' => new ChoiceGroupView( + 'Group 2', + array( + 5 => new ChoiceView('b', 'b', 'B'), + 6 => new ChoiceView('e', 'e', 'E'), + ) + ), + 7 => new ChoiceView('a', 'a', 'AAA'), + ), + array() + ), + $view + ); + } + + public function testCreateViewDuplicateArrayKeyChoiceListValues() + { + $list = new ArrayKeyChoiceList( + array( + 'A' => 'a', + 'AA' => 'a', + 'Group 1' => array( + 'E' => 'e', + 'EE' => 'e', + 'A' => 'abc', + ), + 'Group 2' => array( + 'B' => 'b', + 'E' => 'e', + ), + 'AAA' => 'a', + ) + ); + + $view = $this->factory->createView($list); + + $this->assertEquals( + new ChoiceListView( + array( + 0 => new ChoiceView('A', 'A', 'a'), + 1 => new ChoiceView('AA', 'AA', 'a'), + 'Group 1' => new ChoiceGroupView( + 'Group 1', + array( + 2 => new ChoiceView('E', 'E', 'e'), + 3 => new ChoiceView('EE', 'EE', 'e'), + 4 => new ChoiceView('A', 'A', 'abc'), + ) + ), + 'Group 2' => new ChoiceGroupView( + 'Group 2', + array( + 5 => new ChoiceView('B', 'B', 'b'), + 6 => new ChoiceView('E', 'E', 'e'), + ) + ), + 7 => new ChoiceView('AAA', 'AAA', 'a'), + ), + array() + ), + $view + ); + } + public function testCreateViewFlatGroupByEmpty() { $view = $this->factory->createView( pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy