SlideShare una empresa de Scribd logo
1 de 246
Descargar para leer sin conexión
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 útil
Como 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 RegaloAdmin
2) 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: AppBundleAdminRegaloAdmin
arguments: [~, AppBundleEntityRegalo, ~]
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: AppBundleAdminRegaloAdmin
arguments: [~, AppBundleEntityRegalo, ~]
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' => 'AppBundleEntityDestinatario'))
->add('comprador', 'entity', array(
'class' => 'AppBundleEntityComprador'))
->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' => 'AppBundleEntityDestinatario',
'choice_label' => 'apellidos'))
->add('comprador', null, array(
'class' => 'AppBundleEntityComprador',
'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' => 'AppBundleEntityDestinatario',
'choice_label' => 'nombreCompleto'))
->add('comprador', null, array(
'class' => 'AppBundleEntityComprador',
'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' => 'AppBundleEntityDestinatario',
'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: AppBundleAdminRegaloAdmin
arguments: [~, AppBundleEntityRegalo, ~]
tags:
- { name: sonata.admin, manager_type: orm, label:
Regalos }
Sobrescribir templates
# app/config/services.yml
services:
admin.regalo:
class: AppBundleAdminRegaloAdmin
arguments: [~, AppBundleEntityRegalo, ~]
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 SonataAdminBundleControllerCRUDController as Controller;
use SymfonyComponentHttpFoundationRedirectResponse;
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 SonataAdminBundleControllerCRUDController as Controller;
use SymfonyComponentHttpFoundationRedirectResponse;
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 SonataAdminBundleControllerCRUDController as Controller;
use SymfonyComponentHttpFoundationRedirectResponse;
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: AppBundleAdminRegaloAdmin
arguments: [~, AppBundleEntityRegalo, ~]
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: AppBundleAdminRegaloAdmin
arguments: [~, AppBundleEntityRegalo, AppBundleRegaloAdmin]
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: AppBundleAdminRegaloAdmin
arguments: [~, AppBundleEntityRegalo, 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: AppBundleAdminRegaloAdmin
arguments: [~, AppBundleEntityRegalo, AppBundle:RegaloAdmin]
tags:
- { name: sonata.admin, manager_type: orm, label: Activos }
calls:
- [ setTemplate, [edit, :Admin:edit_regalo.html.twig]]
admin.regalo_pasado:
class: AppBundleAdminRegaloPasadoAdmin
arguments: [~, AppBundleEntityRegalo, ~]
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: AppBundleAdminCompradorAdmin
arguments: [~, AppBundleEntityComprador, ~]
tags:
- { name: sonata.admin, manager_type: orm, label:
Compradores }
calls:
- [ addChild, [ '@admin.pago' ] ]
admin.pago:
class: AppBundleAdminPagoAdmin
arguments: [~, AppBundleEntityPago, ~]
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: AppBundleAdminCompradorAdmin
arguments: [~, AppBundleEntityComprador, ~]
tags:
- { name: sonata.admin, manager_type: orm, label:
Compradores }
calls:
- [ addChild, [ '@admin.pago' ] ]
admin.pago:
class: AppBundleAdminPagoAdmin
arguments: [~, AppBundleEntityPago, ~]
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: AppBundleAdminCompradorAdmin
arguments: [~, AppBundleEntityComprador, ~]
tags:
- { name: sonata.admin, manager_type: orm, label:
Compradores }
calls:
- [ addChild, [ '@admin.pago' ] ]
admin.pago:
class: AppBundleAdminPagoAdmin
arguments: [~, AppBundleEntityPago, ~]
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: AppBundleAdminCompradorAdmin
arguments: [~, AppBundleEntityComprador, ~]
tags:
- { name: sonata.admin, manager_type: orm, label:
Compradores }
calls:
- [ addChild, [ '@admin.pago' ] ]
admin.pago:
class: AppBundleAdminPagoAdmin
arguments: [~, AppBundleEntityPago, ~]
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
@vicqr
victoria@limenius.com
https://github.com/VictoriaQ/sonatademo
Formación, consultoría y
desarrollo de proyectos
Victoria Quirante Ruiz Madrid, 16-17 Sep. 2016#deSymfony
@vicqr
victoria@limenius.com
https://github.com/VictoriaQ/sonatademo
Formación, consultoría y
desarrollo de proyectos
Gracias!

Más contenido relacionado

Similar a SonataAdmin para Regalos

Php Bitter Sweet Symfony!
Php Bitter Sweet Symfony!Php Bitter Sweet Symfony!
Php Bitter Sweet Symfony!Ricard Luquero
 
Introducción al microframework PHP Silex - Sergio Gómez - Betabeers Córdoba 0...
Introducción al microframework PHP Silex - Sergio Gómez - Betabeers Córdoba 0...Introducción al microframework PHP Silex - Sergio Gómez - Betabeers Córdoba 0...
Introducción al microframework PHP Silex - Sergio Gómez - Betabeers Córdoba 0...betabeers
 
Tutorial3 Desymfony - La Vista. Twig
Tutorial3 Desymfony - La Vista. TwigTutorial3 Desymfony - La Vista. Twig
Tutorial3 Desymfony - La Vista. TwigMarcos Labad
 
Actividad 3 . funciones en php
Actividad 3 . funciones en phpActividad 3 . funciones en php
Actividad 3 . funciones en phpLeonardoPuerta2
 
WordPress como back-end de nuestras apps
WordPress como back-end de nuestras appsWordPress como back-end de nuestras apps
WordPress como back-end de nuestras appsJaime Fernández
 
Taller introduccion symfony2
Taller introduccion symfony2Taller introduccion symfony2
Taller introduccion symfony2Mario IC
 
Twig avanzado (sf2Vigo)
Twig avanzado (sf2Vigo)Twig avanzado (sf2Vigo)
Twig avanzado (sf2Vigo)Javier Eguiluz
 
Un newbie conoce a Sinatra
Un newbie conoce a SinatraUn newbie conoce a Sinatra
Un newbie conoce a SinatraJano González
 
Presentacion
PresentacionPresentacion
PresentacionEl Jota
 
Desarrollo de aplicaciones web usando Catalyst y jQuery
Desarrollo de aplicaciones web usando Catalyst y jQueryDesarrollo de aplicaciones web usando Catalyst y jQuery
Desarrollo de aplicaciones web usando Catalyst y jQueryJavier P.
 
Desarrollando aplicaciones web usando Catalyst y jQuery
Desarrollando aplicaciones web usando Catalyst y jQueryDesarrollando aplicaciones web usando Catalyst y jQuery
Desarrollando aplicaciones web usando Catalyst y jQueryJavier P.
 
Desarrollo de aplicaciones web usando Catalyst y jQuery
Desarrollo de aplicaciones web usando Catalyst y jQueryDesarrollo de aplicaciones web usando Catalyst y jQuery
Desarrollo de aplicaciones web usando Catalyst y jQueryJavier P.
 
Deployer PHP. Presentación para #PHPSevilla
Deployer PHP. Presentación para #PHPSevillaDeployer PHP. Presentación para #PHPSevilla
Deployer PHP. Presentación para #PHPSevillaAgencia INNN
 

Similar a SonataAdmin para Regalos (20)

APIREST LARAVEL Y PHP.pptx
APIREST LARAVEL Y PHP.pptxAPIREST LARAVEL Y PHP.pptx
APIREST LARAVEL Y PHP.pptx
 
Php Bitter Sweet Symfony!
Php Bitter Sweet Symfony!Php Bitter Sweet Symfony!
Php Bitter Sweet Symfony!
 
Introducción al microframework PHP Silex - Sergio Gómez - Betabeers Córdoba 0...
Introducción al microframework PHP Silex - Sergio Gómez - Betabeers Córdoba 0...Introducción al microframework PHP Silex - Sergio Gómez - Betabeers Córdoba 0...
Introducción al microframework PHP Silex - Sergio Gómez - Betabeers Córdoba 0...
 
Tutorial3 Desymfony - La Vista. Twig
Tutorial3 Desymfony - La Vista. TwigTutorial3 Desymfony - La Vista. Twig
Tutorial3 Desymfony - La Vista. Twig
 
Actividad 3 . funciones en php
Actividad 3 . funciones en phpActividad 3 . funciones en php
Actividad 3 . funciones en php
 
Backend (sf2Vigo)
Backend (sf2Vigo)Backend (sf2Vigo)
Backend (sf2Vigo)
 
WordPress como back-end de nuestras apps
WordPress como back-end de nuestras appsWordPress como back-end de nuestras apps
WordPress como back-end de nuestras apps
 
Taller introduccion symfony2
Taller introduccion symfony2Taller introduccion symfony2
Taller introduccion symfony2
 
Twig avanzado (sf2Vigo)
Twig avanzado (sf2Vigo)Twig avanzado (sf2Vigo)
Twig avanzado (sf2Vigo)
 
Doctrine2 sf2Vigo
Doctrine2 sf2VigoDoctrine2 sf2Vigo
Doctrine2 sf2Vigo
 
Un newbie conoce a Sinatra
Un newbie conoce a SinatraUn newbie conoce a Sinatra
Un newbie conoce a Sinatra
 
Presentacion
PresentacionPresentacion
Presentacion
 
Desarrollo de aplicaciones web usando Catalyst y jQuery
Desarrollo de aplicaciones web usando Catalyst y jQueryDesarrollo de aplicaciones web usando Catalyst y jQuery
Desarrollo de aplicaciones web usando Catalyst y jQuery
 
Desarrollando aplicaciones web usando Catalyst y jQuery
Desarrollando aplicaciones web usando Catalyst y jQueryDesarrollando aplicaciones web usando Catalyst y jQuery
Desarrollando aplicaciones web usando Catalyst y jQuery
 
Desarrollo de aplicaciones web usando Catalyst y jQuery
Desarrollo de aplicaciones web usando Catalyst y jQueryDesarrollo de aplicaciones web usando Catalyst y jQuery
Desarrollo de aplicaciones web usando Catalyst y jQuery
 
Código Bonito con PHP
Código Bonito con PHPCódigo Bonito con PHP
Código Bonito con PHP
 
Symfony Parte 2
Symfony Parte 2Symfony Parte 2
Symfony Parte 2
 
Deployer PHP. Presentación para #PHPSevilla
Deployer PHP. Presentación para #PHPSevillaDeployer PHP. Presentación para #PHPSevilla
Deployer PHP. Presentación para #PHPSevilla
 
Fabric más allá de lo básico
Fabric más allá de lo básicoFabric más allá de lo básico
Fabric más allá de lo básico
 
Introducción a DJango
Introducción a DJangoIntroducción a DJango
Introducción a DJango
 

Último

BREEAM ES Urbanismo como herramienta para un planeamiento sostenible - Miguel...
BREEAM ES Urbanismo como herramienta para un planeamiento sostenible - Miguel...BREEAM ES Urbanismo como herramienta para un planeamiento sostenible - Miguel...
BREEAM ES Urbanismo como herramienta para un planeamiento sostenible - Miguel...ITeC Instituto Tecnología Construcción
 
Manual de Usuario APPs_AppInventor-2023.pdf
Manual de Usuario APPs_AppInventor-2023.pdfManual de Usuario APPs_AppInventor-2023.pdf
Manual de Usuario APPs_AppInventor-2023.pdfmasogeis
 
Unidad_3_T1_AutomatasFinitos presentacion
Unidad_3_T1_AutomatasFinitos presentacionUnidad_3_T1_AutomatasFinitos presentacion
Unidad_3_T1_AutomatasFinitos presentacionarmando_cardenas
 
Introducción a Funciones LENGUAJE DART FLUTTER
Introducción a Funciones LENGUAJE DART FLUTTERIntroducción a Funciones LENGUAJE DART FLUTTER
Introducción a Funciones LENGUAJE DART FLUTTEREMMAFLORESCARMONA
 
PARTES DEL TECLADO Y SUS FUNCIONES - EJEMPLO
PARTES DEL TECLADO Y SUS FUNCIONES - EJEMPLOPARTES DEL TECLADO Y SUS FUNCIONES - EJEMPLO
PARTES DEL TECLADO Y SUS FUNCIONES - EJEMPLOSelenaCoronadoHuaman
 
Caso de éxito de Hervian con el ERP Sage 200
Caso de éxito de Hervian con el ERP Sage 200Caso de éxito de Hervian con el ERP Sage 200
Caso de éxito de Hervian con el ERP Sage 200Opentix
 
Segmentacion Segmantica_Modelos UNET and DEEPLABV3
Segmentacion Segmantica_Modelos UNET and DEEPLABV3Segmentacion Segmantica_Modelos UNET and DEEPLABV3
Segmentacion Segmantica_Modelos UNET and DEEPLABV3AlexysCaytanoMelndez1
 

Último (7)

BREEAM ES Urbanismo como herramienta para un planeamiento sostenible - Miguel...
BREEAM ES Urbanismo como herramienta para un planeamiento sostenible - Miguel...BREEAM ES Urbanismo como herramienta para un planeamiento sostenible - Miguel...
BREEAM ES Urbanismo como herramienta para un planeamiento sostenible - Miguel...
 
Manual de Usuario APPs_AppInventor-2023.pdf
Manual de Usuario APPs_AppInventor-2023.pdfManual de Usuario APPs_AppInventor-2023.pdf
Manual de Usuario APPs_AppInventor-2023.pdf
 
Unidad_3_T1_AutomatasFinitos presentacion
Unidad_3_T1_AutomatasFinitos presentacionUnidad_3_T1_AutomatasFinitos presentacion
Unidad_3_T1_AutomatasFinitos presentacion
 
Introducción a Funciones LENGUAJE DART FLUTTER
Introducción a Funciones LENGUAJE DART FLUTTERIntroducción a Funciones LENGUAJE DART FLUTTER
Introducción a Funciones LENGUAJE DART FLUTTER
 
PARTES DEL TECLADO Y SUS FUNCIONES - EJEMPLO
PARTES DEL TECLADO Y SUS FUNCIONES - EJEMPLOPARTES DEL TECLADO Y SUS FUNCIONES - EJEMPLO
PARTES DEL TECLADO Y SUS FUNCIONES - EJEMPLO
 
Caso de éxito de Hervian con el ERP Sage 200
Caso de éxito de Hervian con el ERP Sage 200Caso de éxito de Hervian con el ERP Sage 200
Caso de éxito de Hervian con el ERP Sage 200
 
Segmentacion Segmantica_Modelos UNET and DEEPLABV3
Segmentacion Segmantica_Modelos UNET and DEEPLABV3Segmentacion Segmantica_Modelos UNET and DEEPLABV3
Segmentacion Segmantica_Modelos UNET and DEEPLABV3
 

SonataAdmin para Regalos

  • 1.
  • 2.
  • 3. 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
  • 4. I. Introducción O acerca de por qué y para qué estamos aquí
  • 7.
  • 8. Principales problemas históricamente atribuidos - Difícil de instalar
  • 9. Principales problemas históricamente atribuidos - Difícil de instalar - Feo
  • 10. Principales problemas históricamente atribuidos - Difícil de instalar - Feo - Mala documentación
  • 11. Principales problemas históricamente atribuidos - Difícil de instalar - Feo - Mala documentación - Mucho código, difícil de investigar
  • 12. Principales problemas históricamente atribuidos - Difícil de instalar - Feo - Mala documentación - Mucho código, difícil de investigar
  • 13. Principales problemas históricamente atribuidos - Difícil de instalar - Feo - Mala documentación - Mucho código, difícil de investigar
  • 14. Principales problemas históricamente atribuidos - Difícil de instalar - Feo - Mala documentación regular - Mucho código, difícil de investigar
  • 15. Principales problemas históricamente atribuidos - Difícil de instalar - Feo - Mala documentación regular - Mucho código, difícil de investigar
  • 16. El problema que queremos resolver...
  • 17. ...es implementar un panel de administración
  • 18. 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
  • 19. 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
  • 20. 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 Como Symfony, como PHP
  • 21. 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
  • 22. 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í
  • 23. Dos tipos de desarrolladores
  • 24.
  • 25.
  • 27. 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
  • 32. El Admin básico: 3 pasos, 2 minutos Tenemos la entidad Regalo para la que queremos crear un Admin
  • 33. El Admin básico: 3 pasos, 2 minutos Tenemos la entidad Regalo para la que queremos crear un Admin: 1) Creamos la clase RegaloAdmin 2) Registramos el servicio
  • 34. 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'); } }
  • 35. 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'); } }
  • 36. 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'); } }
  • 37. 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'); } }
  • 38. 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'); } }
  • 39. El Admin básico - Paso 2: Registramos el servicio # app/config/services.yml services: admin.regalo: class: AppBundleAdminRegaloAdmin arguments: [~, AppBundleEntityRegalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Regalos }
  • 40. El Admin básico - Paso 2: Registramos el servicio # app/config/services.yml services: admin.regalo: class: AppBundleAdminRegaloAdmin arguments: [~, AppBundleEntityRegalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Regalos }
  • 45. 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
  • 46. 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
  • 47. 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
  • 48. Screenshots (II): Primer Admin (ítem en menú lateral)
  • 49. Ok, ¿y con eso que tengo?
  • 50. ¿Y con eso qué tengo? - Create, edit, delete...
  • 51. Screenshots (II): Primer Admin - El formulario
  • 52. Lo que Sonata te da hecho - Create, edit, delete... - Listado paginado, ordenable, filtrable y exportable
  • 53. Lo que Sonata te da hecho - Create, edit, delete... - Listado paginado, ordenable, filtrable y exportable
  • 54.
  • 55. Screenshots (II): Primer Admin - El listado
  • 56. Screenshots (II): Primer Admin - El listado
  • 57. Screenshots (II): Primer Admin - Los filtros
  • 59. Configuración básica del listado # src/AppBundle/Admin/RegaloAdmin.php protected function configureListFields(ListMapper $listMapper) { $listMapper ->add('nombre') ; }
  • 60. 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') ; }
  • 61. 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') ; }
  • 62. 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') ; }
  • 63. 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') ; }
  • 64. 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') ; }
  • 65. 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
  • 66. Screenshots (II): Primer Admin - El listado
  • 67. Screenshots (II): Primer Admin - El listado
  • 68. Screenshots (II): Primer Admin - El listado
  • 69. Screenshots (II): Primer Admin - El listado
  • 70. 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(), ) )) ; }
  • 71. 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(), ) )) ; }
  • 72. Screenshots (II): Primer Admin - El listado
  • 73. Screenshots (II): Primer Admin - El listado
  • 75. Configuración básica del formulario # src/AppBundle/Admin/RegaloAdmin.php protected function configureFormFields(FormMapper $formMapper) { $formMapper ->add('nombre') ; }
  • 76. 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') ; }
  • 77. Screenshots (II): Primer Admin - El formulario
  • 78. 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') ; }
  • 79. 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() ; }
  • 80. 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() ; }
  • 81. Screenshots (II): Primer Admin - El formulario
  • 82. 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() ; }
  • 83. Screenshots (II): Primer Admin - El formulario
  • 84. ¿Y si alguno de los campos tiene una relación con otra entidad?
  • 85. Screenshots (II): Primer Admin - El formulario
  • 86. 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() ; }
  • 87. 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() ; }
  • 88. 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' => 'AppBundleEntityDestinatario')) ->add('comprador', 'entity', array( 'class' => 'AppBundleEntityComprador')) ->end() ; }
  • 89. 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' => 'AppBundleEntityDestinatario', 'choice_label' => 'apellidos')) ->add('comprador', null, array( 'class' => 'AppBundleEntityComprador', 'choice_label' => 'apellidos')) ->end() ; }
  • 90. 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' => 'AppBundleEntityDestinatario', 'choice_label' => 'nombreCompleto')) ->add('comprador', null, array( 'class' => 'AppBundleEntityComprador', 'choice_label' => 'nombreCompleto')) ->end() ; }
  • 91. Screenshots (II): Primer Admin - El formulario
  • 92. ¿Y los one-to-many y many-to-many?
  • 93. 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() ; }
  • 94. 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() ; }
  • 95. 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() ; }
  • 96. 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
  • 97. Una collection en el form (one-to-many)
  • 98. Una collection en el form (one-to-many)
  • 99. Una collection en el form (one-to-many)
  • 101. 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() ; }
  • 102. 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() ; }
  • 103. 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() ; }
  • 108. Configuración básica de los filtros # src/AppBundle/Admin/RegaloAdmin.php protected function configureDatagridFilters(DatagridMapper $datagridMapper) { $datagridMapper ->add('nombre') ; }
  • 109. 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' => 'AppBundleEntityDestinatario', 'choice_label' => 'nombreCompleto')) ; }
  • 110. Screenshots (II): Primer Admin - Los filtros
  • 111. Hasta aquí lo “gratis”
  • 112. ¿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
  • 113.
  • 114. ¿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…?
  • 115. ¿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?
  • 116.
  • 117. III. Personalizando O cómo campar a mis anchas paso a paso
  • 120. 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' ...
  • 121. 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
  • 122. 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' ...
  • 123. 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' ...
  • 124. 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
  • 126. 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 %}
  • 129. ¿Y si solo quiero sobrescribir la template de un Admin concreto?
  • 130. Sobrescribir templates # app/config/services.yml services: admin.regalo: class: AppBundleAdminRegaloAdmin arguments: [~, AppBundleEntityRegalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Regalos }
  • 131. Sobrescribir templates # app/config/services.yml services: admin.regalo: class: AppBundleAdminRegaloAdmin arguments: [~, AppBundleEntityRegalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Regalos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]]
  • 133. ¿Cómo sobrescribo la template de un campo concreto del listado?
  • 134. Sobrescribir la template de un field en el list # src/AppBundle/Admin/RegaloAdmin.php protected function configureListFields(ListMapper $listMapper) { $listMapper ... ; }
  • 135. 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')) ; }
  • 136. 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')) ; }
  • 137. 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 %}
  • 138. Screenshots (III): Sobrescribir la template de un field en el list
  • 140. Screenshots (III): Modificar la query del list
  • 141. 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; }
  • 142. 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; }
  • 143. Screenshots (III): Modificar la query del list
  • 144. Screenshots (III): Modificar la query de un filtro
  • 145. Screenshots (III): Modificar la query de un filtro
  • 146. Screenshots (III): Modificar la query de un filtro
  • 147. 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' )) ; }
  • 148. 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' )) ; }
  • 149. 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' )) ; }
  • 150. 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' )) ; }
  • 151. Screenshots (III): Modificar la query de un filtro
  • 152. Screenshots (III): Modificar la query de un filtro
  • 154. Screenshots (III): Crear un action custom
  • 155. Crear un action custom (paso 1) # src/AppBundle/Controller/RegaloAdminController.php use SonataAdminBundleControllerCRUDController as Controller; use SymfonyComponentHttpFoundationRedirectResponse; 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')); } }
  • 156. Crear un action custom (paso 1) # src/AppBundle/Controller/RegaloAdminController.php use SonataAdminBundleControllerCRUDController as Controller; use SymfonyComponentHttpFoundationRedirectResponse; 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')); } }
  • 157. Crear un action custom (paso 1) # src/AppBundle/Controller/RegaloAdminController.php use SonataAdminBundleControllerCRUDController as Controller; use SymfonyComponentHttpFoundationRedirectResponse; 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')); } }
  • 158. Crear un action custom (paso 2) # app/config/services.yml services: admin.regalo: class: AppBundleAdminRegaloAdmin arguments: [~, AppBundleEntityRegalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Regalos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]]
  • 159. Crear un action custom (paso 2) # app/config/services.yml services: admin.regalo: class: AppBundleAdminRegaloAdmin arguments: [~, AppBundleEntityRegalo, AppBundleRegaloAdmin] tags: - { name: sonata.admin, manager_type: orm, label: Regalos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]]
  • 160. Crear un action custom (paso 3) # src/AppBundle/Admin/RegaloAdmin.php protected function configureRoutes(RouteCollection $collection) { $collection->add('sendEmail', $this->getRouterIdParameter().'/send-email'); }
  • 161. Crear un action custom (paso 3) # src/AppBundle/Admin/RegaloAdmin.php protected function configureRoutes(RouteCollection $collection) { $collection->add('sendEmail', $this->getRouterIdParameter().'/send-email'); }
  • 162. 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 %}
  • 163. 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 %}
  • 164. Screenshots (III): Crear un action custom
  • 165. Screenshots (III): Crear una batch action custom
  • 166. 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')); }
  • 167. 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')); }
  • 168. 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; }
  • 169. 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; }
  • 170. Screenshots (III): Crear una batch action custom
  • 171. IV. Consejos prácticos O conjunto de ideas varias que pueden venir bien en cualquier proyecto
  • 172. ¿Cómo toco el aspecto general del panel?
  • 176. Aspecto general # app/config/config.yml sonata_admin: title: deSymfony title_logo: 'img/logo.png'
  • 177. 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 …
  • 178. 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
  • 179. 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 …
  • 181. 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 …
  • 182. 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 …
  • 183. 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í
  • 184. Aspecto general - Layout
  • 185. Aspecto general - Layout
  • 186. Aspecto general - Layout
  • 187. 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' ...
  • 188. 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' ...
  • 189. 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' ...
  • 190. Aspecto general - Layout
  • 191. Aspecto general - Dashboard
  • 192. 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' ...
  • 193. 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' ...
  • 194. 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' ...
  • 195. Aspecto general - Dashboard
  • 196. Aspecto general - Dashboard
  • 197. Aspecto general - Dashboard
  • 198. ¿Puedo hacer dos admins de la misma entidad?
  • 199. Crear dos admins de la misma entidad # src/AppBundle/Admin/RegaloPasadoAdmin.php class RegaloPasadoAdmin extends Admin { } Sin problema. Creamos una nueva clase Admin…
  • 200. 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)
  • 201. Crear dos admins de la misma entidad # app/config/services.yml services: admin.regalo: class: AppBundleAdminRegaloAdmin arguments: [~, AppBundleEntityRegalo, AppBundle:RegaloAdmin] tags: - { name: sonata.admin, manager_type: orm, label: Regalos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]] … y registramos el nuevo servicio
  • 202. Crear dos admins de la misma entidad # app/config/services.yml services: admin.regalo: class: AppBundleAdminRegaloAdmin arguments: [~, AppBundleEntityRegalo, AppBundle:RegaloAdmin] tags: - { name: sonata.admin, manager_type: orm, label: Activos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]] admin.regalo_pasado: class: AppBundleAdminRegaloPasadoAdmin arguments: [~, AppBundleEntityRegalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pasados } … y registramos el nuevo servicio
  • 203. Crear dos admins de la misma entidad
  • 204. Crear dos admins de la misma entidad
  • 205. Crear dos admins de la misma entidad
  • 206. Admin como child en el menú de otro Admin
  • 207. Admin como child en el menú de otro Admin
  • 208. Admin como child en el menú de otro Admin
  • 209. Admin como child en el menú de otro Admin # app/config/services.yml admin.comprador: class: AppBundleAdminCompradorAdmin arguments: [~, AppBundleEntityComprador, ~] tags: - { name: sonata.admin, manager_type: orm, label: Compradores } calls: - [ addChild, [ '@admin.pago' ] ] admin.pago: class: AppBundleAdminPagoAdmin arguments: [~, AppBundleEntityPago, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pagos }
  • 210. Admin como child en el menú de otro Admin # app/config/services.yml admin.comprador: class: AppBundleAdminCompradorAdmin arguments: [~, AppBundleEntityComprador, ~] tags: - { name: sonata.admin, manager_type: orm, label: Compradores } calls: - [ addChild, [ '@admin.pago' ] ] admin.pago: class: AppBundleAdminPagoAdmin arguments: [~, AppBundleEntityPago, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pagos }
  • 211. Admin como child en el menú de otro Admin # app/config/services.yml admin.comprador: class: AppBundleAdminCompradorAdmin arguments: [~, AppBundleEntityComprador, ~] tags: - { name: sonata.admin, manager_type: orm, label: Compradores } calls: - [ addChild, [ '@admin.pago' ] ] admin.pago: class: AppBundleAdminPagoAdmin arguments: [~, AppBundleEntityPago, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pagos }
  • 212. Admin como child en el menú de otro Admin # app/config/config.yml admin.comprador: class: AppBundleAdminCompradorAdmin arguments: [~, AppBundleEntityComprador, ~] tags: - { name: sonata.admin, manager_type: orm, label: Compradores } calls: - [ addChild, [ '@admin.pago' ] ] admin.pago: class: AppBundleAdminPagoAdmin arguments: [~, AppBundleEntityPago, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pagos }
  • 213. 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)) ); }
  • 214. 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)) ); }
  • 215. Admin como child en el menú de otro Admin
  • 216. ¿Qué pasa si el listado no es lo principal?
  • 217. Enlazar un action custom desde la sidebar Creamos nuestro action custom, la template y la ruta...
  • 218. 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
  • 219. 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
  • 220. Enlazar un action custom desde la sidebar
  • 221. ¿Y si quiero meter algo que no sea un Admin?
  • 222. 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
  • 223. Toda tu aplicación puede estar dentro de Sonata
  • 224. Toda tu aplicación puede estar dentro de Sonata
  • 225. Toda tu aplicación puede estar dentro de Sonata Creas tu action en el controlador (PacienteAdminController.php)
  • 226. 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');
  • 227. 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>
  • 228. V. Más allá O qué otras cosas hay ahí fuera y dónde puedo encontrarlas
  • 230. 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
  • 231. 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
  • 232. 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
  • 236. Y a la hora de la verdad.. pues el código
  • 237. Admin class Conviene mucho mirarse la Admin class vendor/sonata-project/admin-bundle/Admin/AbstractAdmin.php
  • 238. VI. Conclusiones O con qué me quedo de todo esto
  • 239. Conclusiones ● Los principales problemas se han ido solucionando. Y sigue mejorando.
  • 240. 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.
  • 241. 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.
  • 242. Conclusiones Te permite solucionar un problema aburrido de una forma eficiente
  • 243. Conclusiones Te permite solucionar un problema aburrido de una forma eficiente Para que puedas dedicarte a otra cosa más emocionante
  • 244. Conclusiones Y desde el punto de vista del negocio suele ser muy buena decisión
  • 245. Victoria Quirante Ruiz Madrid, 16-17 Sep. 2016#deSymfony @vicqr victoria@limenius.com https://github.com/VictoriaQ/sonatademo Formación, consultoría y desarrollo de proyectos
  • 246. Victoria Quirante Ruiz Madrid, 16-17 Sep. 2016#deSymfony @vicqr victoria@limenius.com https://github.com/VictoriaQ/sonatademo Formación, consultoría y desarrollo de proyectos Gracias!