Cómo domar SonataAdminBundle

Preview:

Citation preview

Trabajo en Limenius

Hacemos proyectos a medida en Symfony y React

Raro es el proyecto que no requiera un panel de administración

Desde hace bastante resolvemos esa parte con SonataAdminBundle

Victoria Quirante@vicqr

victoria@limenius.com

I. Introducción

O acerca de por qué y para qué estamos aquí

El creador

Principales colaboradores

Principales problemas históricamente atribuidos

- Difícil de instalar

Principales problemas históricamente atribuidos

- Difícil de instalar- Feo

Principales problemas históricamente atribuidos

- Difícil de instalar- Feo- Mala documentación

Principales problemas históricamente atribuidos

- Difícil de instalar- Feo- Mala documentación- Mucho código, difícil de investigar

Principales problemas históricamente atribuidos

- Difícil de instalar- Feo- Mala documentación- Mucho código, difícil de investigar

Principales problemas históricamente atribuidos

- Difícil de instalar- Feo- Mala documentación- Mucho código, difícil de investigar

Principales problemas históricamente atribuidos

- Difícil de instalar- Feo- Mala documentación regular- Mucho código, difícil de investigar

Principales problemas históricamente atribuidos

- Difícil de instalar- Feo- Mala documentación regular- Mucho código, difícil de investigar

El problema que queremos resolver...

...es implementar un panel de administración

Lo que es y lo que no es Sonata

No es el David de Miguel Ángel

Ni la teoría de cuerdas

Ni el número áureo

Lo que es y lo que no es Sonata

No es el David de Miguel Ángel

Ni la teoría de cuerdas

Ni el número áureo

Pero sí es algo muy útil

Lo que es y lo que no es Sonata

No es el David de Miguel Ángel

Ni la teoría de cuerdas

Ni el número áureo

Pero sí es algo muy útilComo Symfony, como PHP

Charla práctica

- No es una revisión exhaustiva de la documentación- Vamos a mostrar cómo se usa en la práctica- Cuál es el recorrido desde la instalación limpia

Charla práctica

- No es una revisión exhaustiva de la documentación- Vamos a mostrar cómo se usa en la práctica- Cuál es el recorrido desde la instalación limpia

1) Qué te da Sonata “gratis”2) Cómo personalizo lo que quiera a partir de ahí

Dos tipos de desarrolladores

Charla práctica

https://github.com/VictoriaQ/sonatademo

II. El Admin básico

O cómo sacar provecho del sudor de otros de forma que llega a dar hasta un poco de vergüenza

Screenshots (II): Instalación limpia

Screenshots (II): Instalación limpia

Screenshots (II): Instalación limpia

¿Cómo empezamos?

El Admin básico: 3 pasos, 2 minutos

Tenemos la entidad Regalo para la que queremos crear un Admin

El Admin básico: 3 pasos, 2 minutos

Tenemos la entidad Regalo para la que queremos crear un Admin:

1) Creamos la clase RegaloAdmin2) Registramos el servicio

El Admin básico - Paso 1: Creamos la clase Admin

# src/AppBundle/Admin/RegaloAdmin.php

class RegaloAdmin extends Admin

{

protected function configureFormFields(FormMapper $formMapper)

{

$formMapper->add('nombre');

}

protected function configureDatagridFilters(DatagridMapper

$datagridMapper)

{

$datagridMapper->add('nombre');

}

protected function configureListFields(ListMapper $listMapper)

{

$listMapper->addIdentifier('nombre');

}

}

El Admin básico - Paso 1: Creamos la clase Admin

# src/AppBundle/Admin/RegaloAdmin.php

class RegaloAdmin extends Admin

{

protected function configureFormFields(FormMapper $formMapper)

{

$formMapper->add('nombre');

}

protected function configureDatagridFilters(DatagridMapper

$datagridMapper)

{

$datagridMapper->add('nombre');

}

protected function configureListFields(ListMapper $listMapper)

{

$listMapper->addIdentifier('nombre');

}

}

El Admin básico - Paso 1: Creamos la clase Admin

# src/AppBundle/Admin/RegaloAdmin.php

class RegaloAdmin extends Admin

{

protected function configureFormFields(FormMapper $formMapper)

{

$formMapper->add('nombre');

}

protected function configureDatagridFilters(DatagridMapper

$datagridMapper)

{

$datagridMapper->add('nombre');

}

protected function configureListFields(ListMapper $listMapper)

{

$listMapper->addIdentifier('nombre');

}

}

El Admin básico - Paso 1: Creamos la clase Admin

# src/AppBundle/Admin/RegaloAdmin.php

class RegaloAdmin extends Admin

{

protected function configureFormFields(FormMapper $formMapper)

{

$formMapper->add('nombre');

}

protected function configureDatagridFilters(DatagridMapper

$datagridMapper)

{

$datagridMapper->add('nombre');

}

protected function configureListFields(ListMapper $listMapper)

{

$listMapper->addIdentifier('nombre');

}

}

El Admin básico - Paso 1: Creamos la clase Admin

# src/AppBundle/Admin/RegaloAdmin.php

class RegaloAdmin extends Admin

{

protected function configureFormFields(FormMapper $formMapper)

{

$formMapper->add('nombre');

}

protected function configureDatagridFilters(DatagridMapper

$datagridMapper)

{

$datagridMapper->add('nombre');

}

protected function configureListFields(ListMapper $listMapper)

{

$listMapper->addIdentifier('nombre');

}

}

El Admin básico - Paso 2: Registramos el servicio

# app/config/services.yml

services: admin.regalo: class: AppBundle\Admin\RegaloAdmin arguments: [~, AppBundle\Entity\Regalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Regalos }

El Admin básico - Paso 2: Registramos el servicio

# app/config/services.yml

services: admin.regalo: class: AppBundle\Admin\RegaloAdmin arguments: [~, AppBundle\Entity\Regalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Regalos }

Screenshots (II): Primer Admin

Screenshots (II): Primer Admin

Screenshots (II): Primer Admin

Screenshots (II): Primer Admin

El Admin básico - Paso 3 (opcional): Menú lateral

# app/config/config.yml

sonata_admin: dashboard: groups: demo.admin.main: label: Admin label_catalogue: AppBundle icon: '<i class="fa fa-database"></i>' items: - admin.regalo

