Sonataadminbundle: autocomplete template: Notice: Array to string conversion

Created on 6 Dec 2018  Â·  14Comments  Â·  Source: sonata-project/SonataAdminBundle

Sonata packages

$ composer show --latest 'sonata-project/*'
sonata-project/admin-bundle              3.42.1 3.42.1 The missing Symfony Admin Generator   
sonata-project/block-bundle              3.13.0 3.13.0 Symfony SonataBlockBundle
sonata-project/cache                     2.0.1  2.0.1  Cache library
sonata-project/core-bundle               3.12.0 3.12.0 Symfony SonataCoreBundle
sonata-project/datagrid-bundle           2.4.0  2.4.0  Symfony SonataDatagridBundle
sonata-project/doctrine-extensions       1.1.2  1.1.2  Doctrine2 behavioral extensions
sonata-project/doctrine-orm-admin-bundle 3.6.3  3.6.3  Symfony Sonata / Integrate Doctrine ORM into the SonataAdminBundle
sonata-project/exporter                  1.9.1  1.9.1  Lightweight Exporter library
sonata-project/intl-bundle               2.5.0  2.5.0  Symfony SonataIntlBundle

Symfony packages

$ composer show --latest 'symfony/*'
symfony/assetic-bundle          v2.8.2  v2.8.2  Integrates Assetic into Symfony2             
Package symfony/assetic-bundle is abandoned, you should avoid using it. Use symfony/webpack-encore-pack instead.
symfony/monolog-bundle          v3.3.1  v3.3.1  Symfony MonologBundle
symfony/polyfill-ctype          v1.10.0 v1.10.0 Symfony polyfill for ctype functions
symfony/psr-http-message-bridge v1.1.0  v1.1.0  PSR HTTP message bridge
symfony/security-acl            v3.0.1  v3.0.1  Symfony Security Component - ACL (Access Control List)
symfony/swiftmailer-bundle      v3.2.4  v3.2.4  Symfony SwiftmailerBundle
symfony/symfony                 v3.4.20 v4.2.1  The Symfony PHP framework

PHP version

$ php -v
PHP 7.2.12-1+0~20181112102304.11+stretch~1.gbp55f215 (cli) (built: Nov 12 2018 10:23:04) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.12-1+0~20181112102304.11+stretch~1.gbp55f215, Copyright (c) 1999-2018, by Zend Technologies

Steps to reproduce

I updated from 3.40.3 to 3.42.1 and now have an issue.

I have this form type in one of my admins:

->add('someRelation', 'sonata_type_model_autocomplete', [
    'property' => ['id', 'name'],
    'multiple' => false,
    'required' => false,
])

So one can search by id and/or name of the related entities.

Since this change here:

https://github.com/sonata-project/SonataAdminBundle/commit/caed9f37233638c1cf4a3bc7e1310c0546b1963e#diff-9596174093e5de44115aaacafe7d4d77R284

it leads to

An exception has been thrown during the rendering of a template ("Notice: Array to string conversion").

in vendor/sonata-project/admin-bundle/src/Resources/views/Form/Type/sonata_type_model_autocomplete.html.twig (line 285) 

So I think the assumption that form.vars.property is a simple scalar value is wrong. It can also be an array as in my case.

ping @psyray

bug

Most helpful comment

I will check this bug ASAP

All 14 comments

Same error for me in file in \vendor/sonata-project/admin-bundle/src/Resources/views/Form/Type/sonata_type_model_autocomplete.html.twig (line 285) :

 form['{{ sonata_admin.field_description.associationadmin.uniqid }}[{{ form.vars.property }}]'],

Ideally it should follow the admin-defined to_string_callback, but then it should be written in JS too :S

I will check this bug ASAP

I've checked this bug.

Main problem is that property is used to autoselect the record added by clicking the add button (set by btn_add option)

If the property option can take multiple values, like in your case, using the property option to get the name could work, but only if the last element is the same as the ___toString_ value returned by the entity.

It works in this case if I add this piece of code

                        {% set property_name = form.vars.property %}
                        {% if form.vars.property is iterable %}
                            {% for current_property in form.vars.property %}
                                {% set property_name = current_property %}
                            {% endfor %}
                        {% endif %}
                        var item = new Option(
                          form['{{ sonata_admin.field_description.associationadmin.uniqid }}[{{ property_name }}]'],
                          xhr.responseJSON.objectId,
                          true, true
                          );

in place of

                        var item = new Option(
                          form['{{ sonata_admin.field_description.associationadmin.uniqid }}[{{ form.vars.property }}]'],
                          xhr.responseJSON.objectId,
                          true, true
                          );

But it's more a workaround than a fix, because it can fail if you set 'property' => ['name', 'id'] (inverse fields), or if the ___toString_ is different because I take only the last one and I can't guess which one is the good one.

So like @andrewmy said, I could use the to_string_callback option to be sure to have the same __toString_ to select in both case (string and array).
So the above code should be

                        {% set property_name = form.vars.property %}
                        {% if form.vars.property is iterable %}
                                {% set property_name = form.vars.to_string_callback %}
                        {% endif %}
                        var item = new Option(
                          form['{{ sonata_admin.field_description.associationadmin.uniqid }}[{{ property_name }}]'],
                          xhr.responseJSON.objectId,
                          true, true
                          );

What's your opinion about that ?

My first thought was like your last code example, but then you just get a stringified representation of the current property, not the one you get from the newly created entity — it's already rendered by PHP and thus hard-coded into JS.

So either:
1) admin create action should return the entity's string using the callback if any;
2) or we get the new entity's string via an additional ajax request to a new endpoint;
3) or make the developer reimplement to_string_callback in both PHP and JS :(.

thanks @andrewmy
Not as easy as it looks like
@greg0ire I need your advice on this issue, what's the best method to use in this really specific case

I'd go with solution 1. That's compliant with the spec:

The 201 response payload typically describes and links to the resource(s) created

And here, you want a string representation of the created resource if I understand correctly

Yes you understand correctly
thanks @greg0ire

@greg0ire I found the solution, 2 lines modifications, but it conflicts with the PR #5345
Can I add it to the #5345 so it will solve 2 issues (this one and #5342), or should I wait #5345 to be merged to open a new PR to solve this issue ?

Lets wait for #5345 please

5345 is now merged

PR released
@dmaicher @acrozes Could you test it ? It's working fine for me.

The PR is using AbstractAdmin::toString() while the use case here is an autocomplete field which often has its own to_string_callback option, and the new entry would display differently from the others.

Is this so important ? Because at page refresh the right label should display.
The most important is that the newly created id recorded and a string representing the object takes place in the list for user verification.
Sure if the to_string_callback is completely different, it could be a problem, but only visual problem.

Was this page helpful?
0 / 5 - 0 ratings