advanced_configuration.rst 11 KB

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