vendor/sonata-project/user-bundle/src/DependencyInjection/SonataUserExtension.php line 49

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\UserBundle\DependencyInjection;
  12. use Sonata\Doctrine\Mapper\Builder\OptionsBuilder;
  13. use Sonata\Doctrine\Mapper\DoctrineCollector;
  14. use Sonata\EasyExtendsBundle\Mapper\DoctrineCollector as DeprecatedDoctrineCollector;
  15. use Sonata\UserBundle\Document\BaseGroup as DocumentGroup;
  16. use Sonata\UserBundle\Document\BaseUser as DocumentUser;
  17. use Sonata\UserBundle\Entity\BaseGroup as EntityGroup;
  18. use Sonata\UserBundle\Entity\BaseUser as EntityUser;
  19. use Symfony\Component\Config\Definition\Processor;
  20. use Symfony\Component\Config\FileLocator;
  21. use Symfony\Component\DependencyInjection\ContainerBuilder;
  22. use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
  23. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  24. use Symfony\Component\HttpKernel\DependencyInjection\Extension;
  25. /**
  26.  * @author     Thomas Rabaix <thomas.rabaix@sonata-project.org>
  27.  */
  28. class SonataUserExtension extends Extension implements PrependExtensionInterface
  29. {
  30.     /**
  31.      * {@inheritdoc}
  32.      */
  33.     public function prepend(ContainerBuilder $container): void
  34.     {
  35.         if ($container->hasExtension('twig')) {
  36.             // add custom form widgets
  37.             $container->prependExtensionConfig('twig', ['form_themes' => ['@SonataUser/Form/form_admin_fields.html.twig']]);
  38.         }
  39.     }
  40.     /**
  41.      * {@inheritdoc}
  42.      */
  43.     public function load(array $configsContainerBuilder $container): void
  44.     {
  45.         $processor = new Processor();
  46.         $configuration = new Configuration();
  47.         $config $processor->processConfiguration($configuration$configs);
  48.         $config $this->fixImpersonating($config);
  49.         $bundles $container->getParameter('kernel.bundles');
  50.         $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
  51.         if (isset($bundles['SonataAdminBundle'])) {
  52.             $loader->load('admin.xml');
  53.             $loader->load(sprintf('admin_%s.xml'$config['manager_type']));
  54.         }
  55.         $loader->load(sprintf('%s.xml'$config['manager_type']));
  56.         $this->aliasManagers($container$config['manager_type']);
  57.         $loader->load('form.xml');
  58.         if (class_exists('Google\Authenticator\GoogleAuthenticator')) {
  59.             @trigger_error(
  60.                 'The \'Google\Authenticator\' namespace is deprecated in sonata-project/GoogleAuthenticator since version 2.1 and will be removed in 3.0.',
  61.                 E_USER_DEPRECATED
  62.             );
  63.         }
  64.         if (class_exists('Google\Authenticator\GoogleAuthenticator') ||
  65.             class_exists('Sonata\GoogleAuthenticator\GoogleAuthenticator')) {
  66.             $loader->load('google_authenticator.xml');
  67.         }
  68.         $loader->load('twig.xml');
  69.         $loader->load('command.xml');
  70.         $loader->load('actions.xml');
  71.         $loader->load('mailer.xml');
  72.         if ('orm' === $config['manager_type'] && isset(
  73.             $bundles['FOSRestBundle'],
  74.             $bundles['NelmioApiDocBundle'],
  75.             $bundles['JMSSerializerBundle']
  76.         )) {
  77.             $loader->load('serializer.xml');
  78.             $loader->load('api_form.xml');
  79.             $loader->load('api_controllers.xml');
  80.         }
  81.         if ($config['security_acl']) {
  82.             $loader->load('security_acl.xml');
  83.         }
  84.         $this->checkManagerTypeToModelTypesMapping($config);
  85.         if (isset($bundles['SonataDoctrineBundle'])) {
  86.             $this->registerSonataDoctrineMapping($config);
  87.         } else {
  88.             // NEXT MAJOR: Remove next line and throw error when not registering SonataDoctrineBundle
  89.             $this->registerDoctrineMapping($config);
  90.         }
  91.         $this->configureAdminClass($config$container);
  92.         $this->configureClass($config$container);
  93.         $this->configureTranslationDomain($config$container);
  94.         $this->configureController($config$container);
  95.         $this->configureMailer($config$container);
  96.         $container->setParameter('sonata.user.default_avatar'$config['profile']['default_avatar']);
  97.         $container->setParameter('sonata.user.impersonating'$config['impersonating']);
  98.         $this->configureGoogleAuthenticator($config$container);
  99.     }
  100.     /**
  101.      * @throws \RuntimeException
  102.      *
  103.      * @return array
  104.      */
  105.     public function fixImpersonating(array $config)
  106.     {
  107.         if (isset($config['impersonating'], $config['impersonating_route'])) {
  108.             throw new \RuntimeException('you can\'t have `impersonating` and `impersonating_route` keys defined at the same time');
  109.         }
  110.         if (isset($config['impersonating_route'])) {
  111.             $config['impersonating'] = [
  112.                 'route' => $config['impersonating_route'],
  113.                 'parameters' => [],
  114.             ];
  115.         }
  116.         if (!isset($config['impersonating']['parameters'])) {
  117.             $config['impersonating']['parameters'] = [];
  118.         }
  119.         if (!isset($config['impersonating']['route'])) {
  120.             $config['impersonating'] = false;
  121.         }
  122.         return $config;
  123.     }
  124.     /**
  125.      * @param array $config
  126.      *
  127.      * @throws \RuntimeException
  128.      *
  129.      * @return mixed
  130.      */
  131.     public function configureGoogleAuthenticator($configContainerBuilder $container)
  132.     {
  133.         $container->setParameter('sonata.user.google.authenticator.enabled'$config['google_authenticator']['enabled']);
  134.         if (!$config['google_authenticator']['enabled']) {
  135.             $container->removeDefinition('sonata.user.google.authenticator');
  136.             $container->removeDefinition('sonata.user.google.authenticator.provider');
  137.             $container->removeDefinition('sonata.user.google.authenticator.interactive_login_listener');
  138.             $container->removeDefinition('sonata.user.google.authenticator.request_listener');
  139.             return;
  140.         }
  141.         if (!class_exists('Google\Authenticator\GoogleAuthenticator')
  142.             && !class_exists('Sonata\GoogleAuthenticator\GoogleAuthenticator')) {
  143.             throw new \RuntimeException('Please add "sonata-project/google-authenticator" package');
  144.         }
  145.         $container->setParameter('sonata.user.google.authenticator.forced_for_role'$config['google_authenticator']['forced_for_role']);
  146.         // NEXT_MAJOR: Remove this checks and only set the `trusted_ip_list`.
  147.         if (\count($config['google_authenticator']['ip_white_list']) > && $config['google_authenticator']['trusted_ip_list'] !== ['127.0.0.1']) {
  148.             throw new \LogicException('Please use only "trusted_ip_list" parameter, "ip_white_list" is deprecated.');
  149.         }
  150.         $trustedIpList $config['google_authenticator']['trusted_ip_list'];
  151.         if (\count($config['google_authenticator']['ip_white_list']) > 0) {
  152.             $trustedIpList $config['google_authenticator']['ip_white_list'];
  153.         }
  154.         // NEXT_MAJOR: Remove `sonata.user.google.authenticator.ip_white_list` parameter.
  155.         $container->setParameter('sonata.user.google.authenticator.ip_white_list'$trustedIpList);
  156.         $container->setParameter('sonata.user.google.authenticator.trusted_ip_list'$trustedIpList);
  157.         $container->getDefinition('sonata.user.google.authenticator.provider')
  158.             ->replaceArgument(0$config['google_authenticator']['server']);
  159.     }
  160.     /**
  161.      * @param array $config
  162.      */
  163.     public function configureClass($configContainerBuilder $container): void
  164.     {
  165.         if ('orm' === $config['manager_type']) {
  166.             $modelType 'entity';
  167.         } elseif ('mongodb' === $config['manager_type']) {
  168.             $modelType 'document';
  169.         } else {
  170.             throw new \InvalidArgumentException(sprintf('Invalid manager type "%s".'$config['manager_type']));
  171.         }
  172.         $container->setParameter(sprintf('sonata.user.admin.user.%s'$modelType), $config['class']['user']);
  173.         $container->setParameter(sprintf('sonata.user.admin.group.%s'$modelType), $config['class']['group']);
  174.     }
  175.     /**
  176.      * @param array $config
  177.      */
  178.     public function configureAdminClass($configContainerBuilder $container): void
  179.     {
  180.         $container->setParameter('sonata.user.admin.user.class'$config['admin']['user']['class']);
  181.         $container->setParameter('sonata.user.admin.group.class'$config['admin']['group']['class']);
  182.     }
  183.     /**
  184.      * @param array $config
  185.      */
  186.     public function configureTranslationDomain($configContainerBuilder $container): void
  187.     {
  188.         $container->setParameter('sonata.user.admin.user.translation_domain'$config['admin']['user']['translation']);
  189.         $container->setParameter('sonata.user.admin.group.translation_domain'$config['admin']['group']['translation']);
  190.     }
  191.     /**
  192.      * @param array $config
  193.      */
  194.     public function configureController($configContainerBuilder $container): void
  195.     {
  196.         $container->setParameter('sonata.user.admin.user.controller'$config['admin']['user']['controller']);
  197.         $container->setParameter('sonata.user.admin.group.controller'$config['admin']['group']['controller']);
  198.     }
  199.     /**
  200.      * NEXT_MAJOR: Remove this method.
  201.      */
  202.     public function registerDoctrineMapping(array $config): void
  203.     {
  204.         @trigger_error(
  205.             'Using this method is deprecated since sonata-project/user-bundle 4.7. You should instead register SonataDoctrineBundle and use `registerSonataDoctrineMapping()`',
  206.             E_USER_DEPRECATED
  207.         );
  208.         foreach ($config['class'] as $type => $class) {
  209.             if (!class_exists($class)) {
  210.                 return;
  211.             }
  212.         }
  213.         $collector DeprecatedDoctrineCollector::getInstance();
  214.         $collector->addAssociation($config['class']['user'], 'mapManyToMany', [
  215.             'fieldName' => 'groups',
  216.             'targetEntity' => $config['class']['group'],
  217.             'cascade' => [],
  218.             'joinTable' => [
  219.                 'name' => $config['table']['user_group'],
  220.                 'joinColumns' => [
  221.                     [
  222.                         'name' => 'user_id',
  223.                         'referencedColumnName' => 'id',
  224.                         'onDelete' => 'CASCADE',
  225.                     ],
  226.                 ],
  227.                 'inverseJoinColumns' => [[
  228.                     'name' => 'group_id',
  229.                     'referencedColumnName' => 'id',
  230.                     'onDelete' => 'CASCADE',
  231.                 ]],
  232.             ],
  233.         ]);
  234.     }
  235.     /**
  236.      * Adds aliases for user & group managers depending on $managerType.
  237.      *
  238.      * @param string $managerType
  239.      */
  240.     protected function aliasManagers(ContainerBuilder $container$managerType): void
  241.     {
  242.         $container
  243.             ->setAlias('sonata.user.user_manager'sprintf('sonata.user.%s.user_manager'$managerType))
  244.             ->setPublic(true);
  245.         $container
  246.             ->setAlias('sonata.user.group_manager'sprintf('sonata.user.%s.group_manager'$managerType))
  247.             ->setPublic(true);
  248.     }
  249.     private function checkManagerTypeToModelTypesMapping(array $config): void
  250.     {
  251.         $managerType $config['manager_type'];
  252.         if (!\in_array($managerType, ['orm''mongodb'], true)) {
  253.             throw new \InvalidArgumentException(sprintf('Invalid manager type "%s".'$managerType));
  254.         }
  255.         $this->prohibitModelTypeMapping(
  256.             $config['class']['user'],
  257.             'orm' === $managerType DocumentUser::class : EntityUser::class,
  258.             $managerType
  259.         );
  260.         $this->prohibitModelTypeMapping(
  261.             $config['class']['group'],
  262.             'orm' === $managerType DocumentGroup::class : EntityGroup::class,
  263.             $managerType
  264.         );
  265.     }
  266.     /**
  267.      * Prohibit using wrong model type mapping.
  268.      */
  269.     private function prohibitModelTypeMapping(
  270.         string $actualModelClass,
  271.         string $prohibitedModelClass,
  272.         string $managerType
  273.     ): void {
  274.         if (is_a($actualModelClass$prohibitedModelClasstrue)) {
  275.             throw new \InvalidArgumentException(
  276.                 sprintf(
  277.                     'Model class "%s" does not correspond to manager type "%s".',
  278.                     $actualModelClass,
  279.                     $managerType
  280.                 )
  281.             );
  282.         }
  283.     }
  284.     private function configureMailer(array $configContainerBuilder $container): void
  285.     {
  286.         $container->setAlias('sonata.user.mailer'$config['mailer']);
  287.     }
  288.     private function registerSonataDoctrineMapping(array $config): void
  289.     {
  290.         foreach ($config['class'] as $type => $class) {
  291.             if (!class_exists($class)) {
  292.                 return;
  293.             }
  294.         }
  295.         $collector DoctrineCollector::getInstance();
  296.         $collector->addAssociation(
  297.             $config['class']['user'],
  298.             'mapManyToMany',
  299.             OptionsBuilder::createManyToMany('groups'$config['class']['group'])
  300.                 ->addJoinTable($config['table']['user_group'], [[
  301.                     'name' => 'user_id',
  302.                     'referencedColumnName' => 'id',
  303.                     'onDelete' => 'CASCADE',
  304.                 ]], [[
  305.                     'name' => 'group_id',
  306.                     'referencedColumnName' => 'id',
  307.                     'onDelete' => 'CASCADE',
  308.                 ]])
  309.         );
  310.     }
  311. }