advanced_configuration.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. Advanced configuration
  2. ======================
  3. Service Configuration
  4. ---------------------
  5. When you create a new Admin service you can configure its dependencies, the services which are injected by default are:
  6. ========================= =============================================
  7. Dependencies Service Id
  8. ========================= =============================================
  9. model_manager sonata.admin.manager.%manager-type%
  10. form_contractor sonata.admin.builder.%manager-type%_form
  11. show_builder sonata.admin.builder.%manager-type%_show
  12. list_builder sonata.admin.builder.%manager-type%_list
  13. datagrid_builder sonata.admin.builder.%manager-type%_datagrid
  14. translator translator
  15. configuration_pool sonata.admin.pool
  16. router router
  17. validator validator
  18. security_handler sonata.admin.security.handler
  19. menu_factory knp_menu.factory
  20. route_builder sonata.admin.route.path_info | sonata.admin.route.path_info_slashes
  21. label_translator_strategy sonata.admin.label.strategy.form_component
  22. ========================= =============================================
  23. .. note::
  24. %manager-type% is to be replaced by the manager type (orm, doctrine_mongodb...),
  25. and the default route_builder depends on it.
  26. You have 2 ways of defining the dependencies inside ``services.xml``:
  27. * With a tag attribute, less verbose:
  28. .. configuration-block::
  29. .. code-block:: xml
  30. <service id="app.admin.project" class="AppBundle\Admin\ProjectAdmin">
  31. <tag
  32. name="sonata.admin"
  33. manager_type="orm"
  34. group="Project"
  35. label="Project"
  36. label_translator_strategy="sonata.admin.label.strategy.native"
  37. route_builder="sonata.admin.route.path_info"
  38. />
  39. <argument />
  40. <argument>AppBundle\Entity\Project</argument>
  41. <argument />
  42. </service>
  43. .. configuration-block::
  44. .. code-block:: yaml
  45. app.admin.project:
  46. class: AppBundle\Admin\ProjectAdmin
  47. tags:
  48. - { name: sonata.admin, manager_type: orm, group: "Project", label: "Project", label_translator_strategy: "sonata.admin.label.strategy.native", route_builder: "sonata.admin.route.path_info" }
  49. arguments:
  50. - ~
  51. - AppBundle\Entity\Project
  52. - ~
  53. * With a method call, more verbose
  54. .. configuration-block::
  55. .. code-block:: xml
  56. <service id="app.admin.project" class="AppBundle\Admin\ProjectAdmin">
  57. <tag
  58. name="sonata.admin"
  59. manager_type="orm"
  60. group="Project"
  61. label="Project"
  62. />
  63. <argument />
  64. <argument>AppBundle\Entity\Project</argument>
  65. <argument />
  66. <call method="setLabelTranslatorStrategy">
  67. <argument type="service" id="sonata.admin.label.strategy.native" />
  68. </call>
  69. <call method="setRouteBuilder">
  70. <argument type="service" id="sonata.admin.route.path_info" />
  71. </call>
  72. </service>
  73. .. configuration-block::
  74. .. code-block:: yaml
  75. app.admin.project:
  76. class: AppBundle\Admin\ProjectAdmin
  77. tags:
  78. - { name: sonata.admin, manager_type: orm, group: "Project", label: "Project" }
  79. arguments:
  80. - ~
  81. - AppBundle\Entity\Project
  82. - ~
  83. calls:
  84. - [ setLabelTranslatorStrategy, [ "@sonata.admin.label.strategy.native" ]]
  85. - [ setRouteBuilder, [ "@sonata.admin.route.path_info" ]]
  86. If you want to modify the service that is going to be injected, add the following code to your
  87. application's config file:
  88. .. configuration-block::
  89. .. code-block:: yaml
  90. # app/config/config.yml
  91. admins:
  92. sonata_admin:
  93. sonata.order.admin.order: # id of the admin service this setting is for
  94. model_manager: # dependency name, from the table above
  95. sonata.order.admin.order.manager # customised service id
  96. Creating a custom RouteBuilder
  97. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  98. To create your own RouteBuilder create the PHP class and register it as a service:
  99. * php Route Generator
  100. .. code-block:: php
  101. <?php
  102. namespace AppBundle\Route;
  103. use Sonata\AdminBundle\Builder\RouteBuilderInterface;
  104. use Sonata\AdminBundle\Admin\AdminInterface;
  105. use Sonata\AdminBundle\Route\PathInfoBuilder;
  106. use Sonata\AdminBundle\Route\RouteCollection;
  107. class EntityRouterBuilder extends PathInfoBuilder implements RouteBuilderInterface
  108. {
  109. /**
  110. * @param AdminInterface $admin
  111. * @param RouteCollection $collection
  112. */
  113. public function build(AdminInterface $admin, RouteCollection $collection)
  114. {
  115. parent::build($admin, $collection);
  116. $collection->add('yourSubAction');
  117. // The create button will disappear, delete functionality will be disabled as well
  118. // No more changes needed!
  119. $collection->remove('create');
  120. $collection->remove('delete');
  121. }
  122. }
  123. * xml service registration
  124. .. configuration-block::
  125. .. code-block:: xml
  126. <service id="app.admin.entity_route_builder" class="AppBundle\Route\EntityRouterBuilder">
  127. <argument type="service" id="sonata.admin.audit.manager" />
  128. </service>
  129. * YAML service registration
  130. .. configuration-block::
  131. .. code-block:: yaml
  132. services:
  133. app.admin.entity_route_builder:
  134. class: AppBundle\Route\EntityRouterBuilder
  135. arguments:
  136. - "@sonata.admin.audit.manager"
  137. Inherited classes
  138. -----------------
  139. You can manage inherited classes by injecting subclasses using the service configuration.
  140. Lets consider a base class named `Person` and its subclasses `Student` and `Teacher`:
  141. .. configuration-block::
  142. .. code-block:: xml
  143. <service id="app.admin.person" class="AppBundle\Admin\PersonAdmin">
  144. <tag name="sonata.admin" manager_type="orm" group="admin" label="Person" />
  145. <argument/>
  146. <argument>AppBundle\Entity\Person</argument>
  147. <argument></argument>
  148. <call method="setSubClasses">
  149. <argument type="collection">
  150. <argument key="student">AppBundle\Entity\Student</argument>
  151. <argument key="teacher">AppBundle\Entity\Teacher</argument>
  152. </argument>
  153. </call>
  154. </service>
  155. You will just need to change the way forms are configured in order to take into account these new subclasses:
  156. .. code-block:: php
  157. <?php
  158. // src/AppBundle/Admin/PersonAdmin.php
  159. protected function configureFormFields(FormMapper $formMapper)
  160. {
  161. $subject = $this->getSubject();
  162. $formMapper
  163. ->add('name')
  164. ;
  165. if ($subject instanceof Teacher) {
  166. $formMapper->add('course', 'text');
  167. }
  168. elseif ($subject instanceof Student) {
  169. $formMapper->add('year', 'integer');
  170. }
  171. }
  172. Tab Menu
  173. --------
  174. ACL
  175. ^^^
  176. Though the route linked by a menu may be protected the Tab Menu will not automatically check the ACl for you.
  177. The link will still appear unless you manually check it using the `isGranted` method:
  178. .. code-block:: php
  179. <?php
  180. protected function configureTabMenu(MenuItemInterface $menu, $action, AdminInterface $childAdmin = null)
  181. {
  182. // Link will always appear even if it is protected by ACL
  183. $menu->addChild($this->trans('Show'), array('uri' => $admin->generateUrl('show', array('id' => $id))));
  184. // Link will only appear if access to ACL protected URL is granted
  185. if ($this->isGranted('EDIT')) {
  186. $menu->addChild($this->trans('Edit'), array('uri' => $admin->generateUrl('edit', array('id' => $id))));
  187. }
  188. }
  189. Dropdowns
  190. ^^^^^^^^^
  191. You can use dropdowns inside the Tab Menu by default. This can be achieved by using
  192. the `'dropdown' => true` attribute:
  193. .. code-block:: php
  194. <?php
  195. // src/AppBundle/Admin/PersonAdmin.php
  196. protected function configureTabMenu(MenuItemInterface $menu, $action, AdminInterface $childAdmin = null)
  197. {
  198. // other tab menu stuff ...
  199. $menu->addChild('comments', array('attributes' => array('dropdown' => true)));
  200. $menu['comments']->addChild('list', array('uri' => $admin->generateUrl('listComment', array('id' => $id))));
  201. $menu['comments']->addChild('create', array('uri' => $admin->generateUrl('addComment', array('id' => $id))));
  202. }
  203. If you want to use the Tab Menu in a different way, you can replace the Menu Template:
  204. .. configuration-block::
  205. .. code-block:: yaml
  206. # app/config/config.yml
  207. sonata_admin:
  208. templates:
  209. tab_menu_template: AppBundle:Admin:own_tab_menu_template.html.twig
  210. Disable content stretching
  211. --------------------------
  212. You can disable ``html``, ``body`` and ``sidebar`` elements stretching. These containers are forced
  213. to be full height by default. If you use custom layout or just don't need such behavior,
  214. add ``no-stretch`` class to the ``<html>`` tag.
  215. For example:
  216. .. code-block:: html+jinja
  217. {# src/AppBundle/Resources/views/standard_layout.html.twig #}
  218. {% block html_attributes %}class="no-js no-stretch"{% endblock %}
  219. Custom Action Access Management
  220. -------------------------------
  221. You can customize the access system inside the CRUDController by adding some entries inside the `$accessMapping` array in the linked Admin.
  222. .. code-block:: php
  223. <?php
  224. // src/AppBundle/Admin/PostAdmin.php
  225. class CustomAdmin extends Admin
  226. {
  227. protected $accessMapping = array(
  228. 'myCustomFoo' => 'EDIT',
  229. 'myCustomBar' => array('EDIT', 'LIST'),
  230. );
  231. }
  232. <?php
  233. // src/AppBundle/Controller/CustomCRUDController.php
  234. class CustomCRUDController extends CRUDController
  235. {
  236. public function myCustomFooAction()
  237. {
  238. $this->admin->checkAccess('myCustomFoo');
  239. // If you can't access to EDIT role for the linked admin, an AccessDeniedException will be thrown
  240. // ...
  241. }
  242. public function myCustomBarAction($object)
  243. {
  244. $this->admin->checkAccess('myCustomBar', $object);
  245. // If you can't access to EDIT AND LIST roles for the linked admin, an AccessDeniedException will be thrown
  246. // ...
  247. }
  248. // ...
  249. }
  250. You can also fully customize how you want to handle your access management by simply overriding ``checkAccess`` function
  251. .. code-block:: php
  252. <?php
  253. // src/AppBundle/Admin/CustomAdmin.php
  254. class CustomAdmin extends Admin
  255. {
  256. public function checkAccess($action, $object = null)
  257. {
  258. $this->customAccessLogic();
  259. }
  260. // ...
  261. }