Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Component][Form][ChoiceType] : Add new option to sort group_by value #22136

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public function createListFromLoader(ChoiceLoaderInterface $loader, $value = nul
/**
* {@inheritdoc}
*/
public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null)
public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null, $groupByOrder = null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new value must be taken into account when building the cache key, otherwise a list could be reused while it was having a different order

{
// The input is not validated on purpose. This way, the decorated
// factory may decide which input to accept and which not.
Expand All @@ -165,7 +165,8 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null,
$label,
$index,
$groupBy,
$attr
$attr,
$groupByOrder
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@ public function createListFromLoader(ChoiceLoaderInterface $loader, $value = nul
* group names
* @param null|array|callable $attr The callable generating the
* HTML attributes
* @param null|array|callable $groupByOrder The group by order
*
* @return ChoiceListView The choice list view
*/
public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null);
public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null, $groupByOrder = null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding arguments in an interface is forbidden by our BC policy

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function createListFromLoader(ChoiceLoaderInterface $loader, $value = nul
/**
* {@inheritdoc}
*/
public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null)
public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null, $groupByOrder = null)
{
$preferredViews = array();
$otherViews = array();
Expand Down Expand Up @@ -81,6 +81,12 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null,
$otherViews
);
}

if ($groupByOrder && is_array($groupByOrder)) {
uksort($otherViews, function ($key1, $key2) use ($groupByOrder) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this logic does not seem to support callable values for $groupByOrder, while the interface allows it (and callables can be arrays, making things even worse).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to see this support both callables and predefined arrays. Something like this should work:

if ($groupByOrder) {
    if (is_callable($groupByOrder)) {
        // TODO
    } elseif (is_array($groupByOrder)) {
        // TODO
    }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@colinodell , thanks
Can you give me an example of callable groupByOrder you need ?
Which parameters you need in the function ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The callable should be compatible with uksort - anything that takes two parameters, compares them, and returns an integer. Your code would then look something like this:

if ($groupByOrder) {
    if (is_callable($groupByOrder)) {
        uksort($otherViews, $groupByOrder);
    } elseif (is_array($groupByOrder)) {
        // TODO: Your existing code goes here
    }
}

I could then use any type of callable for the groupByOrder option:

  • 'strnatcmp' - Sort them using a "natural order" algorithm via the strnatcmp() function
  • [$this, 'sortGroups'] - Use the sortGroups() function on $this
  • [Foo::class, 'sortGroups'] - Use the static sortGroups() function from the Foo class
  • function ($a, $b) { return $b <=> $a; } - Use some anonymous function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@colinodell thanks, will do that soon

return array_search($key1, $groupByOrder) > array_search($key2, $groupByOrder);
});
}
} else {
// Otherwise use the original structure of the choices
self::addChoiceViewsGroupedBy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,11 @@ public function createListFromLoader(ChoiceLoaderInterface $loader, $value = nul
* @param null|callable|string|PropertyPath $index The callable or path generating the view indices
* @param null|callable|string|PropertyPath $groupBy The callable or path generating the group names
* @param null|array|callable|string|PropertyPath $attr The callable or path generating the HTML attributes
* @param null|array|callable|string|PropertyPath $groupByOrder The groupBy order
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this does not support a PropertyPath, as you don't handle it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does PropertyPath even make sense here?

*
* @return ChoiceListView The choice list view
*/
public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null)
public function createView(ChoiceListInterface $list, $preferredChoices = null, $label = null, $index = null, $groupBy = null, $attr = null, $groupByOrder = null)
{
$accessor = $this->propertyAccessor;

Expand Down Expand Up @@ -224,6 +225,6 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null,
};
}

return $this->decoratedFactory->createView($list, $preferredChoices, $label, $index, $groupBy, $attr);
return $this->decoratedFactory->createView($list, $preferredChoices, $label, $index, $groupBy, $attr, $groupByOrder);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ public function configureOptions(OptionsResolver $resolver)
'choice_attr' => null,
'preferred_choices' => array(),
'group_by' => null,
'group_by_order' => null,
'empty_data' => $emptyData,
'placeholder' => $placeholderDefault,
'error_bubbling' => false,
Expand All @@ -356,6 +357,7 @@ public function configureOptions(OptionsResolver $resolver)
$resolver->setAllowedTypes('choice_attr', array('null', 'array', 'callable', 'string', 'Symfony\Component\PropertyAccess\PropertyPath'));
$resolver->setAllowedTypes('preferred_choices', array('array', '\Traversable', 'callable', 'string', 'Symfony\Component\PropertyAccess\PropertyPath'));
$resolver->setAllowedTypes('group_by', array('null', 'callable', 'string', 'Symfony\Component\PropertyAccess\PropertyPath'));
$resolver->setAllowedTypes('group_by_order', array('null', 'array', '\Traversable'));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this does not match the types supported by the implementation.

}

/**
Expand Down Expand Up @@ -444,7 +446,8 @@ private function createChoiceListView(ChoiceListInterface $choiceList, array $op
$options['choice_label'],
$options['choice_name'],
$options['group_by'],
$options['choice_attr']
$options['choice_attr'],
$options['group_by_order']
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1669,6 +1669,37 @@ public function testPassHierarchicalChoicesToView()
), $view->vars['preferred_choices']);
}

public function testPassHierarchicalChoicesToViewWithGroupOrder()
{
$view = $this->factory->create(static::TESTED_TYPE, null, array(
'choices' => $this->choices,
'preferred_choices' => array('b', 'd'),
'group_by' => function ($val, $key, $index) {
return (strlen($key) > 4) ? 'LongName' : 'ShortName';
},
'group_by_order' => array('ShortName', 'LongName', 'TestNotMatched'),
))
->createView();

$this->assertEquals(array(
'ShortName' => new ChoiceGroupView('ShortName', array(
2 => new ChoiceView('c', 'c', 'Kris'),
)),
'LongName' => new ChoiceGroupView('LongName', array(
0 => new ChoiceView('a', 'a', 'Bernhard'),
4 => new ChoiceView('e', 'e', 'Roman'),
)),
), $view->vars['choices']);
$this->assertEquals(array(
'LongName' => new ChoiceGroupView('LongName', array(
1 => new ChoiceView('b', 'b', 'Fabien'),
)),
'ShortName' => new ChoiceGroupView('ShortName', array(
3 => new ChoiceView('d', 'd', 'Jon'),
)),
), $view->vars['preferred_choices']);
}

public function testPassChoiceDataToView()
{
$obj1 = (object) array('value' => 'a', 'label' => 'A');
Expand Down