菜谱项目

AddAnnotatedClassesToCachePass.php 4.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  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 Symfony\Component\HttpKernel\DependencyInjection;
  11. use Composer\Autoload\ClassLoader;
  12. use Symfony\Component\Debug\DebugClassLoader;
  13. use Symfony\Component\DependencyInjection\ContainerBuilder;
  14. use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
  15. use Symfony\Component\HttpKernel\Kernel;
  16. /**
  17. * Sets the classes to compile in the cache for the container.
  18. *
  19. * @author Fabien Potencier <fabien@symfony.com>
  20. */
  21. class AddAnnotatedClassesToCachePass implements CompilerPassInterface
  22. {
  23. private $kernel;
  24. public function __construct(Kernel $kernel)
  25. {
  26. $this->kernel = $kernel;
  27. }
  28. /**
  29. * {@inheritdoc}
  30. */
  31. public function process(ContainerBuilder $container)
  32. {
  33. $classes = array();
  34. $annotatedClasses = array();
  35. foreach ($container->getExtensions() as $extension) {
  36. if ($extension instanceof Extension) {
  37. if (\PHP_VERSION_ID < 70000) {
  38. $classes = array_merge($classes, $extension->getClassesToCompile());
  39. }
  40. $annotatedClasses = array_merge($annotatedClasses, $extension->getAnnotatedClassesToCompile());
  41. }
  42. }
  43. $existingClasses = $this->getClassesInComposerClassMaps();
  44. if (\PHP_VERSION_ID < 70000) {
  45. $classes = $container->getParameterBag()->resolveValue($classes);
  46. $this->kernel->setClassCache($this->expandClasses($classes, $existingClasses));
  47. }
  48. $annotatedClasses = $container->getParameterBag()->resolveValue($annotatedClasses);
  49. $this->kernel->setAnnotatedClassCache($this->expandClasses($annotatedClasses, $existingClasses));
  50. }
  51. /**
  52. * Expands the given class patterns using a list of existing classes.
  53. *
  54. * @param array $patterns The class patterns to expand
  55. * @param array $classes The existing classes to match against the patterns
  56. *
  57. * @return array A list of classes derivated from the patterns
  58. */
  59. private function expandClasses(array $patterns, array $classes)
  60. {
  61. $expanded = array();
  62. // Explicit classes declared in the patterns are returned directly
  63. foreach ($patterns as $key => $pattern) {
  64. if ('\\' !== substr($pattern, -1) && false === strpos($pattern, '*')) {
  65. unset($patterns[$key]);
  66. $expanded[] = ltrim($pattern, '\\');
  67. }
  68. }
  69. // Match patterns with the classes list
  70. $regexps = $this->patternsToRegexps($patterns);
  71. foreach ($classes as $class) {
  72. $class = ltrim($class, '\\');
  73. if ($this->matchAnyRegexps($class, $regexps)) {
  74. $expanded[] = $class;
  75. }
  76. }
  77. return array_unique($expanded);
  78. }
  79. private function getClassesInComposerClassMaps()
  80. {
  81. $classes = array();
  82. foreach (spl_autoload_functions() as $function) {
  83. if (!is_array($function)) {
  84. continue;
  85. }
  86. if ($function[0] instanceof DebugClassLoader) {
  87. $function = $function[0]->getClassLoader();
  88. }
  89. if (is_array($function) && $function[0] instanceof ClassLoader) {
  90. $classes += array_filter($function[0]->getClassMap());
  91. }
  92. }
  93. return array_keys($classes);
  94. }
  95. private function patternsToRegexps($patterns)
  96. {
  97. $regexps = array();
  98. foreach ($patterns as $pattern) {
  99. // Escape user input
  100. $regex = preg_quote(ltrim($pattern, '\\'));
  101. // Wildcards * and **
  102. $regex = strtr($regex, array('\\*\\*' => '.*?', '\\*' => '[^\\\\]*?'));
  103. // If this class does not end by a slash, anchor the end
  104. if ('\\' !== substr($regex, -1)) {
  105. $regex .= '$';
  106. }
  107. $regexps[] = '{^\\\\'.$regex.'}';
  108. }
  109. return $regexps;
  110. }
  111. private function matchAnyRegexps($class, $regexps)
  112. {
  113. $blacklisted = false !== strpos($class, 'Test');
  114. foreach ($regexps as $regex) {
  115. if ($blacklisted && false === strpos($regex, 'Test')) {
  116. continue;
  117. }
  118. if (preg_match($regex, '\\'.$class)) {
  119. return true;
  120. }
  121. }
  122. return false;
  123. }
  124. }