Cómo instalar SonataAdmin en Symfony 4

En este artículo quiero hablaros de los pasos que hay que seguir para instalar y configurar el bundle SonataAdmin en un proyecto con Symfony, así como algunos de sus principales trucos que se encuentran ocultos entre la documentación y que suelen ser de gran ayuda.

Para quien no conozca SonataAdmin, os diré que es un bundle que nos permite añadir un panel de administración CRUD para nuestras entidades y personalizarlo tanto como queramos añadiéndole funcionalidad por medio de bloques y controladores personalizados:

Seguramente os suene también EasyAdmin como alternativa a SonataAdmin, otro bundle para Symfony que permite crear un panel de administración desde cero, si bien cuando en su momento tuve que decantarme por uno de los dos vi al segundo bastante más completo y personalizable (aunque su curva de aprendizaje sea más elevada). Pero como siempre que hablamos de gustos, lo mejor es probar ambos y escoger el que más se adapte a nuestro estilo o necesidades.

Y ahora sí, vamos a instar Sonata Admin en nuestro proyecto.

Paso 0

Lo primero de todo será tener un proyecto Symfony configurado con la versión 4.* y los siguientes bundles (para este tutorial usaremos una base de datos MySQL y Doctrine como ORM):

  • symfony/orm-pack cuya configuración tenéis en este enlace: https://symfony.com/doc/current/doctrine.html
  • symfony/maker-bundle , para automatizar el proceso de creación de entidades y administradores para cada uno de ellas.
  • Tener alguna entidad creada en nuestra aplicación para comprobar que todo funciona correctamente

Paso 1. Instalar SonataAdminBundle

A continuación instalaremos el bundle sonata-project/admin-bundle mediante el comando:

composer require sonata-project/admin-bundle

Y gracias a la magia de flex se ejecutarán las recipes asociadas tanto al bundle sonata-project/core-bundle como al propio admin-bundle que dejarán prácticamente configurado el panel de administración.

Si todo ha ido bien, en bundles.php se deberán haber añadido las líneas:

Sonata\DatagridBundle\SonataDatagridBundle::class => [‘all’ => true],
Sonata\CoreBundle\SonataCoreBundle::class => [‘all’ => true],
Sonata\BlockBundle\SonataBlockBundle::class => [‘all’ => true],
Knp\Bundle\MenuBundle\KnpMenuBundle::class => [‘all’ => true],
Sonata\AdminBundle\SonataAdminBundle::class => [‘all’ => true],

Además, se deberá haber creado un archivo en la ruta config/packages/sonata_admin.yaml con el siguiente contenido:

sonata_admin:
  title: 'Sonata Admin'
  dashboard:
    blocks:
      - { type: sonata.admin.block.admin_list, position: left }
sonata_block:
  blocks:
    sonata.admin.block.admin_list:
      contexts: [admin]

Nota. Dentro de sonata_admin podéis añadir otra clave llamada title_logo con la ruta al archivo de vuestro logo dentro de la carpeta public , algo del estilo:

title_logo: bundles/sonataadmin/logo_title.png

Y otro en la ruta config/packages/sonata_core.yml con este aspecto:

sonata_core:
  form:
    mapping:
      enabled: false

Finalmente, se deberán haber añadido automágicamente las rutas del panel de administración en el archivo config/routes/sonata_admin.yaml :

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

Paso 2. Configurar SonataAdminBundle

Instalado el bundle pasaremos a configurarlo. Para lo cual iremos al archivo config/packages/framework.yaml y añadiremos:

translator: { fallbacks: ['%locale%'] }

dentro de la sección framework .

Hecho ésto, será la hora de limpiar la caché e instalar los assets de SonataAdmin:

bin/console cache:clear
bin/console assets:install

De modo que si accedemos a la ruta /admin podremos ver nuestro panel de administración.

Paso 3. Instalar SonataDoctrineORMAdminBundle

Como os decía al principio de este artículo, estamos partiendo de un proyecto con MySQL como base de datos y Doctrine como ORM, de ahí que vayamos a emplear este bundle. Sin embargo existen alternativas para Mongo:
y para PHPCR:

De cara a poder realizar operaciones CRUD sobre nuestras entidades, necesitaremos un bundle que permita crear los formularios pertinentes y asociarlos con Doctrine. De ello se encargará el bundle DoctrineORMAdminBundle el cual instalaremos del siguiente modo:

composer require sonata-project/doctrine-orm-admin-bundle

De nuevo nos solicitará ejecutar la recipe asociada al bundle, por lo que tras confirmarla deberá haberse añadido al archivo config/bundles.php la siguiente línea:

