architecture.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. Architecture
  2. ============
  3. The architecture of the ``SonataAdminBundle`` is primarily inspired by the Django Admin
  4. Project, which is truly a great project. More information can be found at the
  5. `Django Project Website`_.
  6. If you followed the instructions on the :doc:`getting_started` page, you should by
  7. now have an ``Admin`` class and an ``Admin`` service. In this chapter, we'll discuss more in
  8. depth how it works.
  9. The Admin Class
  10. ---------------
  11. The ``Admin`` class maps a specific model to the rich CRUD interface provided by
  12. ``SonataAdminBundle``. In other words, using your ``Admin`` classes, you can configure
  13. what is shown by ``SonataAdminBundle`` in each CRUD action for the associated model.
  14. By now you've seen 3 of those actions in the ``getting started`` page: list,
  15. filter and form (for creation/edition). However, a fully configured ``Admin`` class
  16. can define more actions:
  17. * ``list``: The fields displayed in the list table;
  18. * ``filter``: The fields available for filtering the list;
  19. * ``form``: The fields used to create/edit the entity;
  20. * ``show``: The fields used to show the entity;
  21. * Batch actions: Actions that can be performed on a group of entities
  22. (e.g. bulk delete)
  23. The ``Sonata\AdminBundle\Admin\Admin`` class is provided as an easy way to
  24. map your models, by extending it. However, any implementation of the
  25. ``Sonata\AdminBundle\Admin\AdminInterface`` can be used to define an ``Admin``
  26. service. For each ``Admin`` service, the following required dependencies are
  27. automatically injected by the bundle:
  28. * ``ModelManager``: service which handles specific ORM code
  29. * ``FormContractor``: builds the edit/create views form using the Symfony ``FormBuilder``
  30. * ``ShowBuilder``: builds the 'show' view
  31. * ``ListBuilder``: builds the list fields
  32. * ``DatagridBuilder``: builds the filter fields
  33. * ``Translator``: generates translations
  34. * ``ConfigurationPool``: configuration pool where all Admin class instances are stored
  35. * ``RouterGenerator``: generates the different urls
  36. * ``Validator``: handles model validation
  37. * ``SecurityHandler``: handles permissions for model instances and actions
  38. * ``MenuFactory``: generates the side menu, depending on the current action
  39. * ``RouteBuilder``: allows you to easily add routes for new actions
  40. * ``Request`` : http request received
  41. * ``LabelTranslatorStrategy``: a strategy to use when generating labels
  42. .. note::
  43. Each of these dependencies is used for a specific task, briefly described above.
  44. If you wish to learn more about how they are used, check the respective documentation
  45. chapter. In most cases, you won't need to worry about their underlying implementation.
  46. All these dependencies have default values that you can override by a using
  47. ``call`` to the matching ``setter`` when declaring the ``Admin`` service, like so:
  48. .. code-block:: xml
  49. <service id="sonata.admin.post" class="Acme\DemoBundle\Admin\PostAdmin">
  50. <tag name="sonata.admin" manager_type="orm" group="Content" label="Post"/>
  51. <argument />
  52. <argument>Acme\DemoBundle\Entity\Post</argument>
  53. <argument />
  54. <call method="setLabelTranslatorStrategy">
  55. <argument>sonata.admin.label.strategy.underscore</argument>
  56. </call>
  57. </service>
  58. .. code-block:: yaml
  59. services:
  60. sonata.admin.post:
  61. class: Acme\DemoBundle\Admin\PostAdmin
  62. tags:
  63. - { name: sonata.admin, manager_type: orm, group: "Content", label: "Post" }
  64. arguments:
  65. - ~
  66. - Acme\DemoBundle\Entity\Post
  67. - ~
  68. calls:
  69. - [ setLabelTranslatorStrategy, [sonata.admin.label.strategy.underscore]]
  70. Here, we declare the same ``Admin`` service as in the :doc:`getting_started` chapter, but using a
  71. different label translator strategy, replacing the default one. Notice that
  72. ``sonata.admin.label.strategy.underscore`` is a service provided by ``SonataAdminBundle``,
  73. but you could just as easily use a service of your own.
  74. CRUDController
  75. --------------
  76. The ``CRUDController`` contains the actions you have available to manipulate
  77. your model instances, like list, create or delete. It uses the ``Admin`` class
  78. to determine its behavior, like which fields to display in the edit form, or
  79. how to build the list view. Inside the ``CRUDController``, you can find the
  80. ``Admin`` class instance in the ``$admin`` variable.
  81. The ``CRUDController`` is no different than any other Symfony2 controller,
  82. meaning you have all the usual options available to you, like getting services
  83. from the Dependency Injection Container (DIC).
  84. This is particulary useful if you decide to extend the ``CRUDController``, to
  85. add new actions or change the behavior of existing ones. You can specify which controller
  86. to use when declaring the ``Admin`` service, by passing it as the 3rd argument:
  87. .. code-block:: xml
  88. <services>
  89. <service id="sonata.admin.post" class="Acme\DemoBundle\Admin\PostAdmin">
  90. <tag name="sonata.admin" manager_type="orm" group="Content" label="Post"/>
  91. <argument />
  92. <argument>Acme\DemoBundle\Entity\Post</argument>
  93. <argument>AcmeDemoBundle:PostAdmin</argument>
  94. <call method="setTranslationDomain">
  95. <argument>AcmeDemoBundle</argument>
  96. </call>
  97. </service>
  98. </services>
  99. .. code-block:: yaml
  100. services:
  101. sonata.admin.post:
  102. class: Acme\DemoBundle\Admin\PostAdmin
  103. tags:
  104. - { name: sonata.admin, manager_type: orm, group: "Content", label: "Post" }
  105. arguments:
  106. - ~
  107. - Acme\DemoBundle\Entity\Post
  108. - AcmeDemoBundle:PostAdmin
  109. calls:
  110. - [ setTranslationDomain, [AcmeDemoBundle]]
  111. When extending a ``CRUDController``, remember that the ``Admin`` class already has
  112. a set of automatically injected dependencies that are useful when implementing several
  113. scenarios. Refer to the existing ``CRUDController`` actions for examples on how to get
  114. the best out of them.
  115. Fields Definition
  116. -----------------
  117. Your ``Admin`` class will map your model's fields to a field in every action defined in you
  118. ``CRUDController``. So, for each action, a list of field mappings is generated. These lists
  119. are implemented using the ``FieldDescriptionCollection`` class which stores instances of
  120. ``FieldDescriptionInterface``. Picking up on our previous ``Admin`` class example:
  121. .. code-block:: php
  122. namespace Acme\DemoBundle\Admin;
  123. use Sonata\AdminBundle\Admin\Admin;
  124. use Sonata\AdminBundle\Datagrid\ListMapper;
  125. use Sonata\AdminBundle\Datagrid\DatagridMapper;
  126. use Sonata\AdminBundle\Form\FormMapper;
  127. class PostAdmin extends Admin
  128. {
  129. //Fields to be shown on create/edit forms
  130. protected function configureFormFields(FormMapper $formMapper)
  131. {
  132. $formMapper
  133. ->add('title', 'text', array('label' => 'Post Title'))
  134. ->add('author', 'entity', array('class' => 'Acme\DemoBundle\Entity\User'))
  135. ->add('body') //if no type is specified, SonataAdminBundle tries to guess it
  136. ;
  137. }
  138. //Fields to be shown on filter forms
  139. protected function configureDatagridFilters(DatagridMapper $datagridMapper)
  140. {
  141. $datagridMapper
  142. ->add('title')
  143. ->add('author')
  144. ;
  145. }
  146. //Fields to be shown on lists
  147. protected function configureListFields(ListMapper $listMapper)
  148. {
  149. $listMapper
  150. ->addIdentifier('title')
  151. ->add('slug')
  152. ->add('author')
  153. ;
  154. }
  155. }
  156. Internally, the provided ``Admin`` class will use these three functions to create three
  157. ``FieldDescriptionCollection`` instances:
  158. * ``$formFieldDescriptions``, containing three ``FieldDescriptionInterface`` instances
  159. * ``$filterFieldDescriptions``, containing two ``FieldDescriptionInterface`` instances
  160. * ``$listFieldDescriptions``, containing three ``FieldDescriptionInterface`` instances
  161. The actual ``FieldDescription`` implementation is provided by the storage
  162. abstraction bundle that you choose during the installation process, based on the
  163. ``BaseFieldDescription`` abstract class provided by ``SonataAdminBundle``.
  164. Each ``FieldDescription`` contains various details about a field mapping. Some of
  165. them are independent of the action in which they are used, like ``name`` or ``type``,
  166. while other are used only in specific actions. More information can be found on the
  167. ``BaseFieldDescription`` class file.
  168. In most scenarios, you won't actually need to handle ``FieldDescription`` yourself.
  169. However, it is important that you know it exists and how it's used, as it sits at the
  170. core of ``SonataAdminBundle``.
  171. Templates
  172. ---------
  173. Like most actions, ``CRUDController`` actions use view files to render their output.
  174. ``SonataAdminBundle`` provides ready to use views as well as ways to easily customize them.
  175. The current implementation uses ``Twig`` as the template engine. All templates
  176. are located in the ``Resources/views`` directory of the bundle.
  177. There are two base templates, one of which is ultimately used in every action:
  178. * ``SonataAdminBundle::standard_layout.html.twig``
  179. * ``SonataAdminBundle::ajax_layout.html.twig``
  180. Like the names say, one if for standard calls, the other one for AJAX.
  181. The subfolders include Twig files for specific sections of ``SonataAdminBundle``:
  182. * Block: ``SonataBlockBundle`` block views. Right now it only has one, that displays all the mapped classes on the dashboard
  183. * Button: Buttons such as ``Add new`` or ``Delete`` that you can see across several CRUD actions
  184. * CRUD: Base views for every CRUD action, plus several field views for each field type
  185. * Core: Dashboard view, together with deprecated and stub twig files.
  186. * Form: Views related to form rendering
  187. * Helper: a view providing a short object description, as part of a specific form field type provided by ``SonataAdminBundle``
  188. * Pager: Pagination related view files
  189. These will be discussed in greater detail in the specific :doc:`templates` section, where
  190. you will also find instructions on how to configure ``SonataAdminBundle`` to use your templates
  191. instead of the default ones.
  192. Managing ``Admin`` Service
  193. ------------------------------
  194. Your ``Admin`` service definitions are parsed when Symfony2 is loaded, and handled by
  195. the ``Pool`` class. This class, available as the ``sonata.admin.pool`` service from the
  196. DIC, handles the ``Admin`` classes, lazy-loading them on demand
  197. (to reduce overhead) and matching each of them to a group. It's also responsible for handling the
  198. top level template files, administration panel title and logo.
  199. .. _`Django Project Website`: http://www.djangoproject.com/