1 | <?php |
||
39 | class FactoryManagerImpl implements FactoryManager |
||
40 | { |
||
41 | /** |
||
42 | * The name of the resource repository variable. |
||
43 | */ |
||
44 | const REPO_VAR_NAME = 'repo'; |
||
45 | |||
46 | /** |
||
47 | * The name of the discovery variable. |
||
48 | */ |
||
49 | const DISCOVERY_VAR_NAME = 'discovery'; |
||
50 | |||
51 | /** |
||
52 | * @var ProjectContext |
||
53 | */ |
||
54 | private $context; |
||
55 | |||
56 | /** |
||
57 | * @var Config |
||
58 | */ |
||
59 | private $config; |
||
60 | |||
61 | /** |
||
62 | * @var string |
||
63 | */ |
||
64 | private $rootDir; |
||
65 | |||
66 | /** |
||
67 | * @var GeneratorRegistry |
||
68 | */ |
||
69 | private $generatorRegistry; |
||
70 | |||
71 | /** |
||
72 | * @var ClassWriter |
||
73 | */ |
||
74 | private $classWriter; |
||
75 | |||
76 | /** |
||
77 | * @var ModuleList |
||
78 | */ |
||
79 | private $modules; |
||
80 | |||
81 | /** |
||
82 | * @var ServerCollection |
||
83 | */ |
||
84 | private $servers; |
||
85 | |||
86 | /** |
||
87 | * Creates a new factory generator. |
||
88 | * |
||
89 | * @param ProjectContext $context The project context. |
||
90 | * @param GeneratorRegistry $generatorRegistry The registry providing |
||
91 | * the generators for the |
||
92 | * services returned by the |
||
93 | * factory. |
||
94 | * @param ClassWriter $classWriter The writer that writes |
||
95 | * the class to a file. |
||
96 | * @param ModuleList|null $modules The loaded modules. |
||
97 | * @param ServerCollection|null $servers The configured servers. |
||
98 | */ |
||
99 | 44 | public function __construct(ProjectContext $context, GeneratorRegistry $generatorRegistry, ClassWriter $classWriter, ModuleList $modules = null, ServerCollection $servers = null) |
|
100 | { |
||
101 | 44 | $this->context = $context; |
|
102 | 44 | $this->config = $context->getConfig(); |
|
103 | 44 | $this->rootDir = $context->getRootDirectory(); |
|
104 | 44 | $this->generatorRegistry = $generatorRegistry; |
|
105 | 44 | $this->classWriter = $classWriter; |
|
106 | 44 | $this->modules = $modules; |
|
107 | 44 | $this->servers = $servers; |
|
108 | 44 | } |
|
109 | |||
110 | /** |
||
111 | * Sets the modules included in the getModuleOrder() method. |
||
112 | * |
||
113 | * @param ModuleList $modules The loaded modules. |
||
114 | */ |
||
115 | public function setModules(ModuleList $modules) |
||
116 | { |
||
117 | $this->modules = $modules; |
||
118 | } |
||
119 | |||
120 | /** |
||
121 | * Sets the servers included in the createUrlGenerator() method. |
||
122 | * |
||
123 | * @param ServerCollection $servers The configured servers. |
||
124 | */ |
||
125 | public function setServers(ServerCollection $servers) |
||
126 | { |
||
127 | $this->servers = $servers; |
||
128 | } |
||
129 | |||
130 | /** |
||
131 | * {@inheritdoc} |
||
132 | */ |
||
133 | 5 | public function createFactory($path = null, $className = null) |
|
134 | { |
||
135 | 5 | Assert::nullOrStringNotEmpty($path, 'The path to the generated factory file must be a non-empty string or null. Got: %s'); |
|
136 | 5 | Assert::nullOrStringNotEmpty($className, 'The class name of the generated factory must be a non-empty string or null. Got: %s'); |
|
137 | |||
138 | 5 | $this->refreshFactoryClass($path, $className); |
|
139 | |||
140 | 5 | $className = $className ?: $this->config->get(Config::FACTORY_IN_CLASS); |
|
141 | 5 | $path = $path ?: $this->config->get(Config::FACTORY_IN_FILE); |
|
142 | |||
143 | 5 | if (null !== $path && !class_exists($className, false)) { |
|
144 | 4 | require_once Path::makeAbsolute($path, $this->rootDir); |
|
145 | } |
||
146 | |||
147 | 5 | return new $className(); |
|
148 | } |
||
149 | |||
150 | /** |
||
151 | * {@inheritdoc} |
||
152 | */ |
||
153 | 1 | public function isFactoryClassAutoGenerated() |
|
157 | |||
158 | /** |
||
159 | * {@inheritdoc} |
||
160 | */ |
||
161 | 24 | public function generateFactoryClass($path = null, $className = null) |
|
198 | |||
199 | /** |
||
200 | * {@inheritdoc} |
||
201 | */ |
||
202 | 3 | public function autoGenerateFactoryClass($path = null, $className = null) |
|
210 | |||
211 | /** |
||
212 | * {@inheritdoc} |
||
213 | */ |
||
214 | 16 | public function refreshFactoryClass($path = null, $className = null) |
|
215 | { |
||
216 | 16 | Assert::nullOrStringNotEmpty($path, 'The path to the generated factory file must be a non-empty string or null. Got: %s'); |
|
217 | 16 | Assert::nullOrStringNotEmpty($className, 'The class name of the generated factory must be a non-empty string or null. Got: %s'); |
|
218 | |||
219 | 16 | $path = Path::makeAbsolute($path ?: $this->config->get(Config::FACTORY_OUT_FILE), $this->rootDir); |
|
220 | 16 | $className = $className ?: $this->config->get(Config::FACTORY_OUT_CLASS); |
|
221 | |||
222 | 16 | if (!$this->config->get(Config::FACTORY_AUTO_GENERATE)) { |
|
223 | 1 | return; |
|
224 | } |
||
225 | |||
226 | 15 | if (!file_exists($path)) { |
|
227 | 9 | $this->generateFactoryClass($path, $className); |
|
228 | |||
229 | 9 | return; |
|
230 | } |
||
231 | |||
232 | 6 | $rootModuleFile = $this->context->getRootModuleFile()->getPath(); |
|
233 | |||
234 | 6 | if (!file_exists($rootModuleFile)) { |
|
235 | 1 | return; |
|
236 | } |
||
237 | |||
238 | // Regenerate file if the configuration has changed and |
||
239 | // auto-generation is enabled |
||
240 | 5 | clearstatcache(true, $rootModuleFile); |
|
241 | 5 | $lastConfigChange = filemtime($rootModuleFile); |
|
242 | |||
243 | 5 | $configFile = $this->context->getConfigFile() |
|
244 | 5 | ? $this->context->getConfigFile()->getPath() |
|
245 | 5 | : ''; |
|
246 | |||
247 | 5 | if (file_exists($configFile)) { |
|
248 | 2 | clearstatcache(true, $configFile); |
|
249 | 2 | $lastConfigChange = max(filemtime($configFile), $lastConfigChange); |
|
250 | } |
||
251 | |||
252 | 5 | clearstatcache(true, $path); |
|
253 | 5 | $lastFactoryUpdate = filemtime($path); |
|
254 | |||
255 | 5 | if ($lastConfigChange > $lastFactoryUpdate) { |
|
256 | 3 | $this->generateFactoryClass($path, $className); |
|
257 | } |
||
258 | 5 | } |
|
259 | |||
260 | /** |
||
261 | * Adds the createRepository() method. |
||
262 | * |
||
263 | * @param Clazz $class The factory class model. |
||
264 | */ |
||
265 | 20 | private function addCreateRepositoryMethod(Clazz $class) |
|
297 | |||
298 | /** |
||
299 | * Adds the createDiscovery() method. |
||
300 | * |
||
301 | * @param Clazz $class The factory class model. |
||
302 | */ |
||
303 | 20 | private function addCreateDiscoveryMethod(Clazz $class) |
|
344 | |||
345 | /** |
||
346 | * Adds the createUrlGenerator() method. |
||
347 | * |
||
348 | * @param Clazz $class The factory class model. |
||
349 | */ |
||
350 | 20 | public function addCreateUrlGeneratorMethod(Clazz $class) |
|
396 | |||
397 | /** |
||
398 | * Adds the getModuleOrder() method. |
||
399 | * |
||
400 | * @param Clazz $class The factory class model. |
||
401 | */ |
||
402 | 20 | public function addGetModuleOrderMethod(Clazz $class) |
|
403 | { |
||
404 | 20 | $class->addImport(new Import('Puli\Discovery\Api\Discovery')); |
|
405 | 20 | $class->addImport(new Import('Puli\Manager\Api\Server\ServerCollection')); |
|
406 | 20 | $class->addImport(new Import('Puli\UrlGenerator\Api\UrlGenerator')); |
|
407 | 20 | $class->addImport(new Import('Puli\UrlGenerator\DiscoveryUrlGenerator')); |
|
408 | 20 | $class->addImport(new Import('RuntimeException')); |
|
409 | |||
410 | 20 | $method = new Method('getModuleOrder'); |
|
411 | 20 | $method->setDescription("Returns the order in which the installed modules should be loaded\naccording to the override statements."); |
|
412 | |||
413 | 20 | $method->setReturnValue(new ReturnValue('$order', 'string[]', 'The sorted module names.')); |
|
414 | |||
415 | 20 | $moduleOrderString = ''; |
|
416 | |||
417 | 20 | if (count($this->modules) > 0) { |
|
418 | 20 | $overrideGraph = OverrideGraph::forModules($this->modules); |
|
419 | |||
420 | 20 | foreach ($overrideGraph->getSortedModuleNames() as $moduleName) { |
|
421 | 20 | $moduleOrderString .= sprintf( |
|
422 | 20 | "\n %s,", |
|
423 | 20 | var_export($moduleName, true) |
|
424 | ); |
||
425 | } |
||
426 | |||
427 | 20 | $moduleOrderString .= "\n"; |
|
428 | } |
||
429 | |||
430 | 20 | $method->addBody("\$order = array($moduleOrderString);"); |
|
431 | |||
432 | 20 | $class->addMethod($method); |
|
433 | 20 | } |
|
434 | |||
435 | /** |
||
436 | * Recursively camelizes the keys of an array. |
||
437 | * |
||
438 | * @param array $array The array to process. |
||
439 | * |
||
440 | * @return array The input array with camelized keys. |
||
441 | */ |
||
442 | 20 | private function camelizeKeys(array $array) |
|
454 | |||
455 | /** |
||
456 | * Camelizes a string. |
||
457 | * |
||
458 | * @param string $string A string. |
||
459 | * |
||
460 | * @return string The camelized string. |
||
461 | */ |
||
462 | private function camelize($string) |
||
468 | } |
||
469 |
It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.