vendor/sonata-project/admin-bundle/src/DependencyInjection/Compiler/AddDependencyCallsCompilerPass.php line 239

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of the Sonata Project package.
  5.  *
  6.  * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
  7.  *
  8.  * For the full copyright and license information, please view the LICENSE
  9.  * file that was distributed with this source code.
  10.  */
  11. namespace Sonata\AdminBundle\DependencyInjection\Compiler;
  12. use Doctrine\Common\Inflector\Inflector;
  13. use Sonata\AdminBundle\Controller\CRUDController;
  14. use Sonata\AdminBundle\Datagrid\Pager;
  15. use Sonata\AdminBundle\Templating\TemplateRegistry;
  16. use Symfony\Component\DependencyInjection\ChildDefinition;
  17. use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
  18. use Symfony\Component\DependencyInjection\ContainerBuilder;
  19. use Symfony\Component\DependencyInjection\Definition;
  20. use Symfony\Component\DependencyInjection\Reference;
  21. /**
  22.  * Add all dependencies to the Admin class, this avoid to write too many lines
  23.  * in the configuration files.
  24.  *
  25.  * @final since sonata-project/admin-bundle 3.52
  26.  *
  27.  * @author Thomas Rabaix <thomas.rabaix@sonata-project.org>
  28.  */
  29. class AddDependencyCallsCompilerPass implements CompilerPassInterface
  30. {
  31.     public function process(ContainerBuilder $container)
  32.     {
  33.         // check if translator service exist
  34.         if (!$container->has('translator')) {
  35.             throw new \RuntimeException('The "translator" service is not yet enabled.
  36.                 It\'s required by SonataAdmin to display all labels properly.
  37.                 To learn how to enable the translator service please visit:
  38.                 http://symfony.com/doc/current/translation.html#configuration
  39.              ');
  40.         }
  41.         $parameterBag $container->getParameterBag();
  42.         $groupDefaults $admins $classes = [];
  43.         $pool $container->getDefinition('sonata.admin.pool');
  44.         foreach ($container->findTaggedServiceIds('sonata.admin') as $id => $tags) {
  45.             foreach ($tags as $attributes) {
  46.                 $definition $container->getDefinition($id);
  47.                 $parentDefinition null;
  48.                 // Temporary fix until we can support service locators
  49.                 $definition->setPublic(true);
  50.                 if ($definition instanceof ChildDefinition) {
  51.                     $parentDefinition $container->getDefinition($definition->getParent());
  52.                 }
  53.                 $this->replaceDefaultArguments([
  54.                     => $id,
  55.                     => CRUDController::class,
  56.                 ], $definition$parentDefinition);
  57.                 $this->applyConfigurationFromAttribute($definition$attributes);
  58.                 $this->applyDefaults($container$id$attributes);
  59.                 $arguments $parentDefinition ?
  60.                     array_merge($parentDefinition->getArguments(), $definition->getArguments()) :
  61.                     $definition->getArguments();
  62.                 $admins[] = $id;
  63.                 if (!isset($classes[$arguments[1]])) {
  64.                     $classes[$arguments[1]] = [];
  65.                 }
  66.                 $classes[$arguments[1]][] = $id;
  67.                 $showInDashboard = (bool) (isset($attributes['show_in_dashboard']) ? $parameterBag->resolveValue($attributes['show_in_dashboard']) : true);
  68.                 if (!$showInDashboard) {
  69.                     continue;
  70.                 }
  71.                 $resolvedGroupName = isset($attributes['group']) ?
  72.                     $parameterBag->resolveValue($attributes['group']) :
  73.                     $container->getParameter('sonata.admin.configuration.default_group');
  74.                 $labelCatalogue $attributes['label_catalogue'] ??
  75.                     $container->getParameter('sonata.admin.configuration.default_label_catalogue');
  76.                 $icon $attributes['icon'] ??
  77.                     $container->getParameter('sonata.admin.configuration.default_icon');
  78.                 $onTop $attributes['on_top'] ?? false;
  79.                 $keepOpen $attributes['keep_open'] ?? false;
  80.                 if (!isset($groupDefaults[$resolvedGroupName])) {
  81.                     $groupDefaults[$resolvedGroupName] = [
  82.                         'label' => $resolvedGroupName,
  83.                         'label_catalogue' => $labelCatalogue,
  84.                         'icon' => $icon,
  85.                         'roles' => [],
  86.                         'on_top' => false,
  87.                         'keep_open' => false,
  88.                     ];
  89.                 }
  90.                 $groupDefaults[$resolvedGroupName]['items'][] = [
  91.                     'admin' => $id,
  92.                     'label' => !empty($attributes['label']) ? $attributes['label'] : '',
  93.                     'route' => '',
  94.                     'route_params' => [],
  95.                     'route_absolute' => false,
  96.                 ];
  97.                 if (isset($groupDefaults[$resolvedGroupName]['on_top']) && $groupDefaults[$resolvedGroupName]['on_top']
  98.                     || $onTop && (\count($groupDefaults[$resolvedGroupName]['items']) > 1)) {
  99.                     throw new \RuntimeException('You can\'t use "on_top" option with multiple same name groups.');
  100.                 }
  101.                 $groupDefaults[$resolvedGroupName]['on_top'] = $onTop;
  102.                 $groupDefaults[$resolvedGroupName]['keep_open'] = $keepOpen;
  103.             }
  104.         }
  105.         $dashboardGroupsSettings $container->getParameter('sonata.admin.configuration.dashboard_groups');
  106.         if (!empty($dashboardGroupsSettings)) {
  107.             $groups $dashboardGroupsSettings;
  108.             foreach ($dashboardGroupsSettings as $groupName => $group) {
  109.                 $resolvedGroupName $parameterBag->resolveValue($groupName);
  110.                 if (!isset($groupDefaults[$resolvedGroupName])) {
  111.                     $groupDefaults[$resolvedGroupName] = [
  112.                         'items' => [],
  113.                         'label' => $resolvedGroupName,
  114.                         'roles' => [],
  115.                         'on_top' => false,
  116.                         'keep_open' => false,
  117.                     ];
  118.                 }
  119.                 if (empty($group['items'])) {
  120.                     $groups[$resolvedGroupName]['items'] = $groupDefaults[$resolvedGroupName]['items'];
  121.                 }
  122.                 if (empty($group['label'])) {
  123.                     $groups[$resolvedGroupName]['label'] = $groupDefaults[$resolvedGroupName]['label'];
  124.                 }
  125.                 if (empty($group['label_catalogue'])) {
  126.                     $groups[$resolvedGroupName]['label_catalogue'] = 'SonataAdminBundle';
  127.                 }
  128.                 if (empty($group['icon'])) {
  129.                     $groups[$resolvedGroupName]['icon'] = $groupDefaults[$resolvedGroupName]['icon'];
  130.                 }
  131.                 if (!empty($group['item_adds'])) {
  132.                     $groups[$resolvedGroupName]['items'] = array_merge($groups[$resolvedGroupName]['items'], $group['item_adds']);
  133.                 }
  134.                 if (empty($group['roles'])) {
  135.                     $groups[$resolvedGroupName]['roles'] = $groupDefaults[$resolvedGroupName]['roles'];
  136.                 }
  137.                 if (isset($groups[$resolvedGroupName]['on_top']) && !empty($group['on_top']) && $group['on_top']
  138.                     && (\count($groups[$resolvedGroupName]['items']) > 1)) {
  139.                     throw new \RuntimeException('You can\'t use "on_top" option with multiple same name groups.');
  140.                 }
  141.                 if (empty($group['on_top'])) {
  142.                     $groups[$resolvedGroupName]['on_top'] = $groupDefaults[$resolvedGroupName]['on_top'];
  143.                 }
  144.                 if (empty($group['keep_open'])) {
  145.                     $groups[$resolvedGroupName]['keep_open'] = $groupDefaults[$resolvedGroupName]['keep_open'];
  146.                 }
  147.             }
  148.         } elseif ($container->getParameter('sonata.admin.configuration.sort_admins')) {
  149.             $groups $groupDefaults;
  150.             $elementSort = static function (&$element) {
  151.                 usort(
  152.                     $element['items'],
  153.                     static function ($a$b) {
  154.                         $a = !empty($a['label']) ? $a['label'] : $a['admin'];
  155.                         $b = !empty($b['label']) ? $b['label'] : $b['admin'];
  156.                         if ($a === $b) {
  157.                             return 0;
  158.                         }
  159.                         return $a $b ? -1;
  160.                     }
  161.                 );
  162.             };
  163.             /*
  164.              * 1) sort the groups by their index
  165.              * 2) sort the elements within each group by label/admin
  166.              */
  167.             ksort($groups);
  168.             array_walk($groups$elementSort);
  169.         } else {
  170.             $groups $groupDefaults;
  171.         }
  172.         $pool->addMethodCall('setAdminServiceIds', [$admins]);
  173.         $pool->addMethodCall('setAdminGroups', [$groups]);
  174.         $pool->addMethodCall('setAdminClasses', [$classes]);
  175.         $routeLoader $container->getDefinition('sonata.admin.route_loader');
  176.         $routeLoader->replaceArgument(1$admins);
  177.     }
  178.     /**
  179.      * This method read the attribute keys and configure admin class to use the related dependency.
  180.      */
  181.     public function applyConfigurationFromAttribute(Definition $definition, array $attributes)
  182.     {
  183.         $keys = [
  184.             'model_manager',
  185.             'form_contractor',
  186.             'show_builder',
  187.             'list_builder',
  188.             'datagrid_builder',
  189.             'translator',
  190.             'configuration_pool',
  191.             'router',
  192.             'validator',
  193.             'security_handler',
  194.             'menu_factory',
  195.             'route_builder',
  196.             'label_translator_strategy',
  197.         ];
  198.         foreach ($keys as $key) {
  199.             $method 'set'.Inflector::classify($key);
  200.             if (!isset($attributes[$key]) || $definition->hasMethodCall($method)) {
  201.                 continue;
  202.             }
  203.             $definition->addMethodCall($method, [new Reference($attributes[$key])]);
  204.         }
  205.     }
  206.     /**
  207.      * Apply the default values required by the AdminInterface to the Admin service definition.
  208.      *
  209.      * @param string $serviceId
  210.      *
  211.      * @return Definition
  212.      */
  213.     public function applyDefaults(ContainerBuilder $container$serviceId, array $attributes = [])
  214.     {
  215.         $definition $container->getDefinition($serviceId);
  216.         $settings $container->getParameter('sonata.admin.configuration.admin_services');
  217.         $definition->setShared(false);
  218.         $managerType $attributes['manager_type'];
  219.         $overwriteAdminConfiguration $settings[$serviceId] ?? [];
  220.         $defaultAddServices = [
  221.             'model_manager' => sprintf('sonata.admin.manager.%s'$managerType),
  222.             'form_contractor' => sprintf('sonata.admin.builder.%s_form'$managerType),
  223.             'show_builder' => sprintf('sonata.admin.builder.%s_show'$managerType),
  224.             'list_builder' => sprintf('sonata.admin.builder.%s_list'$managerType),
  225.             'datagrid_builder' => sprintf('sonata.admin.builder.%s_datagrid'$managerType),
  226.             'translator' => 'translator',
  227.             'configuration_pool' => 'sonata.admin.pool',
  228.             'route_generator' => 'sonata.admin.route.default_generator',
  229.             'validator' => 'validator',
  230.             'security_handler' => 'sonata.admin.security.handler',
  231.             'menu_factory' => 'knp_menu.factory',
  232.             'route_builder' => 'sonata.admin.route.path_info'.
  233.                 (('doctrine_phpcr' === $managerType) ? '_slashes' ''),
  234.             'label_translator_strategy' => 'sonata.admin.label.strategy.native',
  235.         ];
  236.         $definition->addMethodCall('setManagerType', [$managerType]);
  237.         foreach ($defaultAddServices as $attr => $addServiceId) {
  238.             $method 'set'.Inflector::classify($attr);
  239.             if (isset($overwriteAdminConfiguration[$attr]) || !$definition->hasMethodCall($method)) {
  240.                 $args = [new Reference($overwriteAdminConfiguration[$attr] ?? $addServiceId)];
  241.                 if ('translator' === $attr) {
  242.                     $args[] = false;
  243.                 }
  244.                 $definition->addMethodCall($method$args);
  245.             }
  246.         }
  247.         if (isset($overwriteAdminConfiguration['pager_type'])) {
  248.             $pagerType $overwriteAdminConfiguration['pager_type'];
  249.         } elseif (isset($attributes['pager_type'])) {
  250.             $pagerType $attributes['pager_type'];
  251.         } else {
  252.             $pagerType Pager::TYPE_DEFAULT;
  253.         }
  254.         $definition->addMethodCall('setPagerType', [$pagerType]);
  255.         if (isset($overwriteAdminConfiguration['label'])) {
  256.             $label $overwriteAdminConfiguration['label'];
  257.         } elseif (isset($attributes['label'])) {
  258.             $label $attributes['label'];
  259.         } else {
  260.             $label '-';
  261.         }
  262.         $definition->addMethodCall('setLabel', [$label]);
  263.         $persistFilters $container->getParameter('sonata.admin.configuration.filters.persist');
  264.         // override default configuration with admin config if set
  265.         if (isset($attributes['persist_filters'])) {
  266.             $persistFilters $attributes['persist_filters'];
  267.         }
  268.         $filtersPersister $container->getParameter('sonata.admin.configuration.filters.persister');
  269.         // override default configuration with admin config if set
  270.         if (isset($attributes['filter_persister'])) {
  271.             $filtersPersister $attributes['filter_persister'];
  272.         }
  273.         // configure filters persistence, if configured to
  274.         if ($persistFilters) {
  275.             $definition->addMethodCall('setFilterPersister', [new Reference($filtersPersister)]);
  276.         }
  277.         if (isset($overwriteAdminConfiguration['show_mosaic_button'])) {
  278.             $showMosaicButton $overwriteAdminConfiguration['show_mosaic_button'];
  279.         } elseif (isset($attributes['show_mosaic_button'])) {
  280.             $showMosaicButton $attributes['show_mosaic_button'];
  281.         } else {
  282.             $showMosaicButton $container->getParameter('sonata.admin.configuration.show.mosaic.button');
  283.         }
  284.         $definition->addMethodCall('showMosaicButton', [$showMosaicButton]);
  285.         $this->fixTemplates(
  286.             $serviceId,
  287.             $container,
  288.             $definition,
  289.             $overwriteAdminConfiguration['templates'] ?? ['view' => []]
  290.         );
  291.         if ($container->hasParameter('sonata.admin.configuration.security.information') && !$definition->hasMethodCall('setSecurityInformation')) {
  292.             $definition->addMethodCall('setSecurityInformation', ['%sonata.admin.configuration.security.information%']);
  293.         }
  294.         $definition->addMethodCall('initialize');
  295.         return $definition;
  296.     }
  297.     /**
  298.      * @param string $serviceId
  299.      */
  300.     public function fixTemplates(
  301.         $serviceId,
  302.         ContainerBuilder $container,
  303.         Definition $definition,
  304.         array $overwrittenTemplates = []
  305.     ) {
  306.         $definedTemplates $container->getParameter('sonata.admin.configuration.templates');
  307.         $methods = [];
  308.         $pos 0;
  309.         foreach ($definition->getMethodCalls() as $method) {
  310.             if ('setTemplates' === $method[0]) {
  311.                 $definedTemplates array_merge($definedTemplates$method[1][0]);
  312.                 continue;
  313.             }
  314.             if ('setTemplate' === $method[0]) {
  315.                 $definedTemplates[$method[1][0]] = $method[1][1];
  316.                 continue;
  317.             }
  318.             // set template for simple pager if it is not already overwritten
  319.             if ('setPagerType' === $method[0]
  320.                 && Pager::TYPE_SIMPLE === $method[1][0]
  321.                 && (
  322.                     !isset($definedTemplates['pager_results'])
  323.                     || '@SonataAdmin/Pager/results.html.twig' === $definedTemplates['pager_results']
  324.                 )
  325.             ) {
  326.                 $definedTemplates['pager_results'] = '@SonataAdmin/Pager/simple_pager_results.html.twig';
  327.             }
  328.             $methods[$pos] = $method;
  329.             ++$pos;
  330.         }
  331.         $definition->setMethodCalls($methods);
  332.         $definedTemplates $overwrittenTemplates['view'] + $definedTemplates;
  333.         $templateRegistryId $serviceId.'.template_registry';
  334.         $templateRegistryDefinition $container
  335.             ->register($templateRegistryIdTemplateRegistry::class)
  336.             ->addTag('sonata.admin.template_registry')
  337.             ->setPublic(true); // Temporary fix until we can support service locators
  338.         if ($container->getParameter('sonata.admin.configuration.templates') !== $definedTemplates) {
  339.             $templateRegistryDefinition->addArgument($definedTemplates);
  340.         } else {
  341.             $templateRegistryDefinition->addArgument('%sonata.admin.configuration.templates%');
  342.         }
  343.         $definition->addMethodCall('setTemplateRegistry', [new Reference($templateRegistryId)]);
  344.     }
  345.     /**
  346.      * Replace the empty arguments required by the Admin service definition.
  347.      */
  348.     private function replaceDefaultArguments(
  349.         array $defaultArguments,
  350.         Definition $definition,
  351.         Definition $parentDefinition null
  352.     ): void {
  353.         $arguments $definition->getArguments();
  354.         $parentArguments $parentDefinition $parentDefinition->getArguments() : [];
  355.         foreach ($defaultArguments as $index => $value) {
  356.             $declaredInParent $parentDefinition && \array_key_exists($index$parentArguments);
  357.             $argumentValue $declaredInParent $parentArguments[$index] : $arguments[$index];
  358.             if (null === $argumentValue || === \strlen($argumentValue)) {
  359.                 $arguments[$declaredInParent sprintf('index_%s'$index) : $index] = $value;
  360.             }
  361.         }
  362.         $definition->setArguments($arguments);
  363.     }
  364. }