8000 [Form] added "choice_label_attr" option and deprecated "choice_attr" as multi-arrays or property path by HeahDude · Pull Request #16834 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Form] added "choice_label_attr" option and deprecated "choice_attr" as multi-arrays or property path #16834

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
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
65 changes: 65 additions & 0 deletions UPGRADE-3.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,71 @@ Finder

* The `ExceptionInterface` has been deprecated and will be removed in 4.0.

Form
----

* Using `choice_attr` option as an array of nested arrays has been deprecated
and indexes will be considered as attributes in 4.0. Use a unique array for
all choices or a `callable` instead.

Before:

```php
// Single array for all choices using callable
'choice_attr' => function () {
return array('class' => 'choice-options');
},

// Different arrays per choices using array
'choices' => array(
'Yes' => true,
'No' => false,
'Maybe' => null,
'choice_attr' => array(
'Yes' => array('class' => 'option-green'),
'No' => array('class' => 'option-red'),
),
```

After:

```php
// Single array for all choices using array
'choice_attr' => array('class' => 'choice-options'),

// Different arrays per choices using callable
'choices' => array(
'Yes' => true,
'No' => false,
'Maybe' => null,
'choice_attr' => function ($choice, $index, $value) {
if ('Yes' === $index) {
return array('class' => 'option-green');
}
if ('No' === $index) {
return array('class' => 'option-red');
}

return array();
},
```

* Using `choice_attr` option as a string or a `ProprertyPath` instance has been
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice catch, thanks!

deprecated and will throw an exception in 4.0. Use a `callable` instead.

Before:

```php
'choice_attr' => 'htmlAttributes',
```

After:

```php
'choice_attr' => function ($choice, $value, $index) {
return $choice->getHtmlAttributes();
```

FrameworkBundle
---------------

Expand Down
63 changes: 63 additions & 0 deletions UPGRADE-4.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,69 @@ Form
}
```

* Usage of `choice_attr` option as an array of nested arrays has been removed
and indexes will be considered as attributes in 4.0. Use a unique array for
all choices or a `callable` instead.

Before:

```php
// Single array for all choices using callable
'choice_attr' => function () {
return array('class' => 'choice-options');
},