Sonata\DoctrineORMAdminBundle\SonataDoctrineORMAdminBundle::class => ['all' => true]

Y con eso ya estaría preparada la configuración inicial de este bundle (más rápido imposible). El resto de opciones disponibles las tenéis aquí:

Paso 4. Creando nuestro primer Admin

Una vez hecho todo esto, será el momento de crear nuestro primer administrador.

En SonataAdmin, un administrador es un servicio que hereda de la clase

Sonata\AdminBundle\Admin\AbstractAdmin

y donde se definen:

  • los campos que se ven en los listados de esta entidad,
  • los campos del formulario de creación y edición,
  • los campos que se verán cuando accedamos al detalle de la entidades
  • y los campos por los que queremos filtrar los listados.

Por convención, estos servicios los nombraremos NombreEntidadAdmin y los alojaremos en la carpeta src/Admin . Por ejemplo, para una entidad llamada Project podríamos crear la siguiente clase ProjectAdmin :

<?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;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
final class ProjectAdmin extends AbstractAdmin {
  protected function configureFormFields(FormMapper $formMapper) {
    $formMapper
      ->add('name', TextType::class, ['label' => 'Nombre'])
      ->add('description', TextareaType::class, ['label' =>      'Descripción']);
  }
  protected function configureDatagridFilters(DatagridMapper  $datagridMapper)  {
    $datagridMapper->add('name', null, ['label' => 'Nombre']);
  }
  protected function configureListFields(ListMapper $listMapper) {
    $listMapper->addIdentifier('name', null, ['label' => 'Nombre']);
  }
}

configureFormFields define los campos del formulario de edición y creación.

configureDatagridFilters los campos por los que podemos filtrar las entidades en el listado.

configureListFields los campos que se mostrarán en los listados. Emplearemos el método addIdentifier de listMapper para seleccionar qué campo emplearemos como identificador de la fila.

A continuación, crearemos el servicio asociado a esta clase (en el siguiente paso os contaré un par de atajos).

Para definir estos servicios yo generalmente creo un archivo admin.aml en la ruta config/services/admin.yaml y ahí añado el código pertinente para cada clase admin. En nuestro caso:

services:
  admin.project:
    class: App\Admin\ProjectAdmin
    arguments: [~, App\Entity\Project, ~]
    tags:
      - { name: sonata.admin, manager_type: orm, label: Proyecto, group: GroupName }

Con class definiremos la clase Admin asociada.

Con arguments definiremos los argumentos:

  • El primero define el nombre del servicio asociado, que por defecto va al de clase:
  • El segundo, el path completo de la entidad gestionada
  • El tercero el controlador CRUD asociado

Finalmente, añadiremos las siguientes tags:

  • name para indicar que estamos definiendo un servicio de tipo administrador y que así SonataAdmin pueda engancharlos al panel
  • manager_type , según el ORM que estemos empleando
  • label , el nombre que tendrá este servicio en el panel
  • group , a qué grupo/bloque pertenece este servicio dentro del panel

Hecho esto, añadiremos al archivo config/services.yml la línea que importará nuestro archivo admin.yaml :

imports:
  - { resource: "admin.yaml" }

Y si accedemos a /admin ya podremos ver nuestro panel con el nuevo administrador añadido.

Paso 5. Automatizando la creación de clases Admin

Si bien el proceso no es muy largo, en el momento en que tengamos muchas clases se puede hacer demasiado repetitivo. Es aquí donde entra al rescate el nuevo bundle symfony/maker-bundle :

composer require symfony/maker-bundle --dev

El cual se integra con SonataAdmin perfectamente y nos permitirá realizar todo el proceso anterior por línea de comandos mediante el comando:

make:sonata:admin

Lo cual nos permitirá crear los administradores mucho más rápido.

Además, también existe la posibilidad de ahorrarnos la generación del archivo admin.yaml mediante el bundle SonataAutoConfigure (el cual necesita de la funcionalidad autoconfigure incorporada a las últimas versiones de Symfony):

composer require kunicmarko/sonata-auto-configure-bundle

Su configuración básica es la siguiente:

# config/packages/sonata_auto_configure.yaml
sonata_auto_configure:
admin:
suffix: Admin
manager_type: orm
entity:
namespaces:
- { namespace: App\Entity, manager_type: orm }
controller:
suffix: Controller
namespaces:
- App\Controller\Admin

El cual básicamente lo que hace es buscar las entidades alojadas en App\Entity , añadirles el sufijo Admin y así configurar su correspondiente administrador con el manager_type definido.

Y con esto ya tendríamos un primer panel de administración configurado. En próximos artículos ahondaré algo más en la forma en que se pueden configurar los templates y la creación de acciones, bloques y controladores personalizados.