El Admin básico - Paso 3 (opcional): Menú lateral

# app/config/config.yml

sonata_admin: dashboard: groups: demo.admin.main: label: Admin label_catalogue: AppBundle icon: '<i class="fa fa-database"></i>' items: - admin.regalo

El Admin básico - Paso 3 (opcional): Menú lateral

# app/config/config.yml

sonata_admin: dashboard: groups: demo.admin.main: label: Admin label_catalogue: AppBundle icon: '<i class="fa fa-database"></i>' items: - admin.regalo

Screenshots (II): Primer Admin (ítem en menú lateral)

Ok, ¿y con eso que tengo?

¿Y con eso qué tengo?

- Create, edit, delete...

Screenshots (II): Primer Admin - El formulario

Lo que Sonata te da hecho

- Create, edit, delete...- Listado paginado, ordenable, filtrable

y exportable

Lo que Sonata te da hecho

- Create, edit, delete...

- Listado paginado, ordenable, filtrable y exportable

Screenshots (II): Primer Admin - El listado

Screenshots (II): Primer Admin - El listado

Screenshots (II): Primer Admin - Los filtros

Configuración básica del listado

Configuración básica del listado

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureListFields(ListMapper $listMapper) { $listMapper ->add('nombre')

; }

Configuración básica del listado

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureListFields(ListMapper $listMapper) { $listMapper ->add('nombre') ->add('precio') ->add('descripcion') ->add('destinatario') ->add('comprador') ; }

Configuración básica del listado

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureListFields(ListMapper $listMapper) { $listMapper ->addIdentifier('nombre') ->add('precio') ->add('descripcion') ->add('destinatario') ->add('comprador') ; }

Configuración básica del listado

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureListFields(ListMapper $listMapper) { $listMapper ->addIdentifier('nombre') ->add('precio', 'currency', array('currency' => 'EUR')) ->add('descripcion') ->add('destinatario') ->add('comprador') ; }

Configuración básica del listado

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureListFields(ListMapper $listMapper) { $listMapper ->addIdentifier('nombre') ->add('precio', 'currency', array('currency' => 'EUR')) ->add('descripcion', null, array('label' => 'Descripción')) ->add('destinatario') ->add('comprador') ; }

Configuración básica del listado

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureListFields(ListMapper $listMapper) { $listMapper ->addIdentifier('nombre') ->add('precio', 'currency', array('currency' => 'EUR')) ->add('descripcion', null, array('label' => 'Descripción')) ->add('destinatario', null, array('editable' => true) ->add('comprador') ; }

Configuración básica del listado

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureListFields(ListMapper $listMapper) { $listMapper ->addIdentifier('nombre') ->add('precio', 'currency', array('currency' => 'EUR')) ->add('descripcion', null, array('label' => 'Descripción')) ->add('destinatario', null, array('editable' => true)) ->add('comprador') ; }

https://sonata-project.org/bundles/admin/3-x/doc/reference/field_types.html

Screenshots (II): Primer Admin - El listado

Screenshots (II): Primer Admin - El listado

Screenshots (II): Primer Admin - El listado

Screenshots (II): Primer Admin - El listado

Configuración básica del listado

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureListFields(ListMapper $listMapper) { $listMapper

... ->add('_action', null, array( 'actions' => array( 'show' => array(), 'edit' => array(), 'delete' => array(), ) )) ; }

Configuración básica del listado

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureListFields(ListMapper $listMapper) { $listMapper

... ->add('_action', null, array( 'actions' => array( 'show' => array(), 'edit' => array(), 'delete' => array(), ) )) ; }

Screenshots (II): Primer Admin - El listado

Screenshots (II): Primer Admin - El listado

Configuración básica del formulario

Configuración básica del formulario

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper ->add('nombre') ; }

Configuración básica del formulario

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper ->add('nombre') ->add('precio') ->add('descripcion') ->add('destinatario') ->add('comprador') ; }

Screenshots (II): Primer Admin - El formulario

Configuración básica del formulario

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper ->add('nombre') ->add('precio') ->add('descripcion') ->add('destinatario') ->add('comprador') ; }

Configuración básica del formulario

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper ->with('Regalo', array('class' => 'col-md-6')) ->add('nombre') ->add('precio') ->add('descripcion') ->end() ->with('Participantes', array('class' => 'col-md-6')) ->add('destinatario') ->add('comprador') ->end() ; }

Configuración básica del formulario

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper ->with('Regalo', array('class' => 'col-md-6')) ->add('nombre') ->add('precio') ->add('descripcion') ->end() ->with('Participantes', array('class' => 'col-md-6')) ->add('destinatario') ->add('comprador') ->end() ; }

Screenshots (II): Primer Admin - El formulario

Configuración básica del formulario

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper ->tab('Tab 1') ->with('Regalo', array('class' => 'col-md-6')) ->add('nombre') ->add('precio') ->add('descripcion') ->end() ->with('Participantes', array('class' => 'col-md-6')) ->add('destinatario') ->add('comprador') ->end() ->end() ->tab('Tab 2') ->end() ; }

Screenshots (II): Primer Admin - El formulario

¿Y si alguno de los campos tiene una relación con otra entidad?

Screenshots (II): Primer Admin - El formulario

Configuración básica del formulario

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper

... ->with('Participantes', array('class' => 'col-md-6')) ->add('destinatario') ->add('comprador') ->end() ; }

Configuración básica del formulario

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper

... ->with('Participantes', array('class' => 'col-md-6')) ->add('destinatario', null) ->add('comprador', null) ->end() ; }

Configuración básica del formulario

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper

... ->with('Participantes', array('class' => 'col-md-6')) ->add('destinatario', 'entity', array( 'class' => 'AppBundle\Entity\Destinatario')) ->add('comprador', 'entity', array( 'class' => 'AppBundle\Entity\Comprador')) ->end() ; }

Configuración básica del formulario

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper

... ->with('Participantes', array('class' => 'col-md-6')) ->add('destinatario', null, array( 'class' => 'AppBundle\Entity\Destinatario', 'choice_label' => 'apellidos')) ->add('comprador', null, array( 'class' => 'AppBundle\Entity\Comprador', 'choice_label' => 'apellidos')) ->end() ; }

