Mercurial > hg > isophonics-drupal-site
comparison core/modules/migrate/src/Plugin/MigrationPluginManager.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 1fec387a4317 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\migrate\Plugin; | |
4 | |
5 use Drupal\Component\Graph\Graph; | |
6 use Drupal\Component\Plugin\PluginBase; | |
7 use Drupal\Core\Cache\CacheBackendInterface; | |
8 use Drupal\Core\Extension\ModuleHandlerInterface; | |
9 use Drupal\Core\Language\LanguageManagerInterface; | |
10 use Drupal\Core\Plugin\DefaultPluginManager; | |
11 use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator; | |
12 use Drupal\migrate\Plugin\Discovery\ProviderFilterDecorator; | |
13 use Drupal\Core\Plugin\Discovery\YamlDirectoryDiscovery; | |
14 use Drupal\Core\Plugin\Factory\ContainerFactory; | |
15 use Drupal\migrate\MigrateBuildDependencyInterface; | |
16 | |
17 /** | |
18 * Plugin manager for migration plugins. | |
19 */ | |
20 class MigrationPluginManager extends DefaultPluginManager implements MigrationPluginManagerInterface, MigrateBuildDependencyInterface { | |
21 | |
22 /** | |
23 * Provides default values for migrations. | |
24 * | |
25 * @var array | |
26 */ | |
27 protected $defaults = [ | |
28 'class' => '\Drupal\migrate\Plugin\Migration', | |
29 ]; | |
30 | |
31 /** | |
32 * The interface the plugins should implement. | |
33 * | |
34 * @var string | |
35 */ | |
36 protected $pluginInterface = 'Drupal\migrate\Plugin\MigrationInterface'; | |
37 | |
38 /** | |
39 * The module handler. | |
40 * | |
41 * @var \Drupal\Core\Extension\ModuleHandlerInterface | |
42 */ | |
43 protected $moduleHandler; | |
44 | |
45 /** | |
46 * Construct a migration plugin manager. | |
47 * | |
48 * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler | |
49 * The module handler. | |
50 * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend | |
51 * The cache backend for the definitions. | |
52 * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager | |
53 * The language manager. | |
54 */ | |
55 public function __construct(ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager) { | |
56 $this->factory = new ContainerFactory($this, $this->pluginInterface); | |
57 $this->alterInfo('migration_plugins'); | |
58 $this->setCacheBackend($cache_backend, 'migration_plugins', ['migration_plugins']); | |
59 $this->moduleHandler = $module_handler; | |
60 } | |
61 | |
62 /** | |
63 * {@inheritdoc} | |
64 */ | |
65 protected function getDiscovery() { | |
66 if (!isset($this->discovery)) { | |
67 $directories = array_map(function ($directory) { | |
68 return [$directory . '/migration_templates', $directory . '/migrations']; | |
69 }, $this->moduleHandler->getModuleDirectories()); | |
70 | |
71 $yaml_discovery = new YamlDirectoryDiscovery($directories, 'migrate'); | |
72 // This gets rid of migrations which try to use a non-existent source | |
73 // plugin. The common case for this is if the source plugin has, or | |
74 // specifies, a non-existent provider. | |
75 $only_with_source_discovery = new NoSourcePluginDecorator($yaml_discovery); | |
76 // This gets rid of migrations with explicit providers set if one of the | |
77 // providers do not exist before we try to use a potentially non-existing | |
78 // deriver. This is a rare case. | |
79 $filtered_discovery = new ProviderFilterDecorator($only_with_source_discovery, [$this->moduleHandler, 'moduleExists']); | |
80 $this->discovery = new ContainerDerivativeDiscoveryDecorator($filtered_discovery); | |
81 } | |
82 return $this->discovery; | |
83 } | |
84 | |
85 /** | |
86 * {@inheritdoc} | |
87 */ | |
88 public function createInstance($plugin_id, array $configuration = []) { | |
89 $instances = $this->createInstances([$plugin_id], [$plugin_id => $configuration]); | |
90 return reset($instances); | |
91 } | |
92 | |
93 /** | |
94 * {@inheritdoc} | |
95 */ | |
96 public function createInstances($migration_id, array $configuration = []) { | |
97 if (empty($migration_id)) { | |
98 $migration_id = array_keys($this->getDefinitions()); | |
99 } | |
100 | |
101 $factory = $this->getFactory(); | |
102 $migration_ids = (array) $migration_id; | |
103 $plugin_ids = $this->expandPluginIds($migration_ids); | |
104 | |
105 $instances = []; | |
106 foreach ($plugin_ids as $plugin_id) { | |
107 $instances[$plugin_id] = $factory->createInstance($plugin_id, isset($configuration[$plugin_id]) ? $configuration[$plugin_id] : []); | |
108 } | |
109 | |
110 foreach ($instances as $migration) { | |
111 $migration->set('migration_dependencies', array_map([$this, 'expandPluginIds'], $migration->getMigrationDependencies())); | |
112 } | |
113 | |
114 // Sort the migrations based on their dependencies. | |
115 return $this->buildDependencyMigration($instances, []); | |
116 } | |
117 | |
118 /** | |
119 * Create migrations given a tag. | |
120 * | |
121 * @param string $tag | |
122 * A migration tag we want to filter by. | |
123 * | |
124 * @return array|\Drupal\migrate\Plugin\MigrationInterface[] | |
125 * An array of migration objects with the given tag. | |
126 */ | |
127 public function createInstancesByTag($tag) { | |
128 $migrations = array_filter($this->getDefinitions(), function ($migration) use ($tag) { | |
129 return !empty($migration['migration_tags']) && in_array($tag, $migration['migration_tags']); | |
130 }); | |
131 return $this->createInstances(array_keys($migrations)); | |
132 } | |
133 | |
134 /** | |
135 * Expand derivative migration dependencies. | |
136 * | |
137 * We need to expand any derivative migrations. Derivative migrations are | |
138 * calculated by migration derivers such as D6NodeDeriver. This allows | |
139 * migrations to depend on the base id and then have a dependency on all | |
140 * derivative migrations. For example, d6_comment depends on d6_node but after | |
141 * we've expanded the dependencies it will depend on d6_node:page, | |
142 * d6_node:story and so on, for other derivative migrations. | |
143 * | |
144 * @return array | |
145 * An array of expanded plugin ids. | |
146 */ | |
147 protected function expandPluginIds(array $migration_ids) { | |
148 $plugin_ids = []; | |
149 foreach ($migration_ids as $id) { | |
150 $plugin_ids += preg_grep('/^' . preg_quote($id, '/') . PluginBase::DERIVATIVE_SEPARATOR . '/', array_keys($this->getDefinitions())); | |
151 if ($this->hasDefinition($id)) { | |
152 $plugin_ids[] = $id; | |
153 } | |
154 } | |
155 return $plugin_ids; | |
156 } | |
157 | |
158 | |
159 /** | |
160 * {@inheritdoc} | |
161 */ | |
162 public function buildDependencyMigration(array $migrations, array $dynamic_ids) { | |
163 // Migration dependencies can be optional or required. If an optional | |
164 // dependency does not run, the current migration is still OK to go. Both | |
165 // optional and required dependencies (if run at all) must run before the | |
166 // current migration. | |
167 $dependency_graph = []; | |
168 $required_dependency_graph = []; | |
169 $have_optional = FALSE; | |
170 foreach ($migrations as $migration) { | |
171 /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */ | |
172 $id = $migration->id(); | |
173 $requirements[$id] = []; | |
174 $dependency_graph[$id]['edges'] = []; | |
175 $migration_dependencies = $migration->getMigrationDependencies(); | |
176 | |
177 if (isset($migration_dependencies['required'])) { | |
178 foreach ($migration_dependencies['required'] as $dependency) { | |
179 if (!isset($dynamic_ids[$dependency])) { | |
180 $this->addDependency($required_dependency_graph, $id, $dependency, $dynamic_ids); | |
181 } | |
182 $this->addDependency($dependency_graph, $id, $dependency, $dynamic_ids); | |
183 } | |
184 } | |
185 if (!empty($migration_dependencies['optional'])) { | |
186 foreach ($migration_dependencies['optional'] as $dependency) { | |
187 $this->addDependency($dependency_graph, $id, $dependency, $dynamic_ids); | |
188 } | |
189 $have_optional = TRUE; | |
190 } | |
191 } | |
192 $dependency_graph = (new Graph($dependency_graph))->searchAndSort(); | |
193 if ($have_optional) { | |
194 $required_dependency_graph = (new Graph($required_dependency_graph))->searchAndSort(); | |
195 } | |
196 else { | |
197 $required_dependency_graph = $dependency_graph; | |
198 } | |
199 $weights = []; | |
200 foreach ($migrations as $migration_id => $migration) { | |
201 // Populate a weights array to use with array_multisort() later. | |
202 $weights[] = $dependency_graph[$migration_id]['weight']; | |
203 if (!empty($required_dependency_graph[$migration_id]['paths'])) { | |
204 $migration->set('requirements', $required_dependency_graph[$migration_id]['paths']); | |
205 } | |
206 } | |
207 array_multisort($weights, SORT_DESC, SORT_NUMERIC, $migrations); | |
208 | |
209 return $migrations; | |
210 } | |
211 | |
212 /** | |
213 * Add one or more dependencies to a graph. | |
214 * | |
215 * @param array $graph | |
216 * The graph so far, passed by reference. | |
217 * @param int $id | |
218 * The migration ID. | |
219 * @param string $dependency | |
220 * The dependency string. | |
221 * @param array $dynamic_ids | |
222 * The dynamic ID mapping. | |
223 */ | |
224 protected function addDependency(array &$graph, $id, $dependency, $dynamic_ids) { | |
225 $dependencies = isset($dynamic_ids[$dependency]) ? $dynamic_ids[$dependency] : [$dependency]; | |
226 if (!isset($graph[$id]['edges'])) { | |
227 $graph[$id]['edges'] = []; | |
228 } | |
229 $graph[$id]['edges'] += array_combine($dependencies, $dependencies); | |
230 } | |
231 | |
232 /** | |
233 * {@inheritdoc} | |
234 */ | |
235 public function createStubMigration(array $definition) { | |
236 $id = isset($definition['id']) ? $definition['id'] : uniqid(); | |
237 return Migration::create(\Drupal::getContainer(), [], $id, $definition); | |
238 } | |
239 | |
240 /** | |
241 * Finds plugin definitions. | |
242 * | |
243 * @return array | |
244 * List of definitions to store in cache. | |
245 * | |
246 * @todo This is a temporary solution to the fact that migration source | |
247 * plugins have more than one provider. This functionality will be moved to | |
248 * core in https://www.drupal.org/node/2786355. | |
249 */ | |
250 protected function findDefinitions() { | |
251 $definitions = $this->getDiscovery()->getDefinitions(); | |
252 foreach ($definitions as $plugin_id => &$definition) { | |
253 $this->processDefinition($definition, $plugin_id); | |
254 } | |
255 $this->alterDefinitions($definitions); | |
256 return ProviderFilterDecorator::filterDefinitions($definitions, function ($provider) { | |
257 return $this->providerExists($provider); | |
258 }); | |
259 } | |
260 | |
261 } |