diff --git a/module/VuFindConsole/config/module.config.php b/module/VuFindConsole/config/module.config.php index 3a0e8895e8bd6a79c82c06cdb485a5fad40919f7..2a8482527b4b4bceefbb45dff0f2e6be15f9fb40 100644 --- a/module/VuFindConsole/config/module.config.php +++ b/module/VuFindConsole/config/module.config.php @@ -38,6 +38,11 @@ $config = [ ], ], ], + 'service_manager' => [ + 'factories' => [ + 'VuFindConsole\Generator\GeneratorTools' => 'VuFindConsole\Generator\GeneratorToolsFactory', + ], + ], 'view_manager' => [ // CLI tools are admin-oriented, so we should always output full errors: 'display_exceptions' => true, diff --git a/module/VuFindConsole/src/VuFindConsole/Controller/GenerateController.php b/module/VuFindConsole/src/VuFindConsole/Controller/GenerateController.php index 1ee81483b2036045143282b2ef975b980085b743..d4945d27f9775b93bffbb4c42ac52cc6209c7b0e 100644 --- a/module/VuFindConsole/src/VuFindConsole/Controller/GenerateController.php +++ b/module/VuFindConsole/src/VuFindConsole/Controller/GenerateController.php @@ -27,10 +27,6 @@ */ namespace VuFindConsole\Controller; -use Zend\Code\Generator\ClassGenerator; -use Zend\Code\Generator\FileGenerator; -use Zend\Code\Generator\MethodGenerator; -use Zend\Code\Reflection\ClassReflection; use Zend\Console\Console; /** @@ -77,8 +73,9 @@ class GenerateController extends AbstractBase } // Create backup of configuration - $configPath = $this->getModuleConfigPath($module); - $this->backUpFile($configPath); + $generator = $this->getGeneratorTools(); + $configPath = $generator->getModuleConfigPath($module); + $generator->backUpFile($configPath); // Append the route $config = include $configPath; @@ -86,7 +83,7 @@ class GenerateController extends AbstractBase $routeGenerator->addDynamicRoute($config, $route, $controller, $action); // Write updated configuration - $this->writeModuleConfig($configPath, $config); + $generator->writeModuleConfig($configPath, $config); return $this->getSuccessResponse(); } @@ -116,41 +113,8 @@ class GenerateController extends AbstractBase return $this->getFailureResponse(); } - $parts = explode('/', $source); - $partCount = count($parts); - if ($partCount < 3) { - Console::writeLine("Config path too short."); - return $this->getFailureResponse(); - } - $sourceType = $parts[$partCount - 2]; - - $supportedTypes = ['factories', 'invokables']; - if (!in_array($sourceType, $supportedTypes)) { - Console::writeLine( - 'Unsupported service type; supported values: ' - . implode(', ', $supportedTypes) - ); - return $this->getFailureResponse(); - } - - $config = $this->retrieveConfig($parts); - if (!$config) { - Console::writeLine("{$source} not found in configuration."); - return $this->getFailureResponse(); - } - try { - switch ($sourceType) { - case 'factories': - $newConfig = $this->cloneFactory($config, $target); - break; - case 'invokables': - $newConfig = $this->createSubclassInModule($config, $target); - break; - default: - throw new \Exception('Reached unreachable code!'); - } - $this->writeNewConfig($parts, $newConfig, $target); + $this->getGeneratorTools()->extendService($source, $target); } catch (\Exception $e) { Console::writeLine($e->getMessage()); return $this->getFailureResponse(); @@ -184,8 +148,9 @@ class GenerateController extends AbstractBase } // Create backup of configuration - $configPath = $this->getModuleConfigPath($module); - $this->backUpFile($configPath); + $generator = $this->getGeneratorTools(); + $configPath = $generator->getModuleConfigPath($module); + $generator->backUpFile($configPath); // Load the route config $config = include $configPath; @@ -210,7 +175,7 @@ class GenerateController extends AbstractBase } // Write updated configuration - $this->writeModuleConfig($configPath, $config); + $generator->writeModuleConfig($configPath, $config); return $this->getSuccessResponse(); } @@ -243,8 +208,9 @@ class GenerateController extends AbstractBase } // Create backup of configuration - $configPath = $this->getModuleConfigPath($module); - $this->backUpFile($configPath); + $generator = $this->getGeneratorTools(); + $configPath = $generator->getModuleConfigPath($module); + $generator->backUpFile($configPath); // Append the route $config = include $configPath; @@ -252,7 +218,7 @@ class GenerateController extends AbstractBase $routeGenerator->addRecordRoute($config, $base, $controller); // Write updated configuration - $this->writeModuleConfig($configPath, $config); + $generator->writeModuleConfig($configPath, $config); return $this->getSuccessResponse(); } @@ -281,8 +247,9 @@ class GenerateController extends AbstractBase } // Create backup of configuration - $configPath = $this->getModuleConfigPath($module); - $this->backUpFile($configPath); + $generator = $this->getGeneratorTools(); + $configPath = $generator->getModuleConfigPath($module); + $generator->backUpFile($configPath); // Append the route $config = include $configPath; @@ -290,7 +257,7 @@ class GenerateController extends AbstractBase $routeGenerator->addStaticRoute($config, $route); // Write updated configuration - $this->writeModuleConfig($configPath, $config); + $generator->writeModuleConfig($configPath, $config); return $this->getSuccessResponse(); } @@ -349,323 +316,12 @@ class GenerateController extends AbstractBase } /** - * Create a new subclass and factory to override a factory-generated - * service. - * - * @param mixed $factory Factory configuration for class to extend - * @param string $module Module in which to create the new factory - * - * @return string - * @throws \Exception - */ - protected function cloneFactory($factory, $module) - { - // Make sure we can figure out how to handle the factory; it should - // either be a [controller, method] array or a "controller::method" - // string; anything else will cause a problem. - $parts = is_string($factory) ? explode('::', $factory) : $factory; - if (!is_array($parts) || count($parts) != 2 || !class_exists($parts[0]) - || !method_exists($parts[0], $parts[1]) - ) { - throw new \Exception('Unexpected factory configuration format.'); - } - list($factoryClass, $factoryMethod) = $parts; - $newFactoryClass = $this->generateLocalClassName($factoryClass, $module); - if (!class_exists($newFactoryClass)) { - $this->createClassInModule($newFactoryClass, $module); - $skipBackup = true; - } else { - $skipBackup = false; - } - if (method_exists($newFactoryClass, $factoryMethod)) { - throw new \Exception("$newFactoryClass::$factoryMethod already exists."); - } - - $oldReflection = new ClassReflection($factoryClass); - $newReflection = new ClassReflection($newFactoryClass); - - $generator = ClassGenerator::fromReflection($newReflection); - $method = MethodGenerator::fromReflection( - $oldReflection->getMethod($factoryMethod) - ); - $this->createServiceClassAndUpdateFactory( - $method, $oldReflection->getNamespaceName(), $module - ); - $generator->addMethodFromGenerator($method); - $this->writeClass($generator, $module, true, $skipBackup); - - return $newFactoryClass . '::' . $factoryMethod; - } - - /** - * Given a factory method, extend the class being constructed and create - * a new factory for the subclass. - * - * @param MethodGenerator $method Method to modify - * @param string $ns Namespace of old factory - * @param string $module Module in which to make changes - * - * @return void - * @throws \Exception - */ - protected function createServiceClassAndUpdateFactory(MethodGenerator $method, - $ns, $module - ) { - $body = $method->getBody(); - $regex = '/new\s+([\w\\\\]*)\s*\(/m'; - preg_match_all($regex, $body, $matches); - $classNames = $matches[1]; - $count = count($classNames); - if ($count != 1) { - throw new \Exception("Found $count class names; expected 1."); - } - $className = $classNames[0]; - // Figure out fully qualified name for purposes of createSubclassInModule(): - $fqClassName = (substr($className, 0, 1) != '\\') - ? "$ns\\$className" : $className; - $newClass = $this->createSubclassInModule($fqClassName, $module); - $body = preg_replace( - '/new\s+' . addslashes($className) . '\s*\(/m', - 'new \\' . $newClass . '(', - $body - ); - $method->setBody($body); - } - - /** - * Determine the name of a local replacement class within the specified - * module. - * - * @param string $class Name of class to extend/replace - * @param string $module Module in which to create the new class - * - * @return string - * @throws \Exception - */ - protected function generateLocalClassName($class, $module) - { - // Determine the name of the new class by exploding the old class and - // replacing the namespace: - $parts = explode('\\', trim($class, '\\')); - if (count($parts) < 2) { - throw new \Exception('Expected a namespaced class; found ' . $class); - } - $parts[0] = $module; - return implode('\\', $parts); - } - - /** - * Extend a specified class within a specified module. Return the name of - * the new subclass. - * - * @param string $class Name of class to create - * @param string $module Module in which to create the new class - * @param string $parent Parent class (null for no parent) - * - * @return void - * @throws \Exception - */ - protected function createClassInModule($class, $module, $parent = null) - { - $generator = new ClassGenerator($class, null, null, $parent); - return $this->writeClass($generator, $module); - } - - /** - * Write a class to disk. - * - * @param ClassGenerator $classGenerator Representation of class to write - * @param string $module Module in which to write class - * @param bool $allowOverwrite Allow overwrite of existing file? - * @param bool $skipBackup Should we skip backing up the file? - * - * @return void - * @throws \Exception - */ - protected function writeClass(ClassGenerator $classGenerator, $module, - $allowOverwrite = false, $skipBackup = false - ) { - // Use the class name parts from the previous step to determine a path - // and filename, then create the new path. - $parts = explode('\\', $classGenerator->getNamespaceName()); - array_unshift($parts, 'module', $module, 'src'); - $this->createTree($parts); - - // Generate the new class: - $generator = FileGenerator::fromArray(['classes' => [$classGenerator]]); - $filename = $classGenerator->getName() . '.php'; - $fullPath = APPLICATION_PATH . '/' . implode('/', $parts) . '/' . $filename; - if (file_exists($fullPath)) { - if ($allowOverwrite) { - if (!$skipBackup) { - $this->backUpFile($fullPath); - } - } else { - throw new \Exception("$fullPath already exists."); - } - } - if (!file_put_contents($fullPath, $generator->generate())) { - throw new \Exception("Problem writing to $fullPath."); - } - Console::writeLine("Saved file: $fullPath"); - } - - /** - * Extend a specified class within a specified module. Return the name of - * the new subclass. + * Get generator tools * - * @param string $class Name of class to extend - * @param string $module Module in which to create the new class - * - * @return string - * @throws \Exception - */ - protected function createSubclassInModule($class, $module) - { - // Normalize leading backslashes; in some contexts we will - // have them and in others we may not. - $class = trim($class, '\\'); - $newClass = $this->generateLocalClassName($class, $module); - $this->createClassInModule($newClass, $module, "\\$class"); - return $newClass; - } - - /** - * Create a directory tree. - * - * @param array $path Array of subdirectories to create relative to - * APPLICATION_PATH - * - * @return void - * @throws \Exception - */ - protected function createTree($path) - { - $fullPath = APPLICATION_PATH; - foreach ($path as $part) { - $fullPath .= '/' . $part; - if (!file_exists($fullPath)) { - if (!mkdir($fullPath)) { - throw new \Exception("Problem creating $fullPath"); - } - } - if (!is_dir($fullPath)) { - throw new \Exception("$fullPath is not a directory!"); - } - } - } - - /** - * Create a backup of a file. - * - * @param string $filename File to back up - * - * @return void - * @throws \Exception - */ - protected function backUpFile($filename) - { - $backup = $filename . '.' . time() . '.bak'; - if (!copy($filename, $backup)) { - throw new \Exception("Problem generating backup file: $backup"); - } - Console::writeLine("Created backup: $backup"); - } - - /** - * Get the path to the module configuration; throw an exception if it is - * missing. - * - * @param string $module Module name - * - * @return string - * @throws \Exception - */ - protected function getModuleConfigPath($module) - { - $configPath = APPLICATION_PATH . "/module/$module/config/module.config.php"; - if (!file_exists($configPath)) { - throw new \Exception("Cannot find $configPath"); - } - return $configPath; - } - - /** - * Write a module configuration. - * - * @param string $configPath Path to write to - * @param string $config Configuration array to write - * - * @return void - * @throws \Exception - */ - protected function writeModuleConfig($configPath, $config) - { - $generator = FileGenerator::fromArray( - [ - 'body' => 'return ' . var_export($config, true) . ';' - ] - ); - if (!file_put_contents($configPath, $generator->generate())) { - throw new \Exception("Cannot write to $configPath"); - } - Console::writeLine("Successfully updated $configPath"); - } - - /** - * Update the configuration of a target module. - * - * @param array $path Representation of path in config array - * @param string $setting New setting to write into config - * @param string $module Module in which to write the configuration - * - * @return void - * @throws \Exception + * @return \VuFindConsole\Generator\GeneratorTools */ - protected function writeNewConfig($path, $setting, $module) + protected function getGeneratorTools() { - // Create backup of configuration - $configPath = $this->getModuleConfigPath($module); - $this->backUpFile($configPath); - - $config = include $configPath; - $current = & $config; - $finalStep = array_pop($path); - foreach ($path as $step) { - if (!is_array($current)) { - throw new \Exception('Unexpected non-array: ' . $current); - } - if (!isset($current[$step])) { - $current[$step] = []; - } - $current = & $current[$step]; - } - if (!is_array($current)) { - throw new \Exception('Unexpected non-array: ' . $current); - } - $current[$finalStep] = $setting; - - // Write updated configuration - $this->writeModuleConfig($configPath, $config); - } - - /** - * Retrieve a value from the application configuration (or return false - * if the path is not found). - * - * @param array $path Path to walk through configuration - * - * @return mixed - */ - protected function retrieveConfig(array $path) - { - $config = $this->serviceLocator->get('config'); - foreach ($path as $part) { - if (!isset($config[$part])) { - return false; - } - $config = $config[$part]; - } - return $config; + return $this->serviceLocator->get('VuFindConsole\Generator\GeneratorTools'); } } diff --git a/module/VuFindConsole/src/VuFindConsole/Generator/GeneratorTools.php b/module/VuFindConsole/src/VuFindConsole/Generator/GeneratorTools.php new file mode 100644 index 0000000000000000000000000000000000000000..35bc069300aeb3000b5534390d4d64f61069ee41 --- /dev/null +++ b/module/VuFindConsole/src/VuFindConsole/Generator/GeneratorTools.php @@ -0,0 +1,429 @@ +<?php +/** + * Generator tools. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Generator + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFindConsole\Generator; + +use Zend\Code\Generator\ClassGenerator; +use Zend\Code\Generator\FileGenerator; +use Zend\Code\Generator\MethodGenerator; +use Zend\Code\Reflection\ClassReflection; +use Zend\Console\Console; + +/** + * Generator tools. + * + * @category VuFind + * @package Generator + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GeneratorTools +{ + /** + * Zend Framework configuration + * + * @var array + */ + protected $config; + + /** + * Constructor. + * + * @param array $config Zend Framework configuration + */ + public function __construct(array $config) + { + $this->config = $config; + } + + /** + * Extend a service defined in module.config.php. + * + * @param string $source Configuration path to use as source + * @param string $target Target module in which to create new service + * + * @return bool + * @throws \Exception + */ + public function extendService($source, $target) + { + $parts = explode('/', $source); + $partCount = count($parts); + if ($partCount < 3) { + throw new \Exception('Config path too short.'); + } + $sourceType = $parts[$partCount - 2]; + + $supportedTypes = ['factories', 'invokables']; + if (!in_array($sourceType, $supportedTypes)) { + throw new \Exception( + 'Unsupported service type; supported values: ' + . implode(', ', $supportedTypes) + ); + } + + $config = $this->retrieveConfig($parts); + if (!$config) { + throw new \Exception("{$source} not found in configuration."); + } + + switch ($sourceType) { + case 'factories': + $newConfig = $this->cloneFactory($config, $target); + break; + case 'invokables': + $newConfig = $this->createSubclassInModule($config, $target); + break; + default: + throw new \Exception('Reached unreachable code!'); + } + $this->writeNewConfig($parts, $newConfig, $target); + return true; + } + + /** + * Create a new subclass and factory to override a factory-generated + * service. + * + * @param mixed $factory Factory configuration for class to extend + * @param string $module Module in which to create the new factory + * + * @return string + * @throws \Exception + */ + protected function cloneFactory($factory, $module) + { + // Make sure we can figure out how to handle the factory; it should + // either be a [controller, method] array or a "controller::method" + // string; anything else will cause a problem. + $parts = is_string($factory) ? explode('::', $factory) : $factory; + if (!is_array($parts) || count($parts) != 2 || !class_exists($parts[0]) + || !method_exists($parts[0], $parts[1]) + ) { + throw new \Exception('Unexpected factory configuration format.'); + } + list($factoryClass, $factoryMethod) = $parts; + $newFactoryClass = $this->generateLocalClassName($factoryClass, $module); + if (!class_exists($newFactoryClass)) { + $this->createClassInModule($newFactoryClass, $module); + $skipBackup = true; + } else { + $skipBackup = false; + } + if (method_exists($newFactoryClass, $factoryMethod)) { + throw new \Exception("$newFactoryClass::$factoryMethod already exists."); + } + + $oldReflection = new ClassReflection($factoryClass); + $newReflection = new ClassReflection($newFactoryClass); + + $generator = ClassGenerator::fromReflection($newReflection); + $method = MethodGenerator::fromReflection( + $oldReflection->getMethod($factoryMethod) + ); + $this->createServiceClassAndUpdateFactory( + $method, $oldReflection->getNamespaceName(), $module + ); + $generator->addMethodFromGenerator($method); + $this->writeClass($generator, $module, true, $skipBackup); + + return $newFactoryClass . '::' . $factoryMethod; + } + + /** + * Given a factory method, extend the class being constructed and create + * a new factory for the subclass. + * + * @param MethodGenerator $method Method to modify + * @param string $ns Namespace of old factory + * @param string $module Module in which to make changes + * + * @return void + * @throws \Exception + */ + protected function createServiceClassAndUpdateFactory(MethodGenerator $method, + $ns, $module + ) { + $body = $method->getBody(); + $regex = '/new\s+([\w\\\\]*)\s*\(/m'; + preg_match_all($regex, $body, $matches); + $classNames = $matches[1]; + $count = count($classNames); + if ($count != 1) { + throw new \Exception("Found $count class names; expected 1."); + } + $className = $classNames[0]; + // Figure out fully qualified name for purposes of createSubclassInModule(): + $fqClassName = (substr($className, 0, 1) != '\\') + ? "$ns\\$className" : $className; + $newClass = $this->createSubclassInModule($fqClassName, $module); + $body = preg_replace( + '/new\s+' . addslashes($className) . '\s*\(/m', + 'new \\' . $newClass . '(', + $body + ); + $method->setBody($body); + } + + /** + * Determine the name of a local replacement class within the specified + * module. + * + * @param string $class Name of class to extend/replace + * @param string $module Module in which to create the new class + * + * @return string + * @throws \Exception + */ + protected function generateLocalClassName($class, $module) + { + // Determine the name of the new class by exploding the old class and + // replacing the namespace: + $parts = explode('\\', trim($class, '\\')); + if (count($parts) < 2) { + throw new \Exception('Expected a namespaced class; found ' . $class); + } + $parts[0] = $module; + return implode('\\', $parts); + } + + /** + * Extend a specified class within a specified module. Return the name of + * the new subclass. + * + * @param string $class Name of class to create + * @param string $module Module in which to create the new class + * @param string $parent Parent class (null for no parent) + * + * @return void + * @throws \Exception + */ + protected function createClassInModule($class, $module, $parent = null) + { + $generator = new ClassGenerator($class, null, null, $parent); + return $this->writeClass($generator, $module); + } + + /** + * Write a class to disk. + * + * @param ClassGenerator $classGenerator Representation of class to write + * @param string $module Module in which to write class + * @param bool $allowOverwrite Allow overwrite of existing file? + * @param bool $skipBackup Should we skip backing up the file? + * + * @return void + * @throws \Exception + */ + protected function writeClass(ClassGenerator $classGenerator, $module, + $allowOverwrite = false, $skipBackup = false + ) { + // Use the class name parts from the previous step to determine a path + // and filename, then create the new path. + $parts = explode('\\', $classGenerator->getNamespaceName()); + array_unshift($parts, 'module', $module, 'src'); + $this->createTree($parts); + + // Generate the new class: + $generator = FileGenerator::fromArray(['classes' => [$classGenerator]]); + $filename = $classGenerator->getName() . '.php'; + $fullPath = APPLICATION_PATH . '/' . implode('/', $parts) . '/' . $filename; + if (file_exists($fullPath)) { + if ($allowOverwrite) { + if (!$skipBackup) { + $this->backUpFile($fullPath); + } + } else { + throw new \Exception("$fullPath already exists."); + } + } + if (!file_put_contents($fullPath, $generator->generate())) { + throw new \Exception("Problem writing to $fullPath."); + } + Console::writeLine("Saved file: $fullPath"); + } + + /** + * Extend a specified class within a specified module. Return the name of + * the new subclass. + * + * @param string $class Name of class to extend + * @param string $module Module in which to create the new class + * + * @return string + * @throws \Exception + */ + protected function createSubclassInModule($class, $module) + { + // Normalize leading backslashes; in some contexts we will + // have them and in others we may not. + $class = trim($class, '\\'); + $newClass = $this->generateLocalClassName($class, $module); + $this->createClassInModule($newClass, $module, "\\$class"); + return $newClass; + } + + /** + * Create a directory tree. + * + * @param array $path Array of subdirectories to create relative to + * APPLICATION_PATH + * + * @return void + * @throws \Exception + */ + protected function createTree($path) + { + $fullPath = APPLICATION_PATH; + foreach ($path as $part) { + $fullPath .= '/' . $part; + if (!file_exists($fullPath)) { + if (!mkdir($fullPath)) { + throw new \Exception("Problem creating $fullPath"); + } + } + if (!is_dir($fullPath)) { + throw new \Exception("$fullPath is not a directory!"); + } + } + } + + /** + * Create a backup of a file. + * + * @param string $filename File to back up + * + * @return void + * @throws \Exception + */ + public function backUpFile($filename) + { + $backup = $filename . '.' . time() . '.bak'; + if (!copy($filename, $backup)) { + throw new \Exception("Problem generating backup file: $backup"); + } + Console::writeLine("Created backup: $backup"); + } + + /** + * Get the path to the module configuration; throw an exception if it is + * missing. + * + * @param string $module Module name + * + * @return string + * @throws \Exception + */ + public function getModuleConfigPath($module) + { + $configPath = APPLICATION_PATH . "/module/$module/config/module.config.php"; + if (!file_exists($configPath)) { + throw new \Exception("Cannot find $configPath"); + } + return $configPath; + } + + /** + * Write a module configuration. + * + * @param string $configPath Path to write to + * @param string $config Configuration array to write + * + * @return void + * @throws \Exception + */ + public function writeModuleConfig($configPath, $config) + { + $generator = FileGenerator::fromArray( + [ + 'body' => 'return ' . var_export($config, true) . ';' + ] + ); + if (!file_put_contents($configPath, $generator->generate())) { + throw new \Exception("Cannot write to $configPath"); + } + Console::writeLine("Successfully updated $configPath"); + } + + /** + * Update the configuration of a target module. + * + * @param array $path Representation of path in config array + * @param string $setting New setting to write into config + * @param string $module Module in which to write the configuration + * + * @return void + * @throws \Exception + */ + protected function writeNewConfig($path, $setting, $module) + { + // Create backup of configuration + $configPath = $this->getModuleConfigPath($module); + $this->backUpFile($configPath); + + $config = include $configPath; + $current = & $config; + $finalStep = array_pop($path); + foreach ($path as $step) { + if (!is_array($current)) { + throw new \Exception('Unexpected non-array: ' . $current); + } + if (!isset($current[$step])) { + $current[$step] = []; + } + $current = & $current[$step]; + } + if (!is_array($current)) { + throw new \Exception('Unexpected non-array: ' . $current); + } + $current[$finalStep] = $setting; + + // Write updated configuration + $this->writeModuleConfig($configPath, $config); + } + + /** + * Retrieve a value from the application configuration (or return false + * if the path is not found). + * + * @param array $path Path to walk through configuration + * + * @return mixed + */ + protected function retrieveConfig(array $path) + { + $config = $this->config; + foreach ($path as $part) { + if (!isset($config[$part])) { + return false; + } + $config = $config[$part]; + } + return $config; + } +} diff --git a/module/VuFindConsole/src/VuFindConsole/Generator/GeneratorToolsFactory.php b/module/VuFindConsole/src/VuFindConsole/Generator/GeneratorToolsFactory.php new file mode 100644 index 0000000000000000000000000000000000000000..428c424c3dc7f8cf3b669d6dc62ad364293cdc3f --- /dev/null +++ b/module/VuFindConsole/src/VuFindConsole/Generator/GeneratorToolsFactory.php @@ -0,0 +1,66 @@ +<?php +/** + * Generator tools factory. + * + * PHP version 5 + * + * Copyright (C) Villanova University 2018. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * @category VuFind + * @package Generator + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +namespace VuFindConsole\Generator; + +use Interop\Container\ContainerInterface; +use Zend\ServiceManager\Factory\FactoryInterface; + +/** + * Generator tools factory. + * + * @category VuFind + * @package Generator + * @author Demian Katz <demian.katz@villanova.edu> + * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License + * @link https://vufind.org/wiki/development Wiki + */ +class GeneratorToolsFactory implements FactoryInterface +{ + /** + * Create an object + * + * @param ContainerInterface $container Service manager + * @param string $requestedName Service being created + * @param null|array $options Extra options (optional) + * + * @return object + * + * @throws ServiceNotFoundException if unable to resolve the service. + * @throws ServiceNotCreatedException if an exception is raised when + * creating a service. + * @throws ContainerException if any other error occurs + */ + public function __invoke(ContainerInterface $container, $requestedName, + array $options = null + ) { + if (!empty($options)) { + throw new \Exception('Unexpected options sent to factory.'); + } + return new $requestedName($container->get('config')); + } +}