Configuración básica del formulario

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper

... ->with('Participantes', array('class' => 'col-md-6')) ->add('destinatario', null, array( 'class' => 'AppBundle\Entity\Destinatario', 'choice_label' => 'nombreCompleto')) ->add('comprador', null, array( 'class' => 'AppBundle\Entity\Comprador', 'choice_label' => 'nombreCompleto')) ->end() ; }

Screenshots (II): Primer Admin - El formulario

¿Y los one-to-many y many-to-many?

Una collection en el form (one-to-many)

# src/AppBundle/Admin/CompradorAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper ->with('Datos personales', array('class' => 'col-md-6')) ->add('nombre') ->add('apellidos') ->end()

; }

Una collection en el form (one-to-many)

# src/AppBundle/Admin/CompradorAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper ->with('Datos personales', array('class' => 'col-md-6')) ->add('nombre') ->add('apellidos') ->end() ->with('Pagos', array('class' => 'col-md-6')) ->add('pagos', 'sonata_type_collection', array( ), array( 'edit' => 'inline', 'inline' => 'table', )) ->end() ; }

Una collection en el form (one-to-many)

# src/AppBundle/Admin/CompradorAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper ->with('Datos personales', array('class' => 'col-md-6')) ->add('nombre') ->add('apellidos') ->end() ->with('Pagos', array('class' => 'col-md-6')) ->add('pagos', 'sonata_type_collection', array( ), array( 'edit' => 'inline', 'inline' => 'table', )) ->end() ; }

Una collection en el form (one-to-many)

# src/AppBundle/Admin/CompradorAdmin.php

protected function configureFormFields(FormMapper $formMapper) { $formMapper ->with('Datos personales', array('class' => 'col-md-6')) ->add('nombre') ->add('apellidos') ->end() ->with('Pagos', array('class' => 'col-md-6')) ->add('pagos', 'sonata_type_collection', array( ), array( 'edit' => 'inline', 'inline' => 'table', )) ->end() ; }

Y creamos un Admin para la entidad Pago

Una collection en el form (one-to-many)

Una collection en el form (one-to-many)

Una collection en el form (one-to-many)

Una many-to-many en el form

Una many-to-many en el form

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureFormFields(FormMapper $formMapper)

{

$formMapper

...

->with('Establecimientos', array('class' => 'col-md-6'))

->add('tiendas', 'sonata_type_model', array(

'by_reference' => false,

'expanded' => true,

'multiple' => true,

'label' => 'Tiendas')

)

->end()

;

}

Una many-to-many en el form

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureFormFields(FormMapper $formMapper)

{

$formMapper

...

->with('Establecimientos', array('class' => 'col-md-6'))

->add('tiendas', 'sonata_type_model', array(

'by_reference' => false,

'expanded' => true,

'multiple' => true,

'label' => 'Tiendas')

)

->end()

;

}

Una many-to-many en el form

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureFormFields(FormMapper $formMapper)

{

$formMapper

...

->with('Establecimientos', array('class' => 'col-md-6'))

->add('tiendas', 'sonata_type_model', array(

'by_reference' => false,

'expanded' => true,

'multiple' => true,

'label' => 'Tiendas')

)

->end()

;

}

Una many-to-many en el form

Una many-to-many en el form

Una many-to-many en el form

Configuración básica de los filtros

Configuración básica de los filtros

# src/AppBundle/Admin/RegaloAdmin.php

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

Configuración básica de los filtros

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper ->add('nombre') ->add('precio') ->add('destinatario', null, array(), 'entity', array( 'class' => 'AppBundle\Entity\Destinatario', 'choice_label' => 'nombreCompleto')) ; }

Screenshots (II): Primer Admin - Los filtros

Hasta aquí lo “gratis”

¿Tenemos mucho o poco?

- Con muy poco esfuerzo tienes muchísimo

- De hecho tienes la mayor parte de lo que necesitas

- Pero el mundo no es perfecto, y vas a necesitar algunas otras cosas en tu panel casi con seguridad

¿Y si quiero...

… tener un formulario maquetado de otra forma?… meter algo “extraño” en un campo del listado?… crear una sección del menú que no sea un listado?… meter algo dentro de Sonata que no tenga nada que ver con el panel de administración…?

¿Y si quiero...

… tener un formulario maquetado de otra forma?… meter algo “extraño” en un campo del listado?… crear una sección del menú que no sea un listado?… meter algo dentro de Sonata que no tenga nada que ver con el panel de administración…?

¿Cuánto me va a costar todo eso? ¿No será mejor empezar de cero?

III. Personalizando

O cómo campar a mis anchas paso a paso

Personalizando

● Templates

● Queries

● Actions

Sobrescribiendo templates

Sobrescribir templates

# app/config/config.yml

sonata_admin: templates: user_block: 'SonataAdminBundle:Core:user_block.html.twig' add_block: 'SonataAdminBundle:Core:add_block.html.twig' layout: 'SonataAdminBundle::standard_layout.html.twig' ajax: 'SonataAdminBundle::ajax_layout.html.twig' dashboard: 'SonataAdminBundle:Core:dashboard.html.twig' search: 'SonataAdminBundle:Core:search.html.twig' list: 'SonataAdminBundle:CRUD:list.html.twig' show: 'SonataAdminBundle:CRUD:show.html.twig' show_compare: 'SonataAdminBundle:CRUD:show_compare.html.twig' edit: 'SonataAdminBundle:CRUD:edit.html.twig'

...

Sobrescribir templates

# app/config/config.yml

sonata_admin: templates: user_block: 'SonataAdminBundle:Core:user_block.html.twig' add_block: 'SonataAdminBundle:Core:add_block.html.twig' layout: 'SonataAdminBundle::standard_layout.html.twig' ajax: 'SonataAdminBundle::ajax_layout.html.twig' dashboard: 'SonataAdminBundle:Core:dashboard.html.twig' search: 'SonataAdminBundle:Core:search.html.twig' list: 'SonataAdminBundle:CRUD:list.html.twig' show: 'SonataAdminBundle:CRUD:show.html.twig' show_compare: 'SonataAdminBundle:CRUD:show_compare.html.twig' edit: 'SonataAdminBundle:CRUD:edit.html.twig'

