JMSDiExtraExtension.php 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <?php
  2. /*
  3. * Copyright 2011 Johannes M. Schmitt <schmittjoh@gmail.com>
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. namespace JMS\DiExtraBundle\DependencyInjection;
  18. use CG\Core\DefaultNamingStrategy;
  19. use CG\Proxy\Enhancer;
  20. use JMS\DiExtraBundle\Exception\RuntimeException;
  21. use JMS\DiExtraBundle\Generator\RepositoryInjectionGenerator;
  22. use Symfony\Component\Config\Definition\Processor;
  23. use Symfony\Component\Config\FileLocator;
  24. use Symfony\Component\DependencyInjection\Alias;
  25. use Symfony\Component\DependencyInjection\ContainerBuilder;
  26. use Symfony\Component\DependencyInjection\Definition;
  27. use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
  28. use Symfony\Component\Filesystem\Filesystem;
  29. use Symfony\Component\HttpKernel\DependencyInjection\Extension;
  30. class JMSDiExtraExtension extends Extension
  31. {
  32. public function load(array $configs, ContainerBuilder $container)
  33. {
  34. $config = $this->mergeConfigs($configs);
  35. $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
  36. $loader->load('services.xml');
  37. $container->setParameter('jms_di_extra.all_bundles', $config['locations']['all_bundles']);
  38. $container->setParameter('jms_di_extra.bundles', $config['locations']['bundles']);
  39. $container->setParameter('jms_di_extra.directories', $config['locations']['directories']);
  40. $container->setParameter('jms_di_extra.cache_dir', $config['cache_dir']);
  41. $container->setParameter('jms_di_extra.doctrine_integration', $config['doctrine_integration']);
  42. $this->configureMetadata($config['metadata'], $container, $config['cache_dir'].'/metadata');
  43. $this->configureAutomaticControllerInjections($config, $container);
  44. if ($config['doctrine_integration']) {
  45. $this->generateEntityManagerProxyClass($config, $container);
  46. }
  47. $this->addClassesToCompile(array(
  48. 'JMS\\DiExtraBundle\\HttpKernel\ControllerResolver',
  49. ));
  50. }
  51. private function generateEntityManagerProxyClass(array $config, ContainerBuilder $container)
  52. {
  53. $cacheDir = $container->getParameterBag()->resolveValue($config['cache_dir']);
  54. if (!is_dir($cacheDir.'/doctrine')) {
  55. if (false === @mkdir($cacheDir.'/doctrine', 0777, true)) {
  56. throw new \RuntimeException(sprintf('Could not create cache directory "%s".', $cacheDir.'/doctrine'));
  57. }
  58. }
  59. $enhancer = new Enhancer($ref = new \ReflectionClass('Doctrine\ORM\EntityManager'), array(), array(new RepositoryInjectionGenerator()));
  60. $uniqid = uniqid(); // We do have to use a non-static id to avoid problems with cache:clear.
  61. $enhancer->setNamingStrategy(new DefaultNamingStrategy('EntityManager'.$uniqid));
  62. $enhancer->writeClass($file = $cacheDir.'/doctrine/EntityManager_'.$uniqid.'.php');
  63. $container->setParameter('jms_di_extra.doctrine_integration.entity_manager.file', $file);
  64. $container->setParameter('jms_di_extra.doctrine_integration.entity_manager.class', $enhancer->getClassName($ref));
  65. }
  66. private function configureAutomaticControllerInjections(array $config, ContainerBuilder $container)
  67. {
  68. if (!isset($config['automatic_controller_injections'])) {
  69. $container->setAlias('jms_di_extra.metadata_driver', 'jms_di_extra.metadata.driver.annotation_driver');
  70. return;
  71. }
  72. $propertyInjections = array();
  73. foreach ($config['automatic_controller_injections']['properties'] as $name => $value) {
  74. $propertyInjections[$name] = $this->convertValue($value);
  75. }
  76. $methodInjections = array();
  77. foreach ($config['automatic_controller_injections']['method_calls'] as $name => $args) {
  78. foreach ($args as $i => $arg) {
  79. $args[$i] = $this->convertValue($arg);
  80. }
  81. $methodInjections[$name] = $args;
  82. }
  83. $container->getDefinition('jms_di_extra.metadata.driver.configured_controller_injections')
  84. ->addArgument($propertyInjections)
  85. ->addArgument($methodInjections);
  86. }
  87. private function convertValue($value)
  88. {
  89. if (is_string($value) && '@' === $value[0]) {
  90. $def = new Definition('Symfony\Component\DependencyInjection\Reference');
  91. $def->addArgument(substr($value, 1));
  92. return $def;
  93. }
  94. return $value;
  95. }
  96. private function configureMetadata(array $config, $container, $cacheDir)
  97. {
  98. if ('none' === $config['cache']) {
  99. $container->removeAlias('jms_di_extra.metadata.cache');
  100. return;
  101. }
  102. if ('file' === $config['cache']) {
  103. $cacheDir = $container->getParameterBag()->resolveValue($cacheDir);
  104. // clear the cache if container is re-build, needed for correct controller injections
  105. $fs = new Filesystem();
  106. $fs->remove($cacheDir);
  107. if (!file_exists($cacheDir)) {
  108. if (false === @mkdir($cacheDir, 0777, true)) {
  109. throw new RuntimeException(sprintf('The cache dir "%s" could not be created.', $cacheDir));
  110. }
  111. }
  112. if (!is_writable($cacheDir)) {
  113. throw new RuntimeException(sprintf('The cache dir "%s" is not writable.', $cacheDir));
  114. }
  115. $container
  116. ->getDefinition('jms_di_extra.metadata.cache.file_cache')
  117. ->replaceArgument(0, $cacheDir)
  118. ;
  119. } else {
  120. $container->setAlias('jms_di_extra.metadata.cache', new Alias($config['cache'], false));
  121. }
  122. }
  123. private function mergeConfigs(array $configs)
  124. {
  125. $processor = new Processor();
  126. $configuration = new Configuration();
  127. return $processor->process($configuration->getConfigTreeBuilder()->buildTree(), $configs);
  128. }
  129. }