annotate vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@14 1 <?php
Chris@14 2
Chris@14 3 /*
Chris@14 4 * This file is part of the Symfony package.
Chris@14 5 *
Chris@14 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@14 7 *
Chris@14 8 * For the full copyright and license information, please view the LICENSE
Chris@14 9 * file that was distributed with this source code.
Chris@14 10 */
Chris@14 11
Chris@14 12 namespace Symfony\Component\HttpKernel\DependencyInjection;
Chris@14 13
Chris@14 14 use Composer\Autoload\ClassLoader;
Chris@14 15 use Symfony\Component\Debug\DebugClassLoader;
Chris@17 16 use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
Chris@14 17 use Symfony\Component\DependencyInjection\ContainerBuilder;
Chris@14 18 use Symfony\Component\HttpKernel\Kernel;
Chris@14 19
Chris@14 20 /**
Chris@14 21 * Sets the classes to compile in the cache for the container.
Chris@14 22 *
Chris@14 23 * @author Fabien Potencier <fabien@symfony.com>
Chris@14 24 */
Chris@14 25 class AddAnnotatedClassesToCachePass implements CompilerPassInterface
Chris@14 26 {
Chris@14 27 private $kernel;
Chris@14 28
Chris@14 29 public function __construct(Kernel $kernel)
Chris@14 30 {
Chris@14 31 $this->kernel = $kernel;
Chris@14 32 }
Chris@14 33
Chris@14 34 /**
Chris@14 35 * {@inheritdoc}
Chris@14 36 */
Chris@14 37 public function process(ContainerBuilder $container)
Chris@14 38 {
Chris@17 39 $classes = [];
Chris@17 40 $annotatedClasses = [];
Chris@14 41 foreach ($container->getExtensions() as $extension) {
Chris@14 42 if ($extension instanceof Extension) {
Chris@14 43 if (\PHP_VERSION_ID < 70000) {
Chris@14 44 $classes = array_merge($classes, $extension->getClassesToCompile());
Chris@14 45 }
Chris@14 46 $annotatedClasses = array_merge($annotatedClasses, $extension->getAnnotatedClassesToCompile());
Chris@14 47 }
Chris@14 48 }
Chris@14 49
Chris@14 50 $existingClasses = $this->getClassesInComposerClassMaps();
Chris@14 51
Chris@14 52 if (\PHP_VERSION_ID < 70000) {
Chris@14 53 $classes = $container->getParameterBag()->resolveValue($classes);
Chris@14 54 $this->kernel->setClassCache($this->expandClasses($classes, $existingClasses));
Chris@14 55 }
Chris@14 56 $annotatedClasses = $container->getParameterBag()->resolveValue($annotatedClasses);
Chris@14 57 $this->kernel->setAnnotatedClassCache($this->expandClasses($annotatedClasses, $existingClasses));
Chris@14 58 }
Chris@14 59
Chris@14 60 /**
Chris@14 61 * Expands the given class patterns using a list of existing classes.
Chris@14 62 *
Chris@14 63 * @param array $patterns The class patterns to expand
Chris@14 64 * @param array $classes The existing classes to match against the patterns
Chris@14 65 *
Chris@17 66 * @return array A list of classes derived from the patterns
Chris@14 67 */
Chris@14 68 private function expandClasses(array $patterns, array $classes)
Chris@14 69 {
Chris@17 70 $expanded = [];
Chris@14 71
Chris@14 72 // Explicit classes declared in the patterns are returned directly
Chris@14 73 foreach ($patterns as $key => $pattern) {
Chris@14 74 if ('\\' !== substr($pattern, -1) && false === strpos($pattern, '*')) {
Chris@14 75 unset($patterns[$key]);
Chris@14 76 $expanded[] = ltrim($pattern, '\\');
Chris@14 77 }
Chris@14 78 }
Chris@14 79
Chris@14 80 // Match patterns with the classes list
Chris@14 81 $regexps = $this->patternsToRegexps($patterns);
Chris@14 82
Chris@14 83 foreach ($classes as $class) {
Chris@14 84 $class = ltrim($class, '\\');
Chris@14 85
Chris@14 86 if ($this->matchAnyRegexps($class, $regexps)) {
Chris@14 87 $expanded[] = $class;
Chris@14 88 }
Chris@14 89 }
Chris@14 90
Chris@14 91 return array_unique($expanded);
Chris@14 92 }
Chris@14 93
Chris@14 94 private function getClassesInComposerClassMaps()
Chris@14 95 {
Chris@17 96 $classes = [];
Chris@14 97
Chris@14 98 foreach (spl_autoload_functions() as $function) {
Chris@17 99 if (!\is_array($function)) {
Chris@14 100 continue;
Chris@14 101 }
Chris@14 102
Chris@14 103 if ($function[0] instanceof DebugClassLoader) {
Chris@14 104 $function = $function[0]->getClassLoader();
Chris@14 105 }
Chris@14 106
Chris@17 107 if (\is_array($function) && $function[0] instanceof ClassLoader) {
Chris@14 108 $classes += array_filter($function[0]->getClassMap());
Chris@14 109 }
Chris@14 110 }
Chris@14 111
Chris@14 112 return array_keys($classes);
Chris@14 113 }
Chris@14 114
Chris@14 115 private function patternsToRegexps($patterns)
Chris@14 116 {
Chris@17 117 $regexps = [];
Chris@14 118
Chris@14 119 foreach ($patterns as $pattern) {
Chris@14 120 // Escape user input
Chris@14 121 $regex = preg_quote(ltrim($pattern, '\\'));
Chris@14 122
Chris@14 123 // Wildcards * and **
Chris@17 124 $regex = strtr($regex, ['\\*\\*' => '.*?', '\\*' => '[^\\\\]*?']);
Chris@14 125
Chris@14 126 // If this class does not end by a slash, anchor the end
Chris@14 127 if ('\\' !== substr($regex, -1)) {
Chris@14 128 $regex .= '$';
Chris@14 129 }
Chris@14 130
Chris@14 131 $regexps[] = '{^\\\\'.$regex.'}';
Chris@14 132 }
Chris@14 133
Chris@14 134 return $regexps;
Chris@14 135 }
Chris@14 136
Chris@14 137 private function matchAnyRegexps($class, $regexps)
Chris@14 138 {
Chris@14 139 $blacklisted = false !== strpos($class, 'Test');
Chris@14 140
Chris@14 141 foreach ($regexps as $regex) {
Chris@14 142 if ($blacklisted && false === strpos($regex, 'Test')) {
Chris@14 143 continue;
Chris@14 144 }
Chris@14 145
Chris@14 146 if (preg_match($regex, '\\'.$class)) {
Chris@14 147 return true;
Chris@14 148 }
Chris@14 149 }
Chris@14 150
Chris@14 151 return false;
Chris@14 152 }
Chris@14 153 }