Skip to content
19 changes: 19 additions & 0 deletions UPGRADE-4.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,25 @@ Validator
* Calling `EmailValidator::__construct()` method with a boolean parameter is deprecated and will be removed in 5.0, use `EmailValidator("strict")` instead.
* Deprecated the `checkDNS` and `dnsMessage` options of the `Url` constraint. They will be removed in 5.0.

Form
----

* Using callable strings as `empty_data` in `ChoiceType` is deprecated and will be removed in Symfony 5.0, use a `\Closure` instead.

Before:

```php
'empty_data' => 'some_function',
```

After:

```php
'empty_data' => function (FormInterface $form, $data) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Or just Closure::fromCallable('some_function') 😉

return some_function($form, $data);
},
```

Workflow
--------

Expand Down
19 changes: 19 additions & 0 deletions UPGRADE-5.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,25 @@ Validator
* Calling `EmailValidator::__construct()` method with a boolean parameter has been removed, use `EmailValidator("strict")` instead.
* Removed the `checkDNS` and `dnsMessage` options from the `Url` constraint.

Form
----

* Support for callable strings as `empty_data` in `ChoiceType` has been removed. Use a `\Closure` instead.

Before:

```php
'empty_data' => 'some_function',
```

After:

```php
'empty_data' => function (FormInterface $form, $data) {
return some_function($form, $data);
},
```

Workflow
--------

Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/Form/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

4.1.0
-----

* deprecated support for callable strings as `empty_data` in `ChoiceType`

4.0.0
-----

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,14 @@ public function buildForm(FormBuilderInterface $builder, array $options)
$emptyData = $form->getConfig()->getEmptyData();

if (false === FormUtil::isEmpty($emptyData) && array() !== $emptyData) {
$data = is_callable($emptyData) ? call_user_func($emptyData, $form, $data) : $emptyData;
if (is_callable($emptyData)) {
if (is_string($emptyData)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I've introduced that change as a bug fix in #17822 targeting 2.7.
But I've made a mistake, IMO we should do it like https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Form.php#L610 and merge it in 2.7 as bug fix too. No need to deprecate anything.

Copy link
Member

Choose a reason for hiding this comment

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

#17822 is over 1.5y old now. People might have built code against that "feature" already. :-(

Copy link
Member

Choose a reason for hiding this comment

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

Also, I would not check for instanceof \Closure as this would forbid array callables and invokable objects for no reason.

Copy link
Contributor

Choose a reason for hiding this comment

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

The empty_data MUST be a closure for all forms, I'm not sure people rely on this hidden feature which is just a bug I introduced no matter when IMO.

@trigger_error('Passing callable strings is deprecated since version 4.1 and will be removed in 5.0. You should use a "\Closure" instead.', E_USER_DEPRECATED);
}
$data = call_user_func($emptyData, $form, $data);
} else {
$data = $emptyData;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,47 @@ public function testSubmitMultipleChoiceExpandedWithEmptyData()
$this->assertSame(array('test'), $form->getData());
}

/**
* @group legacy
*/
public function testSubmitSingleChoiceWithCallableEmptyData()
{
$form = $this->factory->create(static::TESTED_TYPE, null, array(
'multiple' => false,
'expanded' => true,
'choices' => array('test'),
'empty_data' => __CLASS__.'::emptyDataResolver',
));

$form->submit(null);

$this->assertSame('test', $form->getData());
}

/**
* @return string
*/
public static function emptyDataResolver()
{
return 'test';
}

public function testSubmitSingleChoiceWithClosureEmptyData()
{
$form = $this->factory->create(static::TESTED_TYPE, null, array(
'multiple' => false,
'expanded' => true,
'choices' => array('test'),
'empty_data' => function () {
return 'test';
},
));

$form->submit(null);

$this->assertSame('test', $form->getData());
}

public function testSubmitMultipleNonExpanded()
{
$form = $this->factory->create(static::TESTED_TYPE, null, array(
Expand Down