...

https://sonata-project.org/bundles/admin/3-x/doc/reference/templates.html

Sobrescribir templates

# app/config/config.yml

sonata_admin: templates: user_block: 'SonataAdminBundle:Core:user_block.html.twig' add_block: 'SonataAdminBundle:Core:add_block.html.twig' layout: 'SonataAdminBundle::standard_layout.html.twig' ajax: 'SonataAdminBundle::ajax_layout.html.twig' dashboard: 'SonataAdminBundle:Core:dashboard.html.twig' search: 'SonataAdminBundle:Core:search.html.twig' list: 'SonataAdminBundle:CRUD:list.html.twig' show: 'SonataAdminBundle:CRUD:show.html.twig' show_compare: 'SonataAdminBundle:CRUD:show_compare.html.twig' edit: 'SonataAdminBundle:CRUD:edit.html.twig'

...

Sobrescribir templates

# app/config/config.yml

sonata_admin: templates: user_block: 'SonataAdminBundle:Core:user_block.html.twig' add_block: 'SonataAdminBundle:Core:add_block.html.twig' layout: 'SonataAdminBundle::standard_layout.html.twig' ajax: 'SonataAdminBundle::ajax_layout.html.twig' dashboard: 'SonataAdminBundle:Core:dashboard.html.twig' search: 'SonataAdminBundle:Core:search.html.twig' list: 'SonataAdminBundle:CRUD:list.html.twig' show: 'SonataAdminBundle:CRUD:show.html.twig' show_compare: 'SonataAdminBundle:CRUD:show_compare.html.twig' edit: 'AppBundle:Admin:edit.html.twig'

...

Sobrescribir templates

# app/config/config.yml

sonata_admin: templates: user_block: 'SonataAdminBundle:Core:user_block.html.twig' add_block: 'SonataAdminBundle:Core:add_block.html.twig' layout: 'SonataAdminBundle::standard_layout.html.twig' ajax: 'SonataAdminBundle::ajax_layout.html.twig' dashboard: 'SonataAdminBundle:Core:dashboard.html.twig' search: 'SonataAdminBundle:Core:search.html.twig' list: 'SonataAdminBundle:CRUD:list.html.twig' show: 'SonataAdminBundle:CRUD:show.html.twig' show_compare: 'SonataAdminBundle:CRUD:show_compare.html.twig' edit: 'AppBundle:Admin:edit.html.twig'

...

Fundamental buscar la template original y ver qué queremos sobrescribir exactamente

Sobrescribir templates

# vendor/sonata-project/admin-bundle/Resources/views/CRUD/edit.html.twig

{% extends 'SonataAdminBundle:CRUD:base_edit.html.twig' %}

Sobrescribir templates

# vendor/sonata-project/admin-bundle/Resources/views/CRUD/edit.html.twig

{% extends 'SonataAdminBundle:CRUD:base_edit.html.twig' %}

# vendor/sonata-project/admin-bundle/Resources/views/CRUD/base_edit.html.twig

{% block formactions %}...{% block formactions %}

Screenshots (III): Sobrescribir templates

Screenshots (III): Sobrescribir templates

¿Y si solo quiero sobrescribir la template de un Admin concreto?

Sobrescribir templates

# app/config/services.yml

services: admin.regalo: class: AppBundle\Admin\RegaloAdmin arguments: [~, AppBundle\Entity\Regalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Regalos }

Sobrescribir templates

# app/config/services.yml

services: admin.regalo: class: AppBundle\Admin\RegaloAdmin arguments: [~, AppBundle\Entity\Regalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Regalos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]]

Screenshots (III): Sobrescribir templates

¿Cómo sobrescribo la template de un campo concreto del listado?

Sobrescribir la template de un field en el list

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureListFields(ListMapper $listMapper) { $listMapper

...

; }

Sobrescribir la template de un field en el list (paso 1)

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureListFields(ListMapper $listMapper) { $listMapper

...

->add('miField', 'string', array('template' => ':Admin:field_envio_email.html.twig'))

; }

Sobrescribir la template de un field en el list (paso 1)

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureListFields(ListMapper $listMapper) { $listMapper

...

->add('miField', 'string', array('template' => ':Admin:field_envio_email.html.twig'))

; }

Sobrescribir la template de un field en el list (paso 2)

# app/Resources/views/Admin/field_envio_email.html.twig

{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}

{% block field %}<a class="btn btn-primary btn-sm" href="">

<i class="fa fa-envelope"></i> Enviar</a>{% endblock %}

Screenshots (III): Sobrescribir la template de un field en el list

Modificando las queries

Screenshots (III): Modificar la query del list

Modificar la query del list

# src/AppBundle/Admin/RegaloAdmin.php

public function createQuery($context = 'list') { $query = parent::createQuery($context); $rootAlias = $query->getRootAliases()[0]; $query ->andWhere( $query->expr()->eq($rootAlias.'.entregado', ':entregado')); $query->setParameter('entregado', false);

return $query; }

Modificar la query del list

# src/AppBundle/Admin/RegaloAdmin.php

public function createQuery($context = 'list') { $query = parent::createQuery($context); $rootAlias = $query->getRootAliases()[0]; $query ->andWhere( $query->expr()->eq($rootAlias.'.entregado', ':entregado')); $query->setParameter('entregado', false);

return $query; }

Screenshots (III): Modificar la query del list

Screenshots (III): Modificar la query de un filtro

Screenshots (III): Modificar la query de un filtro

Screenshots (III): Modificar la query de un filtro

Modificar la query de un filtro

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper ->add('miFiltro', 'doctrine_orm_callback',array( 'callback' => function($queryBuilder, $alias, $field, $value) { if (!$value['value']) { return; }

$queryBuilder->andWhere($alias.'.estado != :estado'); $queryBuilder->setParameter('estado', 'entregado');

return true; }, 'field_type' => 'checkbox', 'label' => 'No entregados' )) ; }

Modificar la query de un filtro

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper ->add('miFiltro', 'doctrine_orm_callback',array( 'callback' => function($queryBuilder, $alias, $field, $value) { if (!$value['value']) { return; }

$queryBuilder->andWhere($alias.'.estado != :estado'); $queryBuilder->setParameter('estado', 'entregado');

return true; }, 'field_type' => 'checkbox', 'label' => 'No entregados' )) ; }

