annotate vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php @ 5:12f9dff5fda9 tip

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