Search code examples
phpsymfonysonata-adminsonata

Configuring Sonata Admin Bundle with Symfony 4


I'm trying to install the Sonata Admin Bundle to generate easily admin interfaces of my various entities. I've been following the official docs (https://symfony.com/doc/master/bundles/SonataAdminBundle/getting_started/creating_an_admin.html) but I'm facing a problem I can't figure out while creating my first simple Admin.

My entity is :

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\Timestampable\Traits\TimestampableEntity;

/**
 * @ORM\Entity(repositoryClass="App\Repository\SectorRepository")
 */
class Sector
{
    use TimestampableEntity;

    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=30)
     */
    private $name;

    /**
     * @Gedmo\Slug(fields={"name"})
     * @ORM\Column(type="string", length=128)
     */
    private $slug;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\Company", mappedBy="sector", cascade = {"persist"})
     * @ORM\JoinColumn(onDelete="SET NULL")
     */
    private $companies;

    public function __toString()
    {
        return $this->name;
    }

    public function getId()
    {
        return $this->id;
    }

    public function getName(): ?string
    {
        return $this->name;
    }

    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }

    public function getSlug(): ?string
    {
        return $this->slug;
    }

    public function setSlug(string $slug): self
    {
        $this->slug = $slug;

        return $this;
    }

    public function getCompanies(): array
    {
        return $this->companies;
    }

    public function setCompanies($companies): self
    {
        $this->companies = $companies;

        return $this;
    }
}

My Admin class looks like this:

<?php

namespace App\Admin;

use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Symfony\Component\Form\Extension\Core\Type\TextType;

class SectorAdmin extends AbstractAdmin
{
    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper->add('name', TextType::class);
    }

    protected function configureDatagridFilters(DatagridMapper $datagridMapper)
    {
        $datagridMapper->add('name');
    }

    protected function configureListFields(ListMapper $listMapper)
    {
        $listMapper->addIdentifier('name');
    }
}

I've added this configuration:

services:
    admin.sector:
        class: App\Admin\SectorAdmin
        arguments: [ ~, App\Entity\Sector, ~]
        tags:
            - { name: sonata.admin, manager_type: orm, label: Sector}
    public: true

And in my sonata admin routes file:

admin_area:
    resource: "@SonataAdminBundle/Resources/config/routing/sonata_admin.xml"
    prefix: /admin

_sonata_admin:
    resource: .
    type: sonata_admin
    prefix: /admin

Which is, as I understand from the doc the minimum configuration to get the Admin to be registered.

Yet, when I run my code, I get an error "Array to string conversion" on the {{ form_errors(form) }} of the datagrid filters. If I comment out the line adding the name attribute to these filters, the list page renders fine but if I then enter the form (creation/edition) view, I get the same error on another element so I guess the problem is deeper.

Could it be a problem of compatibility with Symfony 4.x ?

Thanks by advance !


Solution

  • I run to the same problem. Its happened I think in symfony 3.4 where they introduced new widget with same name as the one provided from bundle.

    Actually I have no idea how to solve it without BC breaks. So far I have used solution where I patch PhoneNumberBundle and rename tel_widget to misd_tel_widget.

    Here is my patch - https://pastebin.com/CnjXB1bi. I'm applying patch in composer file using https://github.com/cweagans/composer-patches.

    Patch code:

    diff --git a/Form/Type/PhoneNumberType.php b/Form/Type/PhoneNumberType.php
    index 58b67bf..9c31add 100644
    --- a/Form/Type/PhoneNumberType.php
    +++ b/Form/Type/PhoneNumberType.php
    @@ -183,6 +183,6 @@ class PhoneNumberType extends AbstractType
          */
         public function getBlockPrefix()
         {
    -        return 'tel';
    +        return 'misd_tel';
         }
     }
    diff --git a/Resources/views/Form/tel.html.twig b/Resources/views/Form/tel.html.twig
    index 1fdfed4..c8064e4 100644
    --- a/Resources/views/Form/tel.html.twig
    +++ b/Resources/views/Form/tel.html.twig
    @@ -1,4 +1,4 @@
    -{% block tel_widget -%}
    +{% block misd_tel_widget -%}
         {% if widget is constant('Misd\\PhoneNumberBundle\\Form\\Type\\PhoneNumberType::WIDGET_COUNTRY_CHOICE') %}
             <div {{ block('widget_container_attributes') }}>
                 {{- form_widget(form.country) -}}
    diff --git a/Resources/views/Form/tel_bootstrap.html.twig b/Resources/views/Form/tel_bootstrap.html.twig
    index 79f4748..7772df9 100644
    --- a/Resources/views/Form/tel_bootstrap.html.twig
    +++ b/Resources/views/Form/tel_bootstrap.html.twig
    @@ -1,4 +1,4 @@
    -{% block tel_widget -%}
    +{% block misd_tel_widget -%}
         {% if widget is constant('Misd\\PhoneNumberBundle\\Form\\Type\\PhoneNumberType::WIDGET_COUNTRY_CHOICE') %}
             {% set attr = attr|merge({class: (attr.class|default('') ~ ' form-inline')|trim}) %}
             <div {{ block('widget_container_attributes') }}>