Modificar la query de un filtro

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper ->add('miFiltro', 'doctrine_orm_callback',array( 'callback' => function($queryBuilder, $alias, $field, $value) { if (!$value['value']) { return; }

$queryBuilder->andWhere($alias.'.estado != :estado'); $queryBuilder->setParameter('estado', 'entregado');

return true; }, 'field_type' => 'checkbox', 'label' => 'No entregados' )) ; }

Modificar la query de un filtro

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper ->add('miFiltro', 'doctrine_orm_callback',array( 'callback' => function($queryBuilder, $alias, $field, $value) { if (!$value['value']) { return; }

$queryBuilder->andWhere($alias.'.estado != :estado'); $queryBuilder->setParameter('estado', 'entregado');

return true; }, 'field_type' => 'checkbox', 'label' => 'No entregados' )) ; }

Screenshots (III): Modificar la query de un filtro

Screenshots (III): Modificar la query de un filtro

Escribiendo en el controlador

Screenshots (III): Crear un action custom

Crear un action custom (paso 1)

# src/AppBundle/Controller/RegaloAdminController.php

use Sonata\AdminBundle\Controller\CRUDController as Controller;use Symfony\Component\HttpFoundation\RedirectResponse;

class RegaloAdminController extends Controller{ public function sendEmailAction() { $regalo = $this->admin->getSubject(); $email = $regalo->getDestinatario()->getEmail();

// Here code to send email

$this->addFlash('sonata_flash_success', 'Email enviado a '.$email);

return new RedirectResponse($this->admin->generateUrl('list')); }}

Crear un action custom (paso 1)

# src/AppBundle/Controller/RegaloAdminController.php

use Sonata\AdminBundle\Controller\CRUDController as Controller;use Symfony\Component\HttpFoundation\RedirectResponse;

class RegaloAdminController extends Controller{ public function sendEmailAction() { $regalo = $this->admin->getSubject(); $email = $regalo->getDestinatario()->getEmail();

// Here code to send email

$this->addFlash('sonata_flash_success', 'Email enviado a '.$email);

return new RedirectResponse($this->admin->generateUrl('list')); }}

Crear un action custom (paso 1)

# src/AppBundle/Controller/RegaloAdminController.php

use Sonata\AdminBundle\Controller\CRUDController as Controller;use Symfony\Component\HttpFoundation\RedirectResponse;

class RegaloAdminController extends Controller{ public function sendEmailAction() { $regalo = $this->admin->getSubject(); $email = $regalo->getDestinatario()->getEmail();

// Here code to send email

$this->addFlash('sonata_flash_success', 'Email enviado a '.$email);

return new RedirectResponse($this->admin->generateUrl('list')); }}

Crear un action custom (paso 2)

# app/config/services.yml

services: admin.regalo: class: AppBundle\Admin\RegaloAdmin arguments: [~, AppBundle\Entity\Regalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Regalos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]]

Crear un action custom (paso 2)

# app/config/services.yml

services: admin.regalo: class: AppBundle\Admin\RegaloAdmin arguments: [~, AppBundle\Entity\Regalo, AppBundle\RegaloAdmin] tags: - { name: sonata.admin, manager_type: orm, label: Regalos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]]

Crear un action custom (paso 3)

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureRoutes(RouteCollection $collection) { $collection->add('sendEmail', $this->getRouterIdParameter().'/send-email'); }

Crear un action custom (paso 3)

# src/AppBundle/Admin/RegaloAdmin.php

protected function configureRoutes(RouteCollection $collection) { $collection->add('sendEmail', $this->getRouterIdParameter().'/send-email'); }

Crear un action custom

# app/Resources/views/Admin/field_envio_email.html.twig

{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}

{% block field %}<a class="btn btn-primary btn-sm" href="">

<i class="fa fa-envelope"></i> Enviar</a>{% endblock %}

Crear un action custom

# app/Resources/views/Admin/field_envio_email.html.twig

{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}

{% block field %}<a class="btn btn-primary btn-sm" href="{{

admin.generateObjectUrl('sendEmail', object) }}"> <i class="fa fa-envelope"></i> Enviar

</a>{% endblock %}

Screenshots (III): Crear un action custom

Screenshots (III): Crear una batch action custom

Crear un batch action custom (paso 1)

# src/AppBundle/Controller/RegaloAdminController.php

public function batchActionSendEmail($selectedModelQuery) {

// Here code to send emails

return new RedirectResponse($this->admin->generateUrl('list')); }

Crear un batch action custom (paso 1)

# src/AppBundle/Controller/RegaloAdminController.php

public function batchActionSendEmail($selectedModelQuery) {

// Here code to send emails

return new RedirectResponse($this->admin->generateUrl('list')); }

Crear un batch action custom (paso 2)

# src/AppBundle/Admin/RegaloAdmin.php

public function getBatchActions() { $actions = parent::getBatchActions();

if ($this->hasRoute('edit') && $this->isGranted('EDIT')) { $actions['send_email'] = [ 'label' => 'Enviar email', 'ask_confirmation' => false, ]; }

return $actions; }

Crear un batch action custom (paso 2)

# src/AppBundle/Admin/RegaloAdmin.php

public function getBatchActions() { $actions = parent::getBatchActions();

if ($this->hasRoute('edit') && $this->isGranted('EDIT')) { $actions['send_email'] = [ 'label' => 'Enviar email', 'ask_confirmation' => false, ]; }

return $actions; }

Screenshots (III): Crear una batch action custom

IV. Consejos prácticos

O conjunto de ideas varias que pueden venir bien en cualquier proyecto

¿Cómo toco el aspecto general del panel?

Aspecto general

Aspecto general

Aspecto general

# app/config/config.yml

sonata_admin: title: deSymfony

Aspecto general

# app/config/config.yml

sonata_admin: title: deSymfony title_logo: 'img/logo.png'

Aspecto general

# app/config/config.yml