// Different arrays per choices using array
'choices' => array(
'Yes' => true,
'No' => false,
'Maybe' => null,
'choice_attr' => array(
'Yes' => array('class' => 'option-green'),
'No' => array('class' => 'option-red'),
),
```

After:

```php
// Single array for all choices using array
'choice_attr' => array('class' => 'choice-options'),

// Different arrays per choices using callable
'choices' => array(
'Yes' => true,
'No' => false,
'Maybe' => null,
'choice_attr' => function ($choice, $index, $value) {
if ('Yes' === $index) {
return array('class' => 'option-green');
}
if ('No' === $index) {
return array('class' => 'option-red');
}

return array();
},
```

* Using `choice_attr` option as a string or a `ProprertyPath` instance will
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

throw an exception. Use a `callable` instead.

Before:

```php
'choice_attr' => 'htmlAttributes',
```

After:

```php
'choice_attr' => function ($choice, $value, $index) {
return $choice->getHtmlAttributes();
},
```

FrameworkBundle
---------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class FormExtensionBootstrap3HorizontalLayoutTest extends AbstractBootstrap3Hori

protected $testableFeatures = array(
'choice_attr',
'choice_label_attr',
);

private $renderer;
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Bridge/Twig/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"require-dev": {
"symfony/asset": "~2.8|~3.0",
"symfony/finder": "~2.8|~3.0",
"symfony/form": "^3.2.5",
"symfony/form": "~3.3",
"symfony/http-kernel": "~3.2",
"symfony/polyfill-intl-icu": "~1.0",
"symfony/routing": "~2.8|~3.0",
Expand Down
3 changes: 3 additions & 0 deletions src/Symfony/Component/Form/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ CHANGELOG
* added `Symfony\Component\Form\FormErrorIterator::findByCodes()`
* added `getTypedExtensions`, `getTypes`, and `getTypeGuessers` to `Symfony\Component\Form\Test\FormIntegrationTestCase`
* added `FormPass`
* deprecated `choice_attr` option as array of nested arrays mapped by indexes
* deprecated `choice_attr` option as string or `PropertyPath` instance
* added `choice_label_attr` option to `ChoiceType` to use when expanded

3.2.0
-----
Expand Down
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, $labelAttr = null)
{
// 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,
$labelAttr
);
}

Expand Down
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, $labelAttr = null)
Copy link
Member

Choose a reason for hiding this comment

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

same here

{
$preferredViews = array();
$otherViews = array();
Expand Down Expand Up @@ -76,6 +76,7 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null,
$keys,
$index,
$attr,
$labelAttr,
$preferredChoices,
$preferredViews,
$otherViews
Expand All @@ -90,6 +91,7 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null,
$keys,
$index,
$attr,
$labelAttr,
$preferredChoices,
$preferredViews,
$otherViews
Expand All @@ -113,7 +115,7 @@ 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($choice, $value, $label, $keys, &$index, $attr, $labelAttr, $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.
Expand All @@ -131,13 +133,32 @@ private static function addChoiceView($choice, $value, $label, $keys, &$index, $
$label = false === $dynamicLabel ? false : (string) $dynamicLabel;
}

// BC
if (is_array($attr)) {
if (isset($attr[$key])) {
@trigger_error('Passing an array of arrays to the "choice_attr" option with choice keys as keys is deprecated since version 3.3 and will no longer be supported in 4.0. Use a "\Closure" instead.', E_USER_DEPRECATED);
$attr = $attr[$key];
} else {
foreach ($attr as $a) {
if (is_array($a)) {
// Using the deprecated way of choice keys as keys allows to not define all choices.
// When $attr[$key] is not set for this one but is for another we need to
// prevent using an array as HTML attribute
$attr = array();

break;
}
}
}
}

$view = new ChoiceView(
$choice,
$value,
$label,
// 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())
// The attributes may be a callable or an array
is_callable($attr) ? call_user_func($attr, $choice, $key, $value) : (null !== $attr ? $attr : array()),
is_callable($labelAttr) ? call_user_func($labelAttr, $choice, $key, $value) : (null !== $labelAttr ? $labelAttr : array())
);

// $isPreferred may be null if no choices are preferred
Expand All @@ -148,7 +169,7 @@ private static function addChoiceView($choice, $value, $label, $keys, &$index, $
}
}

private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews)
private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $keys, &$index, $attr, $labelAttr, $isPreferred, &$preferredViews, &$otherViews)
{
foreach ($groupBy as $key => $value) {
if (null === $value) {
Expand All @@ -167,6 +188,7 @@ private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $key
$keys,
$index,
$attr,
$labelAttr,
$isPreferred,
$preferredViewsForGroup,
$otherViewsForGroup
Expand All @@ -191,14 +213,15 @@ private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $key
$keys,
$index,
$attr,
$labelAttr,
$isPreferred,
$preferredViews,
$otherViews
);
}
}

private static function addChoiceViewGroupedBy($groupBy, $choice, $value, $label, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews)
private static function addChoiceViewGroupedBy($groupBy, $choice, $value, $label, $keys, &$index, $attr, $labelAttr, $isPreferred, &$preferredViews, &$otherViews)
{
$groupLabel = call_user_func($groupBy, $choice, $keys[$value], $value);

Expand All @@ -211,6 +234,7 @@ private static function addChoiceViewGroupedBy($groupBy, $choice, $value, $label
$keys,
$index,
$attr,
$labelAttr,
$isPreferred,
$preferredViews,
$otherViews
Expand All @@ -235,6 +259,7 @@ private static function addChoiceViewGroupedBy($groupBy, $choice, $value, $label
$keys,
$index,
$attr,
$labelAttr,
$isPreferred,
$preferredViews[$groupLabel]->choices,
$otherViews[$groupLabel]->choices
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 $labelAttr The array or callable generating the label HTML attributes
*
* @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, $labelAttr = null)
Copy link
Member

Choose a reason for hiding this comment

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

BC break here too

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes they all use the same interface.

The BC break is only mentioned as 'Yes' in the description for now, is there anything more I need to do about it ?

Copy link
Member

Choose a reason for hiding this comment

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

Well, the issue is that we cannot make such a BC break in a minor release. So we should find another solution that would be mergable for the 3.1 release (I don't have any idea yet).

{
$accessor = $this->propertyAccessor;

Expand Down Expand Up @@ -218,12 +219,13 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null,
@trigger_error('Passing callable strings is deprecated since version 3.1 and PropertyAccessDecorator will treat them as property paths in 4.0. You should use a "\Closure" instead.', E_USER_DEPRECATED);
}

// Deprecated since 3.3 and to be removed in 4.0 with the condition above
Copy link
Member

Choose a reason for hiding this comment

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

if it is deprecated, it must trigger a deprecation notice.

And why deprecating this feature ? It is not consistent with other properties.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because of what =I explained in the related issue, it's more consistent IMO to deprecate this behavior rather than supporting it for choice_label_attr too, this is unneeded overhead, the callable or unique array should be the way to go for these.

if ($attr instanceof PropertyPath) {
$attr = function ($choice) use ($accessor, $attr) {
return $accessor->getValue($choice, $attr);
};
}

return $this->decoratedFactory->createView($list, $preferredChoices, $label, $index, $groupBy, $attr);
return $this->decoratedFactory->createView($list, $preferredChoices, $label, $index, $groupBy, $attr, $labelAttr);
}
}
19 changes: 14 additions & 5 deletions src/Symfony/Component/Form/ChoiceList/View/ChoiceView.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,28 @@ class ChoiceView
*/
public $attr;

/**
* Additional label attributes for the HTML tag.
*
* @var array
*/
public $labelAttr;

/**
* Creates a new choice view.
*
* @param mixed $data The original choice
* @param string $value The view representation of the choice
* @param string $label The label displayed to humans
* @param array $attr Additional attributes for the HTML tag
* @param mixed $data The original choice
* @param string $value The view representation of the choice
* @param string $label The label displayed to humans
* @param array $attr Additional attributes for the HTML tag
* @param array $labelAttr Additional label attributes for the HTML tag
*/
public function __construct($data, $value, $label, array $attr = array())
public function __construct($data, $value, $label, array $attr = array(), array $labelAttr = array())
{
$this->data = $data;
$this->value = $value;
$this->label = $label;
$this->attr = $attr;
$this->labelAttr = $labelAttr;
}
}
Loading
0