Skip to content
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

[Form] Cannot use object of type Closure as array #33188

Closed
umpirsky opened this issue Aug 15, 2019 · 9 comments
Closed

[Form] Cannot use object of type Closure as array #33188

umpirsky opened this issue Aug 15, 2019 · 9 comments

Comments

@umpirsky
Copy link
Contributor

umpirsky commented Aug 15, 2019

Symfony version(s) affected: 4.2.11

How to reproduce

Have type defined like this:

class MyDateAndTimeType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('time', TimeType::class, $options);

        $builder->addModelTransformer(new MyDateAndTimeToDateTimeTransformer());
    }

    public function getBlockPrefix()
    {
        return 'data_and_time';
    }
}

You get this error when creating the form:

Cannot use object of type Closure as array

  at vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php:80

The problem is passing options to $builder->add('time', TimeType::class, $options) which carries:

  "empty_data" => Closure(FormInterface $form) {#2763 ▼
    class: "Symfony\Component\Form\Extension\Core\Type\FormType"
    this: FormType {#2569 …}
    parameters: {▶}
    file: "vendor/symfony/symfony/src/Symfony/Component/Form/Extension/Core/Type/FormType.php"
    line: "140 to 142"
  }

This used to work in 4.1

Additional context
Suspected changeset #29182.

@xabbuh
Copy link
Member

xabbuh commented Aug 15, 2019

Does this happen with 4.3 too? If so, could your create a small example application that allows to reproduce?

@umpirsky
Copy link
Contributor Author

According to code I guess it does. I will try to create a reproducer when I have time.

@derrabus
Copy link
Member

Why do you pass the $options array on to the add() method? That looks odd to me.

@umpirsky
Copy link
Contributor Author

Yes, I fixed that, but it still feels like BC break.

@yceruto
Copy link
Member

yceruto commented Aug 19, 2019

Even if passing the parent/resolved empty_data option to the TimeType field would be wrong here, I think TimeType is not taking into account the feasible Closure value that is allowed/documented for this empty_data option:

https://symfony.com/doc/current/reference/forms/types/form.html#empty-data:

If a form is compound, you can set empty_data as an array, object or closure. See the How to Configure empty Data for a Form Class article for more details about these options.

https://symfony.com/doc/current/form/use_empty_data.html#option-2-provide-a-closure:

Using a closure is the preferred method, since it will only create the object if it is needed.
The closure must accept a FormInterface instance as the first argument.

'empty_data' => function (FormInterface $form) {
    return $form->getConfig()->getCompound() ? ['hour' => 0, 'minute' => 0] : '00:00';
},

So the above example should also work for TimeType, isn't it?

@umpirsky
Copy link
Contributor Author

Yeah, seems so.

@yceruto
Copy link
Member

yceruto commented Aug 19, 2019

$emptyData = $builder->getEmptyData() ?: [];
if (isset($emptyData['hour'])) {
$hourOptions['empty_data'] = $emptyData['hour'];
}

As we can't invoke the $emptyData() closure directly in the build process (because the form instance is not ready to be passed to the closure at that point) theoretically something like this can fix the error (unproven):

if ($emptyData instanceof \Closure) {
    $hourOptions['empty_data'] = static function (FormInterface $form) use ($emptyData) {
        $emptyData = $emptyData($form->getParent());

        return isset($emptyData['hour']) ? $emptyData['hour'] : '';
    };
} // elseif ...

@umpirsky would you like to give it a try? (bugfix in 3.4 branch)

@umpirsky
Copy link
Contributor Author

Sorry, can't work on it now, it must wait.

@yceruto
Copy link
Member

yceruto commented Oct 25, 2019

See #34123

@fabpot fabpot closed this as completed Feb 3, 2020
fabpot added a commit that referenced this issue Feb 3, 2020
…/Time form types (yceruto)

This PR was merged into the 3.4 branch.

Discussion
----------

[Form] Fix handling of empty_data's \Closure value in Date/Time form types

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #33188
| License       | MIT
| Doc PR        | -

Basically this would solve the posibility to pass a `\Closure` to the `empty_data` option for Date/Time form types.

> https://symfony.com/doc/current/reference/forms/types/form.html#empty-data
> If a form is compound, you can set empty_data as an array, object or **closure**. See the [How to Configure empty Data](https://symfony.com/doc/current/form/use_empty_data.html) for a Form Class article for more details about these options.

Also related to #29182

Commits
-------

4939f0e Fix handling of empty_data's \Closure value in Date/Time form types
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants