From 6bd2f85d8a25dafab4004e4faff9e23e7756f625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Mon, 20 Jun 2022 01:07:41 +0200 Subject: [PATCH] Rework configuration helper (#661) --- .../Command/TestConfigurableCommand.php | 3 - .../ConfigurationLoader.php} | 36 ++---------- src/Console/Application.php | 9 --- src/Console/Command/BaseCommand.php | 6 -- .../Command/ConfigurableBaseCommand.php | 7 --- src/Console/Command/Validate.php | 4 +- src/Console/ConfigurationLoader.php | 12 ++-- src/Console/ConfigurationLocator.php | 53 ++++++++++++++++++ tests/Composer/ComposerOrchestratorTest.php | 8 +-- .../Configuration/ConfigurationLoaderTest.php | 55 +++++++++++++++++++ tests/Configuration/ConfigurationTestCase.php | 3 +- ...rTest.php => ConfigurationLocatorTest.php} | 51 ++--------------- 12 files changed, 133 insertions(+), 114 deletions(-) rename src/{Console/ConfigurationHelper.php => Configuration/ConfigurationLoader.php} (50%) create mode 100644 src/Console/ConfigurationLocator.php create mode 100644 tests/Configuration/ConfigurationLoaderTest.php rename tests/Console/{ConfigurationHelperTest.php => ConfigurationLocatorTest.php} (56%) diff --git a/fixtures/Console/Command/TestConfigurableCommand.php b/fixtures/Console/Command/TestConfigurableCommand.php index c25d12dfd..7d85c07bc 100644 --- a/fixtures/Console/Command/TestConfigurableCommand.php +++ b/fixtures/Console/Command/TestConfigurableCommand.php @@ -18,9 +18,6 @@ class TestConfigurableCommand extends ConfigurableBaseCommand { - /** - * {@inheritdoc} - */ protected function executeCommand(IO $io): int { return 0; diff --git a/src/Console/ConfigurationHelper.php b/src/Configuration/ConfigurationLoader.php similarity index 50% rename from src/Console/ConfigurationHelper.php rename to src/Configuration/ConfigurationLoader.php index 5960ed751..81405c65d 100644 --- a/src/Console/ConfigurationHelper.php +++ b/src/Configuration/ConfigurationLoader.php @@ -12,49 +12,25 @@ * with this source code in the file LICENSE. */ -namespace KevinGH\Box\Console; +namespace KevinGH\Box\Configuration; -use function file_exists; -use KevinGH\Box\Configuration\Configuration; -use KevinGH\Box\Configuration\NoConfigurationFound; use KevinGH\Box\Json\Json; -use function realpath; use stdClass; -use Symfony\Component\Console\Helper\Helper; /** * @private */ -final class ConfigurationHelper extends Helper +final class ConfigurationLoader { - private const FILE_NAME = 'box.json'; private const SCHEMA_FILE = __DIR__.'/../../res/schema.json'; - private $json; - - public function __construct() - { - $this->json = new Json(); - } - - public function getName(): string - { - return 'config'; - } - - public function findDefaultPath(): string + public function __construct(private readonly Json $json = new Json()) { - if (false === file_exists(self::FILE_NAME)) { - if (false === file_exists(self::FILE_NAME.'.dist')) { - throw new NoConfigurationFound(); - } - - return realpath(self::FILE_NAME.'.dist'); - } - - return realpath(self::FILE_NAME); } + /** + * @param null|non-empty-string $file + */ public function loadFile(?string $file): Configuration { if (null === $file) { diff --git a/src/Console/Application.php b/src/Console/Application.php index 59ccf9334..658d4ba24 100644 --- a/src/Console/Application.php +++ b/src/Console/Application.php @@ -17,7 +17,6 @@ use function KevinGH\Box\get_box_version; use function sprintf; use Symfony\Component\Console\Application as SymfonyApplication; -use Symfony\Component\Console\Helper\HelperSet; use function trim; /** @@ -82,12 +81,4 @@ protected function getDefaultCommands(): array return $commands; } - - protected function getDefaultHelperSet(): HelperSet - { - $helperSet = parent::getDefaultHelperSet(); - $helperSet->set(new ConfigurationHelper()); - - return $helperSet; - } } diff --git a/src/Console/Command/BaseCommand.php b/src/Console/Command/BaseCommand.php index c5c1e1e9c..a5a7dd05e 100644 --- a/src/Console/Command/BaseCommand.php +++ b/src/Console/Command/BaseCommand.php @@ -15,7 +15,6 @@ namespace KevinGH\Box\Console\Command; use KevinGH\Box\Console\Application; -use KevinGH\Box\Console\ConfigurationHelper; use KevinGH\Box\Console\IO\IO; use KevinGH\Box\Console\OutputFormatterConfigurator; use Symfony\Component\Console\Command\Command as SymfonyCommand; @@ -38,9 +37,4 @@ protected function execute(InputInterface $input, OutputInterface $output): int return $this->executeCommand(new IO($input, $output)); } - - final protected function getConfigurationHelper(): ConfigurationHelper - { - return $this->getHelper('config'); - } } diff --git a/src/Console/Command/ConfigurableBaseCommand.php b/src/Console/Command/ConfigurableBaseCommand.php index 97532ac28..d22efa11a 100644 --- a/src/Console/Command/ConfigurableBaseCommand.php +++ b/src/Console/Command/ConfigurableBaseCommand.php @@ -18,7 +18,6 @@ use KevinGH\Box\Console\ConfigurationLoader; use KevinGH\Box\Console\IO\IO; use KevinGH\Box\Json\JsonValidationException; -use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; /** @@ -51,14 +50,8 @@ final protected function getConfig(IO $io, bool $allowNoFile = false): Configura { return ConfigurationLoader::getConfig( $io->getInput()->getOption(self::CONFIG_PARAM), - $this->getConfigurationHelper(), $io, $allowNoFile, ); } - - final protected function getConfigPath(InputInterface $input): string - { - return $input->getOption(self::CONFIG_PARAM) ?? $this->getConfigurationHelper()->findDefaultPath(); - } } diff --git a/src/Console/Command/Validate.php b/src/Console/Command/Validate.php index f8a179165..ec68ce784 100644 --- a/src/Console/Command/Validate.php +++ b/src/Console/Command/Validate.php @@ -16,6 +16,7 @@ use Exception; use KevinGH\Box\Console\ConfigurationLoader; +use KevinGH\Box\Console\ConfigurationLocator; use KevinGH\Box\Console\IO\IO; use KevinGH\Box\Console\MessageRenderer; use KevinGH\Box\Json\JsonValidationException; @@ -70,8 +71,7 @@ protected function executeCommand(IO $io): int try { $config = ConfigurationLoader::getConfig( - $input->getArgument(self::FILE_ARGUMENT) ?? $this->getConfigurationHelper()->findDefaultPath(), - $this->getConfigurationHelper(), + $input->getArgument(self::FILE_ARGUMENT) ?? ConfigurationLocator::findDefaultPath(), $io, false, ); diff --git a/src/Console/ConfigurationLoader.php b/src/Console/ConfigurationLoader.php index dc5c89ab3..797f5f4f7 100644 --- a/src/Console/ConfigurationLoader.php +++ b/src/Console/ConfigurationLoader.php @@ -16,6 +16,7 @@ use InvalidArgumentException; use KevinGH\Box\Configuration\Configuration; +use KevinGH\Box\Configuration\ConfigurationLoader as ConfigLoader; use KevinGH\Box\Configuration\NoConfigurationFound; use KevinGH\Box\Console\IO\IO; use KevinGH\Box\Json\JsonValidationException; @@ -36,18 +37,18 @@ final class ConfigurationLoader * * @param bool $allowNoFile Load the config nonetheless if not file is found when true * - * @throws JsonValidationException + * @throws JsonValidationException|NoConfigurationFound */ public static function getConfig( ?string $configPath, - ConfigurationHelper $helper, IO $io, bool $allowNoFile, ): Configuration { - $configPath = self::getConfigPath($configPath, $helper, $io, $allowNoFile); + $configPath = self::getConfigPath($configPath, $io, $allowNoFile); + $configLoader = new ConfigLoader(); try { - return $helper->loadFile($configPath); + return $configLoader->loadFile($configPath); } catch (InvalidArgumentException $invalidConfig) { $io->error('The configuration file is invalid.'); @@ -57,12 +58,11 @@ public static function getConfig( private static function getConfigPath( ?string $configPath, - ConfigurationHelper $helper, IO $io, bool $allowNoFile, ): ?string { try { - $configPath ??= $helper->findDefaultPath(); + $configPath ??= ConfigurationLocator::findDefaultPath(); } catch (NoConfigurationFound $noConfigurationFound) { if (false === $allowNoFile) { throw $noConfigurationFound; diff --git a/src/Console/ConfigurationLocator.php b/src/Console/ConfigurationLocator.php new file mode 100644 index 000000000..d10ac9d04 --- /dev/null +++ b/src/Console/ConfigurationLocator.php @@ -0,0 +1,53 @@ + + * Théo Fidry + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace KevinGH\Box\Console; + +use function file_exists; +use KevinGH\Box\Configuration\NoConfigurationFound; +use KevinGH\Box\NotInstantiable; +use function realpath; + +/** + * @private + */ +final class ConfigurationLocator +{ + use NotInstantiable; + + private const FILE_NAME = 'box.json'; + + /** + * @var list + */ + private static array $candidates; + + public static function findDefaultPath(): string + { + if (!isset(self::$candidates)) { + self::$candidates = [ + self::FILE_NAME, + self::FILE_NAME.'.dist', + ]; + } + + foreach (self::$candidates as $candidate) { + if (file_exists($candidate)) { + return realpath($candidate); + } + } + + throw new NoConfigurationFound(); + } +} diff --git a/tests/Composer/ComposerOrchestratorTest.php b/tests/Composer/ComposerOrchestratorTest.php index 98ab38019..3d4a10781 100644 --- a/tests/Composer/ComposerOrchestratorTest.php +++ b/tests/Composer/ComposerOrchestratorTest.php @@ -528,7 +528,7 @@ public static function composerAutoloadProvider(): iterable echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; exit(1); } - + require_once __DIR__ . '/composer/autoload_real.php'; \$loader = ${composerAutoloaderName}::getLoader(); @@ -568,7 +568,7 @@ function foo() { echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; exit(1); } - + require_once __DIR__ . '/composer/autoload_real.php'; \$loader = ${composerAutoloaderName}::getLoader(); @@ -624,7 +624,7 @@ function foo() { echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; exit(1); } - + require_once __DIR__ . '/composer/autoload_real.php'; \$loader = ${composerAutoloaderName}::getLoader(); @@ -684,7 +684,7 @@ function foo() { echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; exit(1); } - + require_once __DIR__ . '/composer/autoload_real.php'; return ComposerAutoloaderInit80c62b20a4a44fb21e8e102ccb92ff05::getLoader(); diff --git a/tests/Configuration/ConfigurationLoaderTest.php b/tests/Configuration/ConfigurationLoaderTest.php new file mode 100644 index 000000000..907037473 --- /dev/null +++ b/tests/Configuration/ConfigurationLoaderTest.php @@ -0,0 +1,55 @@ + + * Théo Fidry + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + +namespace KevinGH\Box\Configuration; + +use function KevinGH\Box\FileSystem\dump_file; +use function KevinGH\Box\FileSystem\touch; +use KevinGH\Box\Test\FileSystemTestCase; + +/** + * @covers \KevinGH\Box\Configuration\ConfigurationLoader + */ +class ConfigurationLoaderTest extends FileSystemTestCase +{ + private ConfigurationLoader $loader; + + protected function setUp(): void + { + parent::setUp(); + + $this->loader = new ConfigurationLoader(); + } + + public function test_it_can_load_a_configuration(): void + { + touch('index.php'); + dump_file('box.json.dist', '{}'); + + $this->assertInstanceOf( + Configuration::class, + $this->loader->loadFile('box.json.dist'), + ); + } + + public function test_it_can_load_a_configuration_without_a_file(): void + { + touch('index.php'); + + $this->assertInstanceOf( + Configuration::class, + $this->loader->loadFile(null), + ); + } +} diff --git a/tests/Configuration/ConfigurationTestCase.php b/tests/Configuration/ConfigurationTestCase.php index be3b02206..c9b3d347a 100644 --- a/tests/Configuration/ConfigurationTestCase.php +++ b/tests/Configuration/ConfigurationTestCase.php @@ -16,7 +16,6 @@ use function json_encode; use const JSON_PRETTY_PRINT; -use KevinGH\Box\Console\ConfigurationHelper; use function KevinGH\Box\FileSystem\dump_file; use function KevinGH\Box\FileSystem\make_path_absolute; use function KevinGH\Box\FileSystem\touch; @@ -56,7 +55,7 @@ final protected function setConfig(array $config): void final protected function reloadConfig(): void { - $this->config = (new ConfigurationHelper())->loadFile($this->file); + $this->config = (new ConfigurationLoader())->loadFile($this->file); } final protected function isWindows(): bool diff --git a/tests/Console/ConfigurationHelperTest.php b/tests/Console/ConfigurationLocatorTest.php similarity index 56% rename from tests/Console/ConfigurationHelperTest.php rename to tests/Console/ConfigurationLocatorTest.php index 4c1a5bcad..5a95fdd01 100644 --- a/tests/Console/ConfigurationHelperTest.php +++ b/tests/Console/ConfigurationLocatorTest.php @@ -15,38 +15,22 @@ namespace KevinGH\Box\Console; use const DIRECTORY_SEPARATOR; -use KevinGH\Box\Configuration\Configuration; use KevinGH\Box\Configuration\NoConfigurationFound; -use function KevinGH\Box\FileSystem\dump_file; use function KevinGH\Box\FileSystem\touch; use KevinGH\Box\Test\FileSystemTestCase; /** - * @covers \KevinGH\Box\Console\ConfigurationHelper + * @covers \KevinGH\Box\Console\ConfigurationLocator */ -class ConfigurationHelperTest extends FileSystemTestCase +class ConfigurationLocatorTest extends FileSystemTestCase { - private ConfigurationHelper $helper; - - protected function setUp(): void - { - parent::setUp(); - - $this->helper = new ConfigurationHelper(); - } - - public function test_it_has_a_name(): void - { - $this->assertSame('config', $this->helper->getName()); - } - public function test_it_finds_the_default_path(): void { touch('box.json'); $this->assertSame( $this->tmp.DIRECTORY_SEPARATOR.'box.json', - $this->helper->findDefaultPath(), + ConfigurationLocator::findDefaultPath(), ); } @@ -56,7 +40,7 @@ public function test_it_finds_the_default_dist_path(): void $this->assertSame( $this->tmp.DIRECTORY_SEPARATOR.'box.json.dist', - $this->helper->findDefaultPath(), + ConfigurationLocator::findDefaultPath(), ); } @@ -67,37 +51,14 @@ public function test_it_non_dist_file_takes_priority_over_dist_file(): void $this->assertSame( $this->tmp.DIRECTORY_SEPARATOR.'box.json', - $this->helper->findDefaultPath(), - ); - } - - public function test_it_can_load_a_configuration(): void - { - touch('index.php'); - dump_file('box.json.dist', '{}'); - - $this->assertInstanceOf( - Configuration::class, - $this->helper->loadFile( - $this->helper->findDefaultPath(), - ), - ); - } - - public function test_it_can_load_a_configuration_without_a_file(): void - { - touch('index.php'); - - $this->assertInstanceOf( - Configuration::class, - $this->helper->loadFile(null), + ConfigurationLocator::findDefaultPath(), ); } public function test_it_throws_an_error_if_no_config_path_is_found(): void { try { - $this->helper->findDefaultPath(); + ConfigurationLocator::findDefaultPath(); $this->fail('Expected exception to be thrown.'); } catch (NoConfigurationFound $exception) {