Mercurial > hg > isophonics-drupal-site
comparison core/modules/migrate/src/Plugin/Discovery/AnnotatedClassDiscoveryAutomatedProviders.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 129ea1e6d783 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\migrate\Plugin\Discovery; | |
4 | |
5 use Doctrine\Common\Annotations\AnnotationRegistry; | |
6 use Doctrine\Common\Reflection\StaticReflectionParser as BaseStaticReflectionParser; | |
7 use Drupal\Component\Annotation\AnnotationInterface; | |
8 use Drupal\Component\Annotation\Reflection\MockFileFinder; | |
9 use Drupal\Component\ClassFinder\ClassFinder; | |
10 use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery; | |
11 use Drupal\migrate\Annotation\MultipleProviderAnnotationInterface; | |
12 | |
13 /** | |
14 * Determines providers based on a class's and its parent's namespaces. | |
15 * | |
16 * @internal | |
17 * This is a temporary solution to the fact that migration source plugins have | |
18 * more than one provider. This functionality will be moved to core in | |
19 * https://www.drupal.org/node/2786355. | |
20 */ | |
21 class AnnotatedClassDiscoveryAutomatedProviders extends AnnotatedClassDiscovery { | |
22 | |
23 /** | |
24 * A utility object that can use active autoloaders to find files for classes. | |
25 * | |
26 * @var \Doctrine\Common\Reflection\ClassFinderInterface | |
27 */ | |
28 protected $finder; | |
29 | |
30 /** | |
31 * Constructs an AnnotatedClassDiscoveryAutomatedProviders object. | |
32 * | |
33 * @param string $subdir | |
34 * Either the plugin's subdirectory, for example 'Plugin/views/filter', or | |
35 * empty string if plugins are located at the top level of the namespace. | |
36 * @param \Traversable $root_namespaces | |
37 * An object that implements \Traversable which contains the root paths | |
38 * keyed by the corresponding namespace to look for plugin implementations. | |
39 * If $subdir is not an empty string, it will be appended to each namespace. | |
40 * @param string $plugin_definition_annotation_name | |
41 * The name of the annotation that contains the plugin definition. | |
42 * Defaults to 'Drupal\Component\Annotation\Plugin'. | |
43 * @param string[] $annotation_namespaces | |
44 * Additional namespaces to scan for annotation definitions. | |
45 */ | |
46 public function __construct($subdir, \Traversable $root_namespaces, $plugin_definition_annotation_name = 'Drupal\Component\Annotation\Plugin', array $annotation_namespaces = []) { | |
47 parent::__construct($subdir, $root_namespaces, $plugin_definition_annotation_name, $annotation_namespaces); | |
48 $this->finder = new ClassFinder(); | |
49 } | |
50 | |
51 | |
52 /** | |
53 * {@inheritdoc} | |
54 */ | |
55 protected function prepareAnnotationDefinition(AnnotationInterface $annotation, $class, BaseStaticReflectionParser $parser = NULL) { | |
56 if (!($annotation instanceof MultipleProviderAnnotationInterface)) { | |
57 throw new \LogicException('AnnotatedClassDiscoveryAutomatedProviders annotations must implement \Drupal\migrate\Annotation\MultipleProviderAnnotationInterface'); | |
58 } | |
59 $annotation->setClass($class); | |
60 $providers = $annotation->getProviders(); | |
61 // Loop through all the parent classes and add their providers (which we | |
62 // infer by parsing their namespaces) to the $providers array. | |
63 do { | |
64 $providers[] = $this->getProviderFromNamespace($parser->getNamespaceName()); | |
65 } while ($parser = StaticReflectionParser::getParentParser($parser, $this->finder)); | |
66 $providers = array_unique(array_filter($providers, function ($provider) { | |
67 return $provider && $provider !== 'component'; | |
68 })); | |
69 $annotation->setProviders($providers); | |
70 } | |
71 | |
72 /** | |
73 * {@inheritdoc} | |
74 */ | |
75 public function getDefinitions() { | |
76 $definitions = []; | |
77 | |
78 $reader = $this->getAnnotationReader(); | |
79 | |
80 // Clear the annotation loaders of any previous annotation classes. | |
81 AnnotationRegistry::reset(); | |
82 // Register the namespaces of classes that can be used for annotations. | |
83 AnnotationRegistry::registerLoader('class_exists'); | |
84 | |
85 // Search for classes within all PSR-0 namespace locations. | |
86 foreach ($this->getPluginNamespaces() as $namespace => $dirs) { | |
87 foreach ($dirs as $dir) { | |
88 if (file_exists($dir)) { | |
89 $iterator = new \RecursiveIteratorIterator( | |
90 new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS) | |
91 ); | |
92 foreach ($iterator as $fileinfo) { | |
93 if ($fileinfo->getExtension() == 'php') { | |
94 if ($cached = $this->fileCache->get($fileinfo->getPathName())) { | |
95 if (isset($cached['id'])) { | |
96 // Explicitly unserialize this to create a new object instance. | |
97 $definitions[$cached['id']] = unserialize($cached['content']); | |
98 } | |
99 continue; | |
100 } | |
101 | |
102 $sub_path = $iterator->getSubIterator()->getSubPath(); | |
103 $sub_path = $sub_path ? str_replace(DIRECTORY_SEPARATOR, '\\', $sub_path) . '\\' : ''; | |
104 $class = $namespace . '\\' . $sub_path . $fileinfo->getBasename('.php'); | |
105 | |
106 // The filename is already known, so there is no need to find the | |
107 // file. However, StaticReflectionParser needs a finder, so use a | |
108 // mock version. | |
109 $finder = MockFileFinder::create($fileinfo->getPathName()); | |
110 $parser = new BaseStaticReflectionParser($class, $finder, FALSE); | |
111 | |
112 /** @var $annotation \Drupal\Component\Annotation\AnnotationInterface */ | |
113 if ($annotation = $reader->getClassAnnotation($parser->getReflectionClass(), $this->pluginDefinitionAnnotationName)) { | |
114 $this->prepareAnnotationDefinition($annotation, $class, $parser); | |
115 | |
116 $id = $annotation->getId(); | |
117 $content = $annotation->get(); | |
118 $definitions[$id] = $content; | |
119 // Explicitly serialize this to create a new object instance. | |
120 $this->fileCache->set($fileinfo->getPathName(), ['id' => $id, 'content' => serialize($content)]); | |
121 } | |
122 else { | |
123 // Store a NULL object, so the file is not reparsed again. | |
124 $this->fileCache->set($fileinfo->getPathName(), [NULL]); | |
125 } | |
126 } | |
127 } | |
128 } | |
129 } | |
130 } | |
131 | |
132 // Don't let annotation loaders pile up. | |
133 AnnotationRegistry::reset(); | |
134 | |
135 return $definitions; | |
136 } | |
137 | |
138 } |