sonata_admin: title: deSymfony title_logo: 'img/logo.png' assets: stylesheets: - bundles/sonatacore/vendor/bootstrap/dist/css/bootstrap.min.css - bundles/sonatacore/vendor/ionicons/css/ionicons.min.css - bundles/sonataadmin/vendor/admin-lte/dist/css/AdminLTE.min.css - bundles/sonataadmin/vendor/admin-lte/dist/css/skins/skin-black.min.css - bundles/sonataadmin/vendor/iCheck/skins/square/blue.css - bundles/sonataadmin/vendor/jqueryui/themes/base/jquery-ui.css - bundles/sonatacore/vendor/select2/select2.css - bundles/sonataadmin/css/styles.css - bundles/sonataadmin/css/layout.css - bundles/sonataadmin/css/tree.css - bundles/sonataadmin/css/colors.css

Aspecto general

# app/config/config.yml

sonata_admin: title: deSymfony title_logo: 'img/logo.png' assets: stylesheets: - bundles/sonatacore/vendor/bootstrap/dist/css/bootstrap.min.css - bundles/sonatacore/vendor/ionicons/css/ionicons.min.css - bundles/sonataadmin/vendor/admin-lte/dist/css/AdminLTE.min.css - bundles/sonataadmin/vendor/admin-lte/dist/css/skins/skin-black.min.css - bundles/sonataadmin/vendor/iCheck/skins/square/blue.css - bundles/sonataadmin/vendor/jqueryui/themes/base/jquery-ui.css - bundles/sonatacore/vendor/select2/select2.css - bundles/sonataadmin/css/styles.css - bundles/sonataadmin/css/layout.css - bundles/sonataadmin/css/tree.css - bundles/sonataadmin/css/colors.css

https://sonata-project.org/bundles/admin/master/doc/reference/configuration.html

Aspecto general

# app/config/config.yml

sonata_admin: title: deSymfony title_logo: 'img/logo.png' assets: stylesheets: - bundles/sonatacore/vendor/bootstrap/dist/css/bootstrap.min.css - bundles/sonatacore/vendor/ionicons/css/ionicons.min.css - bundles/sonataadmin/vendor/admin-lte/dist/css/AdminLTE.min.css - bundles/sonataadmin/vendor/admin-lte/dist/css/skins/skin-black.min.css - bundles/sonataadmin/vendor/iCheck/skins/square/blue.css - bundles/sonataadmin/vendor/jqueryui/themes/base/jquery-ui.css - bundles/sonatacore/vendor/select2/select2.css - bundles/sonataadmin/css/styles.css - bundles/sonataadmin/css/layout.css - bundles/sonataadmin/css/tree.css - bundles/sonataadmin/css/colors.css - css/styles.css

Aspecto general

Aspecto general

# app/config/config.yml

sonata_admin: title: deSymfony title_logo: 'img/logo.png' assets: stylesheets: - bundles/sonatacore/vendor/bootstrap/dist/css/bootstrap.min.css - bundles/sonatacore/vendor/ionicons/css/ionicons.min.css - bundles/sonataadmin/vendor/admin-lte/dist/css/AdminLTE.min.css - bundles/sonataadmin/vendor/admin-lte/dist/css/skins/skin-black.min.css - bundles/sonataadmin/vendor/iCheck/skins/square/blue.css - bundles/sonataadmin/vendor/jqueryui/themes/base/jquery-ui.css - bundles/sonatacore/vendor/select2/select2.css - bundles/sonataadmin/css/styles.css - bundles/sonataadmin/css/layout.css - bundles/sonataadmin/css/tree.css - bundles/sonataadmin/css/colors.css - css/styles.css

Aspecto general

# app/config/config.yml

sonata_admin: title: deSymfony title_logo: 'img/logo.png' assets: stylesheets: - bundles/sonatacore/vendor/bootstrap/dist/css/bootstrap.min.css - bundles/sonatacore/vendor/ionicons/css/ionicons.min.css - bundles/sonataadmin/vendor/admin-lte/dist/css/AdminLTE.min.css - bundles/sonataadmin/vendor/admin-lte/dist/css/skins/skin-black.min.css - bundles/sonataadmin/vendor/iCheck/skins/square/blue.css - bundles/sonataadmin/vendor/jqueryui/themes/base/jquery-ui.css - bundles/sonatacore/vendor/select2/select2.css - bundles/sonataadmin/css/styles.css - bundles/sonataadmin/css/layout.css - bundles/sonataadmin/css/tree.css - bundles/sonataadmin/css/colors.css - css/styles.css

Aspecto general

# app/config/config.yml

sonata_admin: title: deSymfony title_logo: 'img/logo.png' assets: stylesheets: - bundles/sonatacore/vendor/bootstrap/dist/css/bootstrap.min.css - bundles/sonatacore/vendor/ionicons/css/ionicons.min.css - bundles/sonataadmin/vendor/admin-lte/dist/css/AdminLTE.min.css - bundles/sonataadmin/vendor/admin-lte/dist/css/skins/skin-black.min.css

https://almsaeedstudio.com/

Sonata utiliza AdminLTE, para lo visual generalmente hay que indagar allí

Aspecto general - Layout

Aspecto general - Layout

Aspecto general - Layout

Aspecto general - Layout

# app/config/config.yml

sonata_admin: templates: user_block: 'SonataAdminBundle:Core:user_block.html.twig' add_block: 'SonataAdminBundle:Core:add_block.html.twig' layout: 'SonataAdminBundle::standard_layout.html.twig' ajax: 'SonataAdminBundle::ajax_layout.html.twig' dashboard: 'SonataAdminBundle:Core:dashboard.html.twig' search: 'SonataAdminBundle:Core:search.html.twig' list: 'SonataAdminBundle:CRUD:list.html.twig' show: 'SonataAdminBundle:CRUD:show.html.twig' show_compare: 'SonataAdminBundle:CRUD:show_compare.html.twig' edit: 'SonataAdminBundle:CRUD:edit.html.twig'

...

Aspecto general - Layout

# app/config/config.yml

sonata_admin: templates: user_block: 'SonataAdminBundle:Core:user_block.html.twig' add_block: 'SonataAdminBundle:Core:add_block.html.twig' layout: 'SonataAdminBundle::standard_layout.html.twig' ajax: 'SonataAdminBundle::ajax_layout.html.twig' dashboard: 'SonataAdminBundle:Core:dashboard.html.twig' search: 'SonataAdminBundle:Core:search.html.twig' list: 'SonataAdminBundle:CRUD:list.html.twig' show: 'SonataAdminBundle:CRUD:show.html.twig' show_compare: 'SonataAdminBundle:CRUD:show_compare.html.twig' edit: 'SonataAdminBundle:CRUD:edit.html.twig'

