PageRenderTime 65ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/docs/reference/advanced_configuration.rst

http://github.com/sonata-project/SonataAdminBundle
ReStructuredText | 453 lines | 342 code | 111 blank | 0 comment | 0 complexity | 2cb9e8f31c66b23a1c1869fe2a763081 MD5 | raw file
Possible License(s): JSON, Apache-2.0, MIT
  1. Advanced configuration
  2. ======================
  3. Service Configuration
  4. ---------------------
  5. When you create a new Admin service you can configure its dependencies,
  6. the services which are injected by default are:
  7. ========================= ===================================================================
  8. Dependencies Service ID
  9. ========================= ===================================================================
  10. model_manager sonata.admin.manager.%manager-type%
  11. form_contractor sonata.admin.builder.%manager-type%_form
  12. show_builder sonata.admin.builder.%manager-type%_show
  13. list_builder sonata.admin.builder.%manager-type%_list
  14. datagrid_builder sonata.admin.builder.%manager-type%_datagrid
  15. translator translator
  16. configuration_pool sonata.admin.pool
  17. router router
  18. validator validator
  19. security_handler sonata.admin.security.handler
  20. menu_factory knp_menu.factory
  21. route_builder sonata.admin.route.path_info | sonata.admin.route.path_info_slashes
  22. label_translator_strategy sonata.admin.label.strategy.form_component
  23. ========================= ===================================================================
  24. .. note::
  25. ``%manager-type%`` is to be replaced by the manager type (orm, doctrine_mongodb...),
  26. and the default route_builder depends on it.
  27. You have 2 ways of defining the dependencies inside your services config file
  28. (``services.xml`` or ``services.yaml``):
  29. With a tag attribute (less verbose)
  30. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  31. .. configuration-block::
  32. .. code-block:: yaml
  33. # config/services.yaml
  34. app.admin.project:
  35. class: App\Admin\ProjectAdmin
  36. arguments:
  37. - ~
  38. - App\Entity\Project
  39. - ~
  40. tags:
  41. -
  42. name: sonata.admin
  43. manager_type: orm
  44. group: 'Project'
  45. label: 'Project'
  46. label_translator_strategy: 'sonata.admin.label.strategy.native'
  47. route_builder: 'sonata.admin.route.path_info'
  48. .. code-block:: xml
  49. <!-- config/services.xml -->
  50. <service id="app.admin.project" class="App\Admin\ProjectAdmin">
  51. <argument/>
  52. <argument>App\Entity\Project</argument>
  53. <argument/>
  54. <tag
  55. name="sonata.admin"
  56. manager_type="orm"
  57. group="Project"
  58. label="Project"
  59. label_translator_strategy="sonata.admin.label.strategy.native"
  60. route_builder="sonata.admin.route.path_info"
  61. />
  62. </service>
  63. With a method call (more verbose)
  64. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  65. .. configuration-block::
  66. .. code-block:: yaml
  67. # config/services.yaml
  68. app.admin.project:
  69. class: App\Admin\ProjectAdmin
  70. arguments:
  71. - ~
  72. - App\Entity\Project
  73. - ~
  74. calls:
  75. - [setLabelTranslatorStrategy, ['@sonata.admin.label.strategy.native']]
  76. - [setRouteBuilder, ['@sonata.admin.route.path_info']]
  77. tags:
  78. - { name: sonata.admin, manager_type: orm, group: 'Project', label: 'Project' }
  79. .. code-block:: xml
  80. <!-- config/services.xml -->
  81. <service id="app.admin.project" class="App\Admin\ProjectAdmin">
  82. <argument/>
  83. <argument>App\Entity\Project</argument>
  84. <argument/>
  85. <call method="setLabelTranslatorStrategy">
  86. <argument type="service" id="sonata.admin.label.strategy.native"/>
  87. </call>
  88. <call method="setRouteBuilder">
  89. <argument type="service" id="sonata.admin.route.path_info"/>
  90. </call>
  91. <tag name="sonata.admin" manager_type="orm" group="Project" label="Project"/>
  92. </service>
  93. If you want to modify the service that is going to be injected, add the following code to your
  94. application's config file:
  95. .. configuration-block::
  96. .. code-block:: yaml
  97. # config/packages/sonata_admin.yaml
  98. admins:
  99. sonata_admin:
  100. sonata.order.admin.order: # id of the admin service this setting is for
  101. model_manager: # dependency name, from the table above
  102. sonata.order.admin.order.manager # customised service id
  103. Creating a custom RouteBuilder
  104. ------------------------------
  105. To create your own RouteBuilder create the PHP class and register it as a service::
  106. namespace App\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 AdminInterface $admin
  115. * @param RouteCollection $collection
  116. */
  117. public function build(AdminInterface $admin, RouteCollection $collection)
  118. {
  119. parent::build($admin, $collection);
  120. $collection->add('yourSubAction');
  121. // The 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. .. configuration-block::
  128. .. code-block:: yaml
  129. # config/services.yaml
  130. services:
  131. app.admin.entity_route_builder:
  132. class: App\Route\EntityRouterBuilder
  133. arguments:
  134. - '@sonata.admin.audit.manager'
  135. .. code-block:: xml
  136. <!-- config/services.xml -->
  137. <service id="app.admin.entity_route_builder" class="App\Route\EntityRouterBuilder">
  138. <argument type="service" id="sonata.admin.audit.manager"/>
  139. </service>
  140. Inherited classes
  141. -----------------
  142. You can manage inherited classes by injecting subclasses using the service configuration.
  143. Lets consider a base class named `Person` and its subclasses `Student` and `Teacher`:
  144. .. configuration-block::
  145. .. code-block:: yaml
  146. # config/services.yaml
  147. app.admin.person:
  148. class: App\Admin\PersonAdmin
  149. arguments:
  150. - ~
  151. - App\Entity\Person
  152. - ~
  153. calls:
  154. -
  155. - setSubClasses
  156. -
  157. student: App\Entity\Student
  158. teacher: App\Entity\Teacher
  159. tags:
  160. - { name: sonata.admin, manager_type: orm, group: "admin", label: "Person" }
  161. .. code-block:: xml
  162. <!-- config/services.xml -->
  163. <service id="app.admin.person" class="App\Admin\PersonAdmin">
  164. <argument/>
  165. <argument>App\Entity\Person</argument>
  166. <argument></argument>
  167. <call method="setSubClasses">
  168. <argument type="collection">
  169. <argument key="student">App\Entity\Student</argument>
  170. <argument key="teacher">App\Entity\Teacher</argument>
  171. </argument>
  172. </call>
  173. <tag name="sonata.admin" manager_type="orm" group="admin" label="Person"/>
  174. </service>
  175. You will need to change the way forms are configured in order to
  176. take into account these new subclasses::
  177. // src/Admin/PersonAdmin.php
  178. protected function configureFormFields(FormMapper $formMapper)
  179. {
  180. $subject = $this->getSubject();
  181. $formMapper
  182. ->add('name')
  183. ;
  184. if ($subject instanceof Teacher) {
  185. $formMapper->add('course', 'text');
  186. }
  187. elseif ($subject instanceof Student) {
  188. $formMapper->add('year', 'integer');
  189. }
  190. }
  191. Tab Menu
  192. --------
  193. ACL
  194. ^^^
  195. Though the route linked by a menu may be protected the Tab Menu will not automatically check the ACl for you.
  196. The link will still appear unless you manually check it using the `hasAccess` method::
  197. protected function configureTabMenu(MenuItemInterface $menu, $action, AdminInterface $childAdmin = null)
  198. {
  199. // Link will always appear even if it is protected by ACL
  200. $menu->addChild($this->trans('Show'), [
  201. 'uri' => $admin->generateUrl('show', ['id' => $id])
  202. ]);
  203. // Link will only appear if access to ACL protected URL is granted
  204. if ($this->hasAccess('edit')) {
  205. $menu->addChild($this->trans('Edit'), [
  206. 'uri' => $admin->generateUrl('edit', ['id' => $id])
  207. ]);
  208. }
  209. }
  210. Dropdowns
  211. ^^^^^^^^^
  212. You can use dropdowns inside the Tab Menu by default. This can be achieved by using
  213. the `'dropdown' => true` attribute::
  214. // src/Admin/PersonAdmin.php
  215. protected function configureTabMenu(MenuItemInterface $menu, $action, AdminInterface $childAdmin = null)
  216. {
  217. // other tab menu stuff ...
  218. $menu->addChild('comments', ['attributes' => ['dropdown' => true]]);
  219. $menu['comments']->addChild('list', [
  220. 'uri' => $admin->generateUrl('listComment', ['id' => $id])
  221. ]);
  222. $menu['comments']->addChild('create', [
  223. 'uri' => $admin->generateUrl('addComment', ['id' => $id])
  224. ]);
  225. }
  226. If you want to use the Tab Menu in a different way, you can replace the Menu Template:
  227. .. configuration-block::
  228. .. code-block:: yaml
  229. # config/packages/sonata_admin.yaml
  230. sonata_admin:
  231. templates:
  232. tab_menu_template: "@App/Admin/own_tab_menu_template.html.twig"
  233. Translations
  234. ^^^^^^^^^^^^
  235. The translation parameters and domain can be customised by using the
  236. ``translation_domain`` and ``translation_parameters`` keys of the extra array
  237. of data associated with the item, respectively::
  238. $menuItem->setExtras([
  239. 'translation_parameters' => ['myparam' => 'myvalue'],
  240. 'translation_domain' => 'My domain',
  241. ]);
  242. You can also set the translation domain on the menu root, and children will
  243. inherit it::
  244. $menu->setExtra('translation_domain', 'My domain');
  245. Filter parameters
  246. ^^^^^^^^^^^^^^^^^
  247. You can add or override filter parameters to the Tab Menu::
  248. use Knp\Menu\ItemInterface as MenuItemInterface;
  249. use Sonata\AdminBundle\Admin\AbstractAdmin;
  250. use Sonata\AdminBundle\Admin\AdminInterface;
  251. use Sonata\Form\Type\EqualType;
  252. final class DeliveryAdmin extends AbstractAdmin
  253. {
  254. protected function configureTabMenu(MenuItemInterface $menu, $action, AdminInterface $childAdmin = null)
  255. {
  256. if (!$childAdmin && !in_array($action, ['edit', 'show', 'list'])) {
  257. return;
  258. }
  259. if ($action == 'list') {
  260. // Get current filter parameters
  261. $filterParameters = $this->getFilterParameters();
  262. // Add or override filter parameters
  263. $filterParameters['status'] = [
  264. 'type' => EqualType::TYPE_IS_EQUAL, // => 1
  265. 'value' => Delivery::STATUS_OPEN,
  266. ];
  267. // Add filters to uri of tab
  268. $menu->addChild('List open deliveries', [
  269. 'uri' => $this->generateUrl('list', ['filter' => $filterParameters])
  270. ]);
  271. return;
  272. }
  273. }
  274. }
  275. The `Delivery` class is based on the `sonata_type_translatable_choice` example inside the `Core's documentation`_.
  276. Actions Menu
  277. ------------
  278. You can add custom items to the actions menu for a specific action by
  279. overriding the following method::
  280. public function configureActionButtons(AdminInterface $admin, $list, $action, $object)
  281. {
  282. if (in_array($action, ['show', 'edit', 'acl']) && $object) {
  283. $list['custom'] = [
  284. 'template' => '@App/Button/custom_button.html.twig',
  285. ];
  286. }
  287. // Remove history action
  288. unset($list['history']);
  289. return $list;
  290. }
  291. .. figure:: ../images/custom_action_buttons.png
  292. :align: center
  293. :alt: Custom action buttons
  294. Disable content stretching
  295. --------------------------
  296. You can disable ``html``, ``body`` and ``sidebar`` elements stretching.
  297. These containers are forced to be full height by default. If you use a
  298. custom layout or don't need such behavior, add the ``no-stretch`` class
  299. to the ``<html>`` tag.
  300. .. code-block:: html+jinja
  301. {# templates/standard_layout.html.twig #}
  302. {% block html_attributes %}class="no-js no-stretch"{% endblock %}
  303. Custom Action Access Management
  304. -------------------------------
  305. You can customize the access system inside the CRUDController by adding
  306. some entries inside the `$accessMapping` array in the linked Admin::
  307. // src/Admin/PostAdmin.php
  308. final class CustomAdmin extends AbstractAdmin
  309. {
  310. protected $accessMapping = [
  311. 'myCustomFoo' => 'EDIT',
  312. 'myCustomBar' => ['EDIT', 'LIST'],
  313. ];
  314. }
  315. .. code-block:: php
  316. // src/Controller/CustomCRUDController.php
  317. class CustomCRUDController extends CRUDController
  318. {
  319. public function myCustomFooAction()
  320. {
  321. $this->admin->checkAccess('myCustomFoo');
  322. // If you can't access to EDIT role for the linked admin, an AccessDeniedException will be thrown
  323. // ...
  324. }
  325. public function myCustomBarAction($object)
  326. {
  327. $this->admin->checkAccess('myCustomBar', $object);
  328. // If you can't access to EDIT AND LIST roles for the linked admin, an AccessDeniedException will be thrown
  329. // ...
  330. }
  331. }
  332. You can also fully customize how you want to handle your access management
  333. by overriding ``checkAccess`` function::
  334. // src/Admin/CustomAdmin.php
  335. final class CustomAdmin extends AbstractAdmin
  336. {
  337. public function checkAccess($action, $object = null)
  338. {
  339. $this->customAccessLogic();
  340. }
  341. }
  342. .. _`Core's documentation`: http://sonata-project.org/bundles/core/master/doc/reference/form_types.html#sonata-type-translatable-choice