Cómo domar SonataAdminBundle

Cómo domar SonataAdminBundle

Exposición de lo que nos ofrece SonataAdminBundle y recorrido práctico desde su instalación, aprendiendo a personalizarlo y solventar diversos casos que nos encontramos con frecuencia en la implementación de un panel de administración con este bundle. Charla impartida en deSymfony 2016.

281604c1a5357a164f2a9cd6e403b4e3?s=128

Victoria Quirante

September 16, 2016
Tweet

Transcript

  1. None
  2. None
  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í
  5. El creador

  6. Principales colaboradores

  7. None
  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. None
  25. None
  26. Charla práctica https://github.com/VictoriaQ/sonatademo

  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
  28. Screenshots (II): Instalación limpia

  29. Screenshots (II): Instalación limpia

  30. Screenshots (II): Instalación limpia

  31. ¿Cómo empezamos?

  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: AppBundle\Admin\RegaloAdmin arguments: [~, AppBundle\Entity\Regalo, ~] 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: AppBundle\Admin\RegaloAdmin arguments: [~, AppBundle\Entity\Regalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Regalos }
  41. Screenshots (II): Primer Admin

  42. Screenshots (II): Primer Admin

  43. Screenshots (II): Primer Admin

  44. Screenshots (II): Primer Admin

  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. None
  55. Screenshots (II): Primer Admin - El listado

  56. Screenshots (II): Primer Admin - El listado

  57. Screenshots (II): Primer Admin - Los filtros

  58. Configuración básica del listado

  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

  74. Configuración básica del formulario

  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' => 'AppBundle\Entity\Destinatario')) ->add('comprador', 'entity', array( 'class' => 'AppBundle\Entity\Comprador')) ->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' => 'AppBundle\Entity\Destinatario', 'choice_label' => 'apellidos')) ->add('comprador', null, array( 'class' => 'AppBundle\Entity\Comprador', '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' => 'AppBundle\Entity\Destinatario', 'choice_label' => 'nombreCompleto')) ->add('comprador', null, array( 'class' => 'AppBundle\Entity\Comprador', '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)

  100. Una many-to-many en el form

  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() ; }
  104. Una many-to-many en el form

  105. Una many-to-many en el form

  106. Una many-to-many en el form

  107. Configuración básica de los filtros

  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' => 'AppBundle\Entity\Destinatario', '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. None
  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. None
  117. III. Personalizando O cómo campar a mis anchas paso a

    paso
  118. Personalizando • Templates • Queries • Actions

  119. Sobrescribiendo templates

  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
  125. Sobrescribir templates # vendor/sonata-project/admin-bundle/Resources/views/CRUD/edit.html.twig {% extends 'SonataAdminBundle:CRUD:base_edit.html.twig' %}

  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 %}
  127. Screenshots (III): Sobrescribir templates

  128. Screenshots (III): Sobrescribir templates

  129. ¿Y si solo quiero sobrescribir la template de un Admin

    concreto?
  130. Sobrescribir templates # app/config/services.yml services: admin.regalo: class: AppBundle\Admin\RegaloAdmin arguments: [~,

    AppBundle\Entity\Regalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Regalos }
  131. Sobrescribir templates # app/config/services.yml services: admin.regalo: class: AppBundle\Admin\RegaloAdmin arguments: [~,

    AppBundle\Entity\Regalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Regalos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]]
  132. Screenshots (III): Sobrescribir templates

  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
  139. Modificando las queries

  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

  153. Escribiendo en el controlador

  154. Screenshots (III): Crear un action custom

  155. Crear un action custom (paso 1) # src/AppBundle/Controller/RegaloAdminController.php use Sonata\AdminBundle\Controller\CRUDController

    as Controller; use Symfony\Component\HttpFoundation\RedirectResponse; class RegaloAdminController extends Controller { public function sendEmailAction() { $regalo = $this->admin->getSubject(); $email = $regalo->getDestinatario()->getEmail(); // Here code to send email $this->addFlash('sonata_flash_success', 'Email enviado a '.$email); return new RedirectResponse($this->admin->generateUrl('list')); } }
  156. Crear un action custom (paso 1) # src/AppBundle/Controller/RegaloAdminController.php use Sonata\AdminBundle\Controller\CRUDController

    as Controller; use Symfony\Component\HttpFoundation\RedirectResponse; class RegaloAdminController extends Controller { public function sendEmailAction() { $regalo = $this->admin->getSubject(); $email = $regalo->getDestinatario()->getEmail(); // Here code to send email $this->addFlash('sonata_flash_success', 'Email enviado a '.$email); return new RedirectResponse($this->admin->generateUrl('list')); } }
  157. Crear un action custom (paso 1) # src/AppBundle/Controller/RegaloAdminController.php use Sonata\AdminBundle\Controller\CRUDController

    as Controller; use Symfony\Component\HttpFoundation\RedirectResponse; class RegaloAdminController extends Controller { public function sendEmailAction() { $regalo = $this->admin->getSubject(); $email = $regalo->getDestinatario()->getEmail(); // Here code to send email $this->addFlash('sonata_flash_success', 'Email enviado a '.$email); return new RedirectResponse($this->admin->generateUrl('list')); } }
  158. Crear un action custom (paso 2) # app/config/services.yml services: admin.regalo:

    class: AppBundle\Admin\RegaloAdmin arguments: [~, AppBundle\Entity\Regalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Regalos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]]
  159. Crear un action custom (paso 2) # app/config/services.yml services: admin.regalo:

    class: AppBundle\Admin\RegaloAdmin arguments: [~, AppBundle\Entity\Regalo, AppBundle\RegaloAdmin] tags: - { name: sonata.admin, manager_type: orm, label: Regalos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]]
  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?

  173. Aspecto general

  174. Aspecto general

  175. Aspecto general # app/config/config.yml sonata_admin: title: deSymfony

  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 …
  180. Aspecto general

  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: AppBundle\Admin\RegaloAdmin arguments: [~, AppBundle\Entity\Regalo, AppBundle:RegaloAdmin] tags: - { name: sonata.admin, manager_type: orm, label: Regalos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]] … y registramos el nuevo servicio
  202. Crear dos admins de la misma entidad # app/config/services.yml services:

    admin.regalo: class: AppBundle\Admin\RegaloAdmin arguments: [~, AppBundle\Entity\Regalo, AppBundle:RegaloAdmin] tags: - { name: sonata.admin, manager_type: orm, label: Activos } calls: - [ setTemplate, [edit, :Admin:edit_regalo.html.twig]] admin.regalo_pasado: class: AppBundle\Admin\RegaloPasadoAdmin arguments: [~, AppBundle\Entity\Regalo, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pasados } … y registramos el nuevo servicio
  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: AppBundle\Admin\CompradorAdmin arguments: [~, AppBundle\Entity\Comprador, ~] tags: - { name: sonata.admin, manager_type: orm, label: Compradores } calls: - [ addChild, [ '@admin.pago' ] ] admin.pago: class: AppBundle\Admin\PagoAdmin arguments: [~, AppBundle\Entity\Pago, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pagos }
  210. Admin como child en el menú de otro Admin #

    app/config/services.yml admin.comprador: class: AppBundle\Admin\CompradorAdmin arguments: [~, AppBundle\Entity\Comprador, ~] tags: - { name: sonata.admin, manager_type: orm, label: Compradores } calls: - [ addChild, [ '@admin.pago' ] ] admin.pago: class: AppBundle\Admin\PagoAdmin arguments: [~, AppBundle\Entity\Pago, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pagos }
  211. Admin como child en el menú de otro Admin #

    app/config/services.yml admin.comprador: class: AppBundle\Admin\CompradorAdmin arguments: [~, AppBundle\Entity\Comprador, ~] tags: - { name: sonata.admin, manager_type: orm, label: Compradores } calls: - [ addChild, [ '@admin.pago' ] ] admin.pago: class: AppBundle\Admin\PagoAdmin arguments: [~, AppBundle\Entity\Pago, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pagos }
  212. Admin como child en el menú de otro Admin #

    app/config/config.yml admin.comprador: class: AppBundle\Admin\CompradorAdmin arguments: [~, AppBundle\Entity\Comprador, ~] tags: - { name: sonata.admin, manager_type: orm, label: Compradores } calls: - [ addChild, [ '@admin.pago' ] ] admin.pago: class: AppBundle\Admin\PagoAdmin arguments: [~, AppBundle\Entity\Pago, ~] tags: - { name: sonata.admin, manager_type: orm, label: Pagos }
  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
  229. Documentación de SonataAdminBundle

  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
  233. Sonata Project Demo

  234. Sonata Project Demo

  235. Sonata Project Demo

  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!