Skip to content
Snippets Groups Projects
Commit 47780737 authored by Demian Katz's avatar Demian Katz
Browse files

Generator improvements.

- Add controller and controller plugin support to extendclass
- Make static factory support smarter
parent 8ac89fb6
No related merge requests found
...@@ -80,11 +80,16 @@ class GeneratorTools ...@@ -80,11 +80,16 @@ class GeneratorTools
) { ) {
// Set things up differently depending on whether this is a top-level // Set things up differently depending on whether this is a top-level
// service or a class in a plugin manager. // service or a class in a plugin manager.
$cm = $container->get('ControllerManager');
$cpm = $container->get('ControllerPluginManager');
if ($container->has($class)) { if ($container->has($class)) {
$factory = $this->getFactoryFromContainer($container, $class); $factory = $this->getFactoryFromContainer($container, $class);
$configPath = ['service_manager']; $configPath = ['service_manager'];
} else { } elseif ($factory = $this->getFactoryFromContainer($cm, $class)) {
$pm = $this->getPluginManagerContainingClass($container, $class); $configPath = ['controllers'];
} elseif ($factory = $this->getFactoryFromContainer($cpm, $class)) {
$configPath = ['controller_plugins'];
} elseif ($pm = $this->getPluginManagerContainingClass($container, $class)) {
$apmFactory = new \VuFind\ServiceManager\AbstractPluginManagerFactory(); $apmFactory = new \VuFind\ServiceManager\AbstractPluginManagerFactory();
$pmKey = $apmFactory->getConfigKey(get_class($pm)); $pmKey = $apmFactory->getConfigKey(get_class($pm));
$factory = $this->getFactoryFromContainer($pm, $class); $factory = $this->getFactoryFromContainer($pm, $class);
...@@ -92,7 +97,7 @@ class GeneratorTools ...@@ -92,7 +97,7 @@ class GeneratorTools
} }
// No factory found? Throw an error! // No factory found? Throw an error!
if (!$factory) { if (empty($factory)) {
throw new \Exception('Could not find factory for ' . $class); throw new \Exception('Could not find factory for ' . $class);
} }
...@@ -101,7 +106,7 @@ class GeneratorTools ...@@ -101,7 +106,7 @@ class GeneratorTools
// Create the custom factory only if requested. // Create the custom factory only if requested.
$newFactory = $extendFactory $newFactory = $extendFactory
? $this->createSubclassInModule($factory, $target) ? $this->cloneFactory($factory, $target)
: $factory; : $factory;
// Finalize the local module configuration -- create a factory for the // Finalize the local module configuration -- create a factory for the
...@@ -202,6 +207,7 @@ class GeneratorTools ...@@ -202,6 +207,7 @@ class GeneratorTools
switch ($sourceType) { switch ($sourceType) {
case 'factories': case 'factories':
$this->createSubclassInModule($parts[$partCount - 1], $target);
$newConfig = $this->cloneFactory($config, $target); $newConfig = $this->cloneFactory($config, $target);
break; break;
case 'invokables': case 'invokables':
...@@ -226,39 +232,63 @@ class GeneratorTools ...@@ -226,39 +232,63 @@ class GeneratorTools
*/ */
protected function cloneFactory($factory, $module) protected function cloneFactory($factory, $module)
{ {
// If the factory is a stand-alone class, it's simple to clone:
if (class_exists($factory)) {
return $this->createSubclassInModule($factory, $module);
}
// Make sure we can figure out how to handle the factory; it should // Make sure we can figure out how to handle the factory; it should
// either be a [controller, method] array or a "controller::method" // either be a [controller, method] array or a "controller::method"
// string; anything else will cause a problem. // string; anything else will cause a problem.
$parts = is_string($factory) ? explode('::', $factory) : $factory; $parts = is_string($factory) ? explode('::', $factory) : $factory;
if (!is_array($parts) || count($parts) != 2 || !class_exists($parts[0]) if (!is_array($parts) || count($parts) != 2 || !class_exists($parts[0])
|| !method_exists($parts[0], $parts[1]) || !is_callable($parts)
) { ) {
throw new \Exception('Unexpected factory configuration format.'); throw new \Exception('Unexpected factory configuration format.');
} }
list($factoryClass, $factoryMethod) = $parts; list($factoryClass, $factoryMethod) = $parts;
$newFactoryClass = $this->generateLocalClassName($factoryClass, $module); $newFactoryClass = $this->generateLocalClassName($factoryClass, $module);
if (!class_exists($newFactoryClass)) { if (!class_exists($newFactoryClass)) {
$this->createClassInModule($newFactoryClass, $module); $this->createSubclassInModule($factoryClass, $module);
$skipBackup = true; $skipBackup = true;
} else { } else {
$skipBackup = false; $skipBackup = false;
} }
if (method_exists($newFactoryClass, $factoryMethod)) {
throw new \Exception("$newFactoryClass::$factoryMethod already exists.");
}
$oldReflection = new ClassReflection($factoryClass); $oldReflection = new ClassReflection($factoryClass);
$newReflection = new ClassReflection($newFactoryClass); $newReflection = new ClassReflection($newFactoryClass);
$generator = ClassGenerator::fromReflection($newReflection); try {
$method = MethodGenerator::fromReflection( $newMethod = $newReflection->getMethod($factoryMethod);
$oldReflection->getMethod($factoryMethod) if ($newMethod->getDeclaringClass()->getName() == $newFactoryClass) {
); throw new \Exception(
$this->createServiceClassAndUpdateFactory( "$newFactoryClass::$factoryMethod already exists."
$method, $oldReflection->getNamespaceName(), $module );
); }
$generator->addMethodFromGenerator($method);
$this->writeClass($generator, $module, true, $skipBackup); $generator = ClassGenerator::fromReflection($newReflection);
$method = MethodGenerator::fromReflection(
$oldReflection->getMethod($factoryMethod)
);
$this->updateFactory(
$method, $oldReflection->getNamespaceName(), $module
);
$generator->addMethodFromGenerator($method);
$this->writeClass($generator, $module, true, $skipBackup);
} catch (\ReflectionException $e) {
// If a parent factory has a __callStatic method, the method we are
// trying to rewrite may not exist. In that case, we can just inherit
// __callStatic and ignore the error. Any other exception should be
// treated as a fatal error.
if (method_exists($factoryClass, '__callStatic')) {
Console::writeLine('Error: ' . $e->getMessage());
Console::writeLine(
'__callStatic in parent factory; skipping method generation.'
);
} else {
throw $e;
}
}
return $newFactoryClass . '::' . $factoryMethod; return $newFactoryClass . '::' . $factoryMethod;
} }
...@@ -274,7 +304,7 @@ class GeneratorTools ...@@ -274,7 +304,7 @@ class GeneratorTools
* @return void * @return void
* @throws \Exception * @throws \Exception
*/ */
protected function createServiceClassAndUpdateFactory(MethodGenerator $method, protected function updateFactory(MethodGenerator $method,
$ns, $module $ns, $module
) { ) {
$body = $method->getBody(); $body = $method->getBody();
...@@ -289,7 +319,7 @@ class GeneratorTools ...@@ -289,7 +319,7 @@ class GeneratorTools
// Figure out fully qualified name for purposes of createSubclassInModule(): // Figure out fully qualified name for purposes of createSubclassInModule():
$fqClassName = (substr($className, 0, 1) != '\\') $fqClassName = (substr($className, 0, 1) != '\\')
? "$ns\\$className" : $className; ? "$ns\\$className" : $className;
$newClass = $this->createSubclassInModule($fqClassName, $module); $newClass = $this->generateLocalClassName($fqClassName, $module);
$body = preg_replace( $body = preg_replace(
'/new\s+' . addslashes($className) . '\s*\(/m', '/new\s+' . addslashes($className) . '\s*\(/m',
'new \\' . $newClass . '(', 'new \\' . $newClass . '(',
...@@ -370,7 +400,13 @@ class GeneratorTools ...@@ -370,7 +400,13 @@ class GeneratorTools
throw new \Exception("$fullPath already exists."); throw new \Exception("$fullPath already exists.");
} }
} }
if (!file_put_contents($fullPath, $generator->generate())) { // TODO: this is a workaround for an apparent bug in Zend\Code which
// omits the leading backslash on "extends" statements when rewriting
// existing classes. Can we remove this after a future Zend\Code upgrade?
$code = str_replace(
'extends VuFind\\', 'extends \\VuFind\\', $generator->generate()
);
if (!file_put_contents($fullPath, $code)) {
throw new \Exception("Problem writing to $fullPath."); throw new \Exception("Problem writing to $fullPath.");
} }
Console::writeLine("Saved file: $fullPath"); Console::writeLine("Saved file: $fullPath");
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment