SonataUserExtension.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. <?php
  2. /*
  3. * This file is part of the Sonata Project package.
  4. *
  5. * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Sonata\UserBundle\DependencyInjection;
  11. use Sonata\EasyExtendsBundle\Mapper\DoctrineCollector;
  12. use Symfony\Component\Config\Definition\Processor;
  13. use Symfony\Component\Config\FileLocator;
  14. use Symfony\Component\DependencyInjection\ContainerBuilder;
  15. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  16. use Symfony\Component\DependencyInjection\Reference;
  17. use Symfony\Component\HttpKernel\DependencyInjection\Extension;
  18. /**
  19. * @author Thomas Rabaix <thomas.rabaix@sonata-project.org>
  20. */
  21. class SonataUserExtension extends Extension
  22. {
  23. /**
  24. * {@inheritdoc}
  25. */
  26. public function load(array $configs, ContainerBuilder $container)
  27. {
  28. $processor = new Processor();
  29. $configuration = new Configuration();
  30. $config = $processor->processConfiguration($configuration, $configs);
  31. $config = $this->fixImpersonating($config);
  32. $bundles = $container->getParameter('kernel.bundles');
  33. $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
  34. if (isset($bundles['SonataAdminBundle'])) {
  35. $loader->load('admin.xml');
  36. $loader->load(sprintf('admin_%s.xml', $config['manager_type']));
  37. }
  38. $loader->load(sprintf('%s.xml', $config['manager_type']));
  39. $this->aliasManagers($container, $config['manager_type']);
  40. $loader->load('block.xml');
  41. $loader->load('menu.xml');
  42. $loader->load('form.xml');
  43. $loader->load('google_authenticator.xml');
  44. $loader->load('twig.xml');
  45. if ('orm' === $config['manager_type'] && isset(
  46. $bundles['FOSRestBundle'],
  47. $bundles['NelmioApiDocBundle'],
  48. $bundles['JMSSerializerBundle']
  49. )) {
  50. $loader->load('serializer.xml');
  51. $loader->load('api_form.xml');
  52. $loader->load('api_controllers.xml');
  53. }
  54. if (isset($bundles['SonataSeoBundle'])) {
  55. $loader->load('seo_block.xml');
  56. }
  57. if ($config['security_acl']) {
  58. $loader->load('security_acl.xml');
  59. }
  60. $config = $this->addDefaults($config);
  61. // Set the SecurityContext for Symfony <2.6
  62. // NEXT_MAJOR: Go back to simple xml configuration when bumping requirements to SF 2.6+
  63. if (interface_exists('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')) {
  64. $tokenStorageReference = new Reference('security.token_storage');
  65. $authorizationCheckerReference = new Reference('security.authorization_checker');
  66. } else {
  67. $tokenStorageReference = new Reference('security.context');
  68. $authorizationCheckerReference = new Reference('security.context');
  69. }
  70. // NEXT_MAJOR: Remove following lines.
  71. $profileFormDefinition = $container->getDefinition('sonata.user.profile.form');
  72. $registrationFormDefinition = $container->getDefinition('sonata.user.registration.form');
  73. if (method_exists($profileFormDefinition, 'setFactory')) {
  74. $profileFormDefinition->setFactory(array(new Reference('form.factory'), 'createNamed'));
  75. $registrationFormDefinition->setFactory(array(new Reference('form.factory'), 'createNamed'));
  76. } else {
  77. $profileFormDefinition->setFactoryClass(new Reference('form.factory'));
  78. $profileFormDefinition->setFactoryMethod('createNamed');
  79. $registrationFormDefinition->setFactoryClass(new Reference('form.factory'));
  80. $registrationFormDefinition->setFactoryMethod('createNamed');
  81. }
  82. if ($container->hasDefinition('sonata.user.editable_role_builder')) {
  83. $container
  84. ->getDefinition('sonata.user.editable_role_builder')
  85. ->replaceArgument(0, $tokenStorageReference)
  86. ->replaceArgument(1, $authorizationCheckerReference)
  87. ;
  88. }
  89. $container
  90. ->getDefinition('sonata.user.block.account')
  91. ->replaceArgument(2, $tokenStorageReference)
  92. ;
  93. $container
  94. ->getDefinition('sonata.user.google.authenticator.request_listener')
  95. ->replaceArgument(1, $tokenStorageReference)
  96. ;
  97. $this->registerDoctrineMapping($config);
  98. $this->configureAdminClass($config, $container);
  99. $this->configureClass($config, $container);
  100. $this->configureTranslationDomain($config, $container);
  101. $this->configureController($config, $container);
  102. // add custom form widgets
  103. $container->setParameter('twig.form.resources', array_merge(
  104. $container->getParameter('twig.form.resources'),
  105. array('SonataUserBundle:Form:form_admin_fields.html.twig')
  106. ));
  107. $container->setParameter('sonata.user.default_avatar', $config['profile']['default_avatar']);
  108. $container->setParameter('sonata.user.impersonating', $config['impersonating']);
  109. $this->configureGoogleAuthenticator($config, $container);
  110. $this->configureShortcut($container);
  111. $this->configureProfile($config, $container);
  112. $this->configureRegistration($config, $container);
  113. $this->configureMenu($config, $container);
  114. }
  115. /**
  116. * @param array $config
  117. *
  118. * @return array
  119. *
  120. * @throws \RuntimeException
  121. */
  122. public function fixImpersonating(array $config)
  123. {
  124. if (isset($config['impersonating']) && isset($config['impersonating_route'])) {
  125. throw new \RuntimeException('you can\'t have `impersonating` and `impersonating_route` keys defined at the same time');
  126. }
  127. if (isset($config['impersonating_route'])) {
  128. $config['impersonating'] = array(
  129. 'route' => $config['impersonating_route'],
  130. 'parameters' => array(),
  131. );
  132. }
  133. if (!isset($config['impersonating']['parameters'])) {
  134. $config['impersonating']['parameters'] = array();
  135. }
  136. if (!isset($config['impersonating']['route'])) {
  137. $config['impersonating'] = false;
  138. }
  139. return $config;
  140. }
  141. /**
  142. * @param array $config
  143. * @param ContainerBuilder $container
  144. *
  145. * @return mixed
  146. *
  147. * @throws \RuntimeException
  148. */
  149. public function configureGoogleAuthenticator($config, ContainerBuilder $container)
  150. {
  151. $container->setParameter('sonata.user.google.authenticator.enabled', $config['google_authenticator']['enabled']);
  152. if (!$config['google_authenticator']['enabled']) {
  153. $container->removeDefinition('sonata.user.google.authenticator');
  154. $container->removeDefinition('sonata.user.google.authenticator.provider');
  155. $container->removeDefinition('sonata.user.google.authenticator.interactive_login_listener');
  156. $container->removeDefinition('sonata.user.google.authenticator.request_listener');
  157. return;
  158. }
  159. if (!class_exists('Google\Authenticator\GoogleAuthenticator')) {
  160. throw new \RuntimeException('Please add ``sonata-project/google-authenticator`` package');
  161. }
  162. $container->getDefinition('sonata.user.google.authenticator.provider')
  163. ->replaceArgument(0, $config['google_authenticator']['server']);
  164. }
  165. /**
  166. * @param array $config
  167. *
  168. * @return array
  169. */
  170. public function addDefaults(array $config)
  171. {
  172. if ('orm' === $config['manager_type']) {
  173. $modelType = 'Entity';
  174. } elseif ('mongodb' === $config['manager_type']) {
  175. $modelType = 'Document';
  176. } else {
  177. throw new \InvalidArgumentException(sprintf('Invalid manager type "%s".', $config['manager_type']));
  178. }
  179. $defaultConfig['class']['user'] = sprintf('Application\\Sonata\\UserBundle\\%s\\User', $modelType);
  180. $defaultConfig['class']['group'] = sprintf('Application\\Sonata\\UserBundle\\%s\\Group', $modelType);
  181. $defaultConfig['admin']['user']['class'] = sprintf('Sonata\\UserBundle\\Admin\\%s\\UserAdmin', $modelType);
  182. $defaultConfig['admin']['group']['class'] = sprintf('Sonata\\UserBundle\\Admin\\%s\\GroupAdmin', $modelType);
  183. return array_replace_recursive($defaultConfig, $config);
  184. }
  185. /**
  186. * @param array $config
  187. * @param ContainerBuilder $container
  188. */
  189. public function configureClass($config, ContainerBuilder $container)
  190. {
  191. if ('orm' === $config['manager_type']) {
  192. $modelType = 'entity';
  193. } elseif ('mongodb' === $config['manager_type']) {
  194. $modelType = 'document';
  195. } else {
  196. throw new \InvalidArgumentException(sprintf('Invalid manager type "%s".', $config['manager_type']));
  197. }
  198. $container->setParameter(sprintf('sonata.user.admin.user.%s', $modelType), $config['class']['user']);
  199. $container->setParameter(sprintf('sonata.user.admin.group.%s', $modelType), $config['class']['group']);
  200. }
  201. /**
  202. * @param array $config
  203. * @param ContainerBuilder $container
  204. */
  205. public function configureAdminClass($config, ContainerBuilder $container)
  206. {
  207. $container->setParameter('sonata.user.admin.user.class', $config['admin']['user']['class']);
  208. $container->setParameter('sonata.user.admin.group.class', $config['admin']['group']['class']);
  209. }
  210. /**
  211. * @param array $config
  212. * @param ContainerBuilder $container
  213. */
  214. public function configureTranslationDomain($config, ContainerBuilder $container)
  215. {
  216. $container->setParameter('sonata.user.admin.user.translation_domain', $config['admin']['user']['translation']);
  217. $container->setParameter('sonata.user.admin.group.translation_domain', $config['admin']['group']['translation']);
  218. }
  219. /**
  220. * @param array $config
  221. * @param ContainerBuilder $container
  222. */
  223. public function configureController($config, ContainerBuilder $container)
  224. {
  225. $container->setParameter('sonata.user.admin.user.controller', $config['admin']['user']['controller']);
  226. $container->setParameter('sonata.user.admin.group.controller', $config['admin']['group']['controller']);
  227. }
  228. /**
  229. * @param array $config
  230. */
  231. public function registerDoctrineMapping(array $config)
  232. {
  233. foreach ($config['class'] as $type => $class) {
  234. if (!class_exists($class)) {
  235. return;
  236. }
  237. }
  238. $collector = DoctrineCollector::getInstance();
  239. $collector->addAssociation($config['class']['user'], 'mapManyToMany', array(
  240. 'fieldName' => 'groups',
  241. 'targetEntity' => $config['class']['group'],
  242. 'cascade' => array(),
  243. 'joinTable' => array(
  244. 'name' => $config['table']['user_group'],
  245. 'joinColumns' => array(
  246. array(
  247. 'name' => 'user_id',
  248. 'referencedColumnName' => 'id',
  249. 'onDelete' => 'CASCADE',
  250. ),
  251. ),
  252. 'inverseJoinColumns' => array(array(
  253. 'name' => 'group_id',
  254. 'referencedColumnName' => 'id',
  255. 'onDelete' => 'CASCADE',
  256. )),
  257. ),
  258. ));
  259. }
  260. /**
  261. * @param ContainerBuilder $container
  262. */
  263. public function configureShortcut(ContainerBuilder $container)
  264. {
  265. $container->setAlias('sonata.user.authentication.form', 'fos_user.profile.form');
  266. $container->setAlias('sonata.user.authentication.form_handler', 'fos_user.profile.form.handler');
  267. }
  268. /**
  269. * @param array $config
  270. * @param ContainerBuilder $container
  271. */
  272. public function configureProfile(array $config, ContainerBuilder $container)
  273. {
  274. $container->setParameter('sonata.user.profile.form.type', $config['profile']['form']['type']);
  275. $container->setParameter('sonata.user.profile.form.name', $config['profile']['form']['name']);
  276. $container->setParameter('sonata.user.profile.form.validation_groups', $config['profile']['form']['validation_groups']);
  277. $container->setParameter('sonata.user.register.confirm.redirect_route', $config['profile']['register']['confirm']['redirect']['route']);
  278. $container->setParameter('sonata.user.register.confirm.redirect_route_params', $config['profile']['register']['confirm']['redirect']['route_parameters']);
  279. $container->setParameter('sonata.user.configuration.profile_blocks', $config['profile']['dashboard']['blocks']);
  280. $container->setAlias('sonata.user.profile.form.handler', $config['profile']['form']['handler']);
  281. }
  282. /**
  283. * @param array $config
  284. * @param ContainerBuilder $container
  285. */
  286. public function configureRegistration(array $config, ContainerBuilder $container)
  287. {
  288. $bundles = $container->getParameter('kernel.bundles');
  289. if (isset($bundles['MopaBootstrapBundle'])) {
  290. $options = array(
  291. 'horizontal_input_wrapper_class' => 'col-lg-8',
  292. 'horizontal_label_class' => 'col-lg-4 control-label',
  293. );
  294. } else {
  295. $options = array();
  296. }
  297. $container->setParameter('sonata.user.registration.form.options', $options);
  298. $container->setParameter('sonata.user.registration.form.type', $config['profile']['register']['form']['type']);
  299. $container->setParameter('sonata.user.registration.form.name', $config['profile']['register']['form']['name']);
  300. $container->setParameter('sonata.user.registration.form.validation_groups', $config['profile']['register']['form']['validation_groups']);
  301. $container->setAlias('sonata.user.registration.form.handler', $config['profile']['register']['form']['handler']);
  302. }
  303. /**
  304. * @param array $config
  305. * @param ContainerBuilder $container
  306. */
  307. public function configureMenu(array $config, ContainerBuilder $container)
  308. {
  309. $container->getDefinition('sonata.user.profile.menu_builder')->replaceArgument(2, $config['profile']['menu']);
  310. }
  311. /**
  312. * Adds aliases for user & group managers depending on $managerType.
  313. *
  314. * @param ContainerBuilder $container
  315. * @param $managerType
  316. */
  317. protected function aliasManagers(ContainerBuilder $container, $managerType)
  318. {
  319. $container->setAlias('sonata.user.user_manager', sprintf('sonata.user.%s.user_manager', $managerType));
  320. $container->setAlias('sonata.user.group_manager', sprintf('sonata.user.%s.group_manager', $managerType));
  321. }
  322. }