From 32671e3a9867782a4d88b79a370f062f615ce066 Mon Sep 17 00:00:00 2001 From: Herve Donner Date: Thu, 6 Jun 2019 13:36:36 +0200 Subject: [PATCH] Issue #36: Update project namespace during composer create-project. --- scripts/composer/SetupWizard.php | 128 +++++++++++++++++++++++++++---- 1 file changed, 112 insertions(+), 16 deletions(-) diff --git a/scripts/composer/SetupWizard.php b/scripts/composer/SetupWizard.php index 903bb7b..65759fa 100644 --- a/scripts/composer/SetupWizard.php +++ b/scripts/composer/SetupWizard.php @@ -7,12 +7,20 @@ use Composer\Json\JsonFile; use Composer\Script\Event; use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Finder\Finder; /** * Setup wizard to handle user input during initial composer installation. */ class SetupWizard { + /** + * The original namespace used in this project. + * + * @var string + */ + const ORIGINAL_NAMESPACE = 'OpenEuropa\Site'; + /** * The setup wizard. * @@ -47,12 +55,13 @@ public static function setup(Event $event): bool { $params['machine_name'] = $event->getIO()->ask('What is the (machine readable) project name? [' . $params['machine_name'] . ']? ', $params['machine_name']); $params['package_name'] = $event->getIO()->ask('What is the package name? [' . $params['package_name'] . ']? ', $params['package_name']); - $params['description'] = $event->getIO()->ask('Provide a description [' . $params['description'] . ']? ', $params['description']); + $params['namespace'] = $params['camelcased_organization_name'] . '\\' . ucwords($params['machine_name']); + $params['namespace'] = $event->getIO()->ask('What is the project namespace? [' . $params['namespace'] . ']? ', $params['namespace']); - // Define the namespace for the project. - $params['namespace'] = $params['camelcased_organization_name'] . '\\' . $params['machine_name'] . '\\'; + $params['description'] = $event->getIO()->ask('Provide a description [' . $params['description'] . ']? ', $params['description']); self::updateConfig($composer_filename, $params); + self::updateBehatFiles($params); self::updateRunnerFile($params); self::cleanFile(); self::createLibDir(); @@ -81,32 +90,68 @@ private static function updateConfig(string $composer_filename, array $params): $config['description'] = $params['description']; // Remove the configuration related to the setup wizard. - $config['autoload']['classmap'] = array_diff($config['autoload']['classmap'], ['scripts/composer/SetupWizard.php', 'scripts/composer/CheckSetupWizard.php']); - if (empty($config['autoload']['classmap'])) { - unset($config['autoload']['classmap']); + if (!empty($config['autoload']['classmap'])) { + $config['autoload']['classmap'] = array_diff($config['autoload']['classmap'], [ + 'scripts/composer/SetupWizard.php', + 'scripts/composer/CheckSetupWizard.php', + ]); } - if (empty($config['autoload'])) { - unset($config['autoload']); + if (!empty($config['scripts']['post-create-project-cmd'])) { + $config['scripts']['post-create-project-cmd'] = array_diff($config['scripts']['post-create-project-cmd'], [ + 'DrupalSiteTemplate\\composer\\CheckSetupWizard::check', + 'DrupalSiteTemplate\\composer\\SetupWizard::cleanup', + ]); } - $config['scripts']['post-create-project-cmd'] = array_diff($config['scripts']['post-create-project-cmd'], ['DrupalSiteTemplate\\composer\\CheckSetupWizard::check', 'DrupalSiteTemplate\\composer\\SetupWizard::cleanup']); - if (empty($config['scripts']['post-create-project-cmd'])) { - unset($config['scripts']['post-create-project-cmd']); + if (!empty($config['scripts']['post-root-package-install'])) { + $config['scripts']['post-root-package-install'] = array_diff($config['scripts']['post-root-package-install'], ['DrupalSiteTemplate\\composer\\SetupWizard::setup']); } - $config['scripts']['post-root-package-install'] = array_diff($config['scripts']['post-root-package-install'], ['DrupalSiteTemplate\\composer\\SetupWizard::setup']); - if (empty($config['scripts']['post-root-package-install'])) { - unset($config['scripts']['post-root-package-install']); + // Convert namespaces in autoload. + if (!empty($config['autoload']['psr-4'])) { + $config['autoload']['psr-4'] = self::convertArrayKeysNamespaces($config['autoload']['psr-4'], self::ORIGINAL_NAMESPACE, $params['namespace']); } - if (empty($config['scripts'])) { - unset($config['scripts']); + // Convert namespaces in autoload-dev. + if (!empty($config['autoload-dev']['psr-4'])) { + $config['autoload-dev']['psr-4'] = self::convertArrayKeysNamespaces($config['autoload-dev']['psr-4'], self::ORIGINAL_NAMESPACE, $params['namespace']); } + $config = self::arrayFilterRecursive($config); $composer_json->write($config); } + /** + * Update the Behat files. + * + * @param array $params + * The array of parameters. + */ + private static function updateBehatFiles(array $params): void { + $finder = new Finder(); + + // Update namespaces in behat classes. + $dirs = ['tests/Behat']; + $finder->files()->in($dirs); + foreach ($finder as $file) { + $filepath = $file->getRealPath(); + + // Update the namespace. + $file_contents = file_get_contents($filepath); + $pattern = '@^namespace ' . preg_quote(self::ORIGINAL_NAMESPACE) . '(.+;)$@m'; + $replacement = 'namespace ' . preg_quote($params['namespace']) . '$1'; + $file_contents = preg_replace($pattern, $replacement, $file_contents); + file_put_contents($filepath, $file_contents); + } + + // Update namespaces in behat.yml.dist. + $filename = 'behat.yml.dist'; + $file_contents = file_get_contents($filename); + $file_contents = str_replace(self::ORIGINAL_NAMESPACE, $params['namespace'], $file_contents); + file_put_contents($filename, $file_contents); + } + /** * Update the configuration file. * @@ -202,4 +247,55 @@ public static function cleanup(Event $event): void { $event->getIO()->write('Setup wizard file cleaned.'); } + /** + * Convert namespaces in array keys to a given namespace. + * + * @param array $array + * The array to convert. + * @param string $old_namespace + * The old namespace. + * @param string $new_namespace + * The new namespace. + * + * @return array + * The array with converted keys. + */ + private static function convertArrayKeysNamespaces(array $array, string $old_namespace, string $new_namespace): array { + $new_array = []; + + foreach ($array as $key => $value) { + if (strpos($key, $old_namespace) !== FALSE) { + $new_namespace = str_replace($old_namespace, $new_namespace, $key); + $new_array[$new_namespace] = $value; + } + else { + $new_array[$key] = $value; + } + } + + return $new_array; + } + + /** + * Filters an array recursively. + * + * @param array $array + * The filtered nested array. + * @param callable|null $callable + * The callable to apply for filtering. + * + * @return array + * The filtered array. + */ + private static function arrayFilterRecursive(array $array, callable $callable = NULL): array { + foreach ($array as &$element) { + if (is_array($element)) { + $element = static::arrayFilterRecursive($element, $callable); + } + } + + $array = is_callable($callable) ? array_filter($array, $callable) : array_filter($array); + return $array; + } + }