...

Aspecto general - Layout

# app/config/config.yml

sonata_admin: templates: user_block: 'SonataAdminBundle:Core:user_block.html.twig' add_block: 'SonataAdminBundle:Core:add_block.html.twig' layout: ':Admin:layout.html.twig' ajax: 'SonataAdminBundle::ajax_layout.html.twig' dashboard: 'SonataAdminBundle:Core:dashboard.html.twig' search: 'SonataAdminBundle:Core:search.html.twig' list: 'SonataAdminBundle:CRUD:list.html.twig' show: 'SonataAdminBundle:CRUD:show.html.twig' show_compare: 'SonataAdminBundle:CRUD:show_compare.html.twig' edit: 'SonataAdminBundle:CRUD:edit.html.twig'

...

Aspecto general - Layout

Aspecto general - Dashboard

Aspecto general - Dashboard

# app/config/config.yml

sonata_admin: templates: user_block: 'SonataAdminBundle:Core:user_block.html.twig' add_block: 'SonataAdminBundle:Core:add_block.html.twig' layout: 'SonataAdminBundle::standard_layout.html.twig' ajax: 'SonataAdminBundle::ajax_layout.html.twig' dashboard: 'SonataAdminBundle:Core:dashboard.html.twig' search: 'SonataAdminBundle:Core:search.html.twig' list: 'SonataAdminBundle:CRUD:list.html.twig' show: 'SonataAdminBundle:CRUD:show.html.twig' show_compare: 'SonataAdminBundle:CRUD:show_compare.html.twig' edit: 'SonataAdminBundle:CRUD:edit.html.twig'

...

Aspecto general - Dashboard

# app/config/config.yml

sonata_admin: templates: user_block: 'SonataAdminBundle:Core:user_block.html.twig' add_block: 'SonataAdminBundle:Core:add_block.html.twig' layout: 'SonataAdminBundle::standard_layout.html.twig' ajax: 'SonataAdminBundle::ajax_layout.html.twig' dashboard: 'SonataAdminBundle:Core:dashboard.html.twig' search: 'SonataAdminBundle:Core:search.html.twig' list: 'SonataAdminBundle:CRUD:list.html.twig' show: 'SonataAdminBundle:CRUD:show.html.twig' show_compare: 'SonataAdminBundle:CRUD:show_compare.html.twig' edit: 'SonataAdminBundle:CRUD:edit.html.twig'

...

Aspecto general - Dashboard

# app/config/config.yml

sonata_admin: templates: user_block: 'SonataAdminBundle:Core:user_block.html.twig' add_block: 'SonataAdminBundle:Core:add_block.html.twig' layout: 'SonataAdminBundle::standard_layout.html.twig' ajax: 'SonataAdminBundle::ajax_layout.html.twig' dashboard: ':Admin:dashboard.html.twig' search: 'SonataAdminBundle:Core:search.html.twig' list: 'SonataAdminBundle:CRUD:list.html.twig' show: 'SonataAdminBundle:CRUD:show.html.twig' show_compare: 'SonataAdminBundle:CRUD:show_compare.html.twig' edit: 'SonataAdminBundle:CRUD:edit.html.twig'

...

Aspecto general - Dashboard

Aspecto general - Dashboard

Aspecto general - Dashboard

¿Puedo hacer dos admins de la misma entidad?

Crear dos admins de la misma entidad

# src/AppBundle/Admin/RegaloPasadoAdmin.php

class RegaloPasadoAdmin extends Admin

{

}

Sin problema. Creamos una nueva clase Admin…

Crear dos admins de la misma entidad

# src/AppBundle/Admin/RegaloPasadoAdmin.php

class RegaloPasadoAdmin extends Admin

{

protected $baseRouteName = 'regalo_pasado'; protected $baseRoutePattern = 'regalo-pasado'

...}

(sin olvidar estas propiedades para que Sonata no se líe con el routing)

Crear dos admins de la misma entidad

# app/config/services.yml

services: admin.regalo: class: AppBundle\Admin\RegaloAdmin arguments: [~, AppBundle\Entity\Regalo, AppBundle:RegaloAdmin] tags: - { name: sonata.admin, manager_type: orm, label: Regalos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]]

… y registramos el nuevo servicio

Crear dos admins de la misma entidad

# app/config/services.yml

services: admin.regalo: class: AppBundle\Admin\RegaloAdmin arguments: [~, AppBundle\Entity\Regalo, AppBundle:RegaloAdmin] tags: - { name: sonata.admin, manager_type: orm, label: Activos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]] admin.regalo_pasado: class: AppBundle\Admin\RegaloPasadoAdmin arguments: [~, AppBundle\Entity\Regalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pasados }

… y registramos el nuevo servicio

Crear dos admins de la misma entidad

Crear dos admins de la misma entidad

Crear dos admins de la misma entidad

Admin como child en el menú de otro Admin

Admin como child en el menú de otro Admin

Admin como child en el menú de otro Admin

Admin como child en el menú de otro Admin

# app/config/services.yml

admin.comprador: class: AppBundle\Admin\CompradorAdmin arguments: [~, AppBundle\Entity\Comprador, ~] tags: - { name: sonata.admin, manager_type: orm, label: Compradores } calls: - [ addChild, [ '@admin.pago' ] ] admin.pago: class: AppBundle\Admin\PagoAdmin arguments: [~, AppBundle\Entity\Pago, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pagos }

Admin como child en el menú de otro Admin

# app/config/services.yml

admin.comprador: class: AppBundle\Admin\CompradorAdmin arguments: [~, AppBundle\Entity\Comprador, ~] tags: - { name: sonata.admin, manager_type: orm, label: Compradores } calls: - [ addChild, [ '@admin.pago' ] ] admin.pago: class: AppBundle\Admin\PagoAdmin arguments: [~, AppBundle\Entity\Pago, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pagos }

Admin como child en el menú de otro Admin

# app/config/services.yml

admin.comprador: class: AppBundle\Admin\CompradorAdmin arguments: [~, AppBundle\Entity\Comprador, ~] tags: - { name: sonata.admin, manager_type: orm, label: Compradores } calls: - [ addChild, [ '@admin.pago' ] ] admin.pago: class: AppBundle\Admin\PagoAdmin arguments: [~, AppBundle\Entity\Pago, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pagos }

Admin como child en el menú de otro Admin

# app/config/config.yml

admin.comprador: class: AppBundle\Admin\CompradorAdmin arguments: [~, AppBundle\Entity\Comprador, ~] tags: - { name: sonata.admin, manager_type: orm, label: Compradores } calls: - [ addChild, [ '@admin.pago' ] ] admin.pago: class: AppBundle\Admin\PagoAdmin arguments: [~, AppBundle\Entity\Pago, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pagos }

Admin como child en el menú de otro Admin

# src/AppBundle/Admin/CompradorAdmin.php

protected function configureSideMenu(ItemInterface $menu, $action, AdminInterface $childAdmin = null) {

... $menu->addChild( 'Pagos', $admin->generateMenuUrl('admin.comprador|admin.pago.list', array('id' => $id)) ); }

Admin como child en el menú de otro Admin

# src/AppBundle/Admin/CompradorAdmin.php

protected function configureSideMenu(ItemInterface $menu, $action, AdminInterface $childAdmin = null) {

... $menu->addChild( 'Pagos', $admin->generateMenuUrl('admin.comprador|admin.pago.list', array('id' => $id)) ); }

Admin como child en el menú de otro Admin

¿Qué pasa si el listado no es lo principal?

Enlazar un action custom desde la sidebar

Creamos nuestro action custom, la template y la ruta...

Enlazar un action custom desde la sidebar

# app/config/config.yml

dashboard: groups:

... demo.admin.settings: label: Configuración label_catalogue: AppBundle icon: '<i class="fa fa-gear"></i>' items: - admin.configuracion

Creamos nuestro action custom, la template y la ruta...

… la enlazamos desde el sidebar

Enlazar un action custom desde la sidebar

# app/config/config.yml

dashboard: groups:

... demo.admin.settings: label: Configuración label_catalogue: AppBundle icon: '<i class="fa fa-gear"></i>' items: - admin.configuracion - route: config_myEdit label: 'Mi configuración'

Creamos nuestro action custom, la template y la ruta...

… la enlazamos desde el sidebar

Enlazar un action custom desde la sidebar

¿Y si quiero meter algo que no sea un Admin?

Toda tu aplicación puede estar dentro de Sonata

Tu aplicación puede tener partes que no sean un Admin

Y sin embargo estén integradas con lo demás

Puedes meter cualquier cosa ahí dentro

Toda tu aplicación puede estar dentro de Sonata

Toda tu aplicación puede estar dentro de Sonata

Toda tu aplicación puede estar dentro de Sonata

Creas tu action en el controlador (PacienteAdminController.php)

Toda tu aplicación puede estar dentro de Sonata

Creas tu action en el controlador (PacienteAdminController.php)

Configuras tu ruta en configureRoutes (PacienteAdmin.php)

$collection->add('editor', $this->getRouterIdParameter().'/editor');

Toda tu aplicación puede estar dentro de Sonata

Creas tu action en el controlador (PacienteAdminController.php)

Configuras tu ruta en configureRoutes (PacienteAdmin.php)

$collection->add('editor', $this->getRouterIdParameter().'/editor');

Haces setTemplate en la declaración del servicio (services.yml)

<call method="setTemplates">

<argument type="collection">

<argument key="editor">:editor:editor.html.twig</argument>

</argument>

</call>

V. Más allá

O qué otras cosas hay ahí fuera y dónde puedo encontrarlas

Documentación de SonataAdminBundle

FOSUserBundle & SonataUserAdminBundle

SonataUserAdminBundle es una capa sobre FOSUserBundle que aporta algunas cosas

(pero no es imprescindible para usar FOSUserBundle)

https://sonata-project.org/bundles/user/3-x/doc/reference/introduction.html

Seguridad, roles

https://sonata-project.org/bundles/admin/3-x/doc/reference/security.html

La seguridad se puede configurar de muchas formas distintas y con tanto detalle como quieras

Eventos

https://sonata-project.org/bundles/admin/3-x/doc/reference/events.html

Hay una serie de eventos definidos por Sonata que pueden resultar muy útiles

● sonata.admin.event.persistence.pre_update

● sonata.admin.event.persistence.post_update

● sonata.admin.event.persistence.pre_persist

● sonata.admin.event.persistence.post_persist

● sonata.admin.event.persistence.pre_remove

● sonata.admin.event.persistence.post_remove

Sonata Project Demo

Sonata Project Demo

Sonata Project Demo

Y a la hora de la verdad.. pues el código

Admin class

Conviene mucho mirarse la Admin class

vendor/sonata-project/admin-bundle/Admin/AbstractAdmin.php

VI. Conclusiones

O con qué me quedo de todo esto

Conclusiones

● Los principales problemas se han ido solucionando. Y sigue mejorando.

Conclusiones

● Los principales problemas se han ido solucionando. Y sigue mejorando.

● Te da MUCHO hecho. Hay que sacar el máximo provecho a esa parte.

Conclusiones

● Los principales problemas se han ido solucionando. Y sigue mejorando.

● Te da MUCHO hecho. Hay que sacar el máximo provecho a esa parte.

● Puedes sobrescribir lo que quieras y meter tu propio código donde quieras.

Conclusiones

Te permite solucionar un problema aburrido de una forma eficiente

Conclusiones

Te permite solucionar un problema aburrido de una forma eficiente

Para que puedas dedicarte a otra cosa más emocionante

Conclusiones

Y desde el punto de vista del negocio suele ser muy buena decisión

Victoria Quirante Ruiz Madrid, 16-17 Sep. 2016#deSymfony

@vicqrvictoria@limenius.com

https://github.com/VictoriaQ/sonatademo

Formación, consultoría y desarrollo de proyectos

Victoria Quirante Ruiz Madrid, 16-17 Sep. 2016#deSymfony

@vicqrvictoria@limenius.com

https://github.com/VictoriaQ/sonatademo

Formación, consultoría y desarrollo de proyectos

Gracias!

Recommended