From 389974e639a78dbe2a8b9686534c9e4949b3d3cd Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 28 Oct 2023 10:52:22 +0900 Subject: [PATCH 1/3] feat: add `config:check` command to check Config vaules --- system/Commands/Utilities/ConfigCheck.php | 146 ++++++++++++ .../Commands/Utilities/ConfigCheckTest.php | 212 ++++++++++++++++++ 2 files changed, 358 insertions(+) create mode 100644 system/Commands/Utilities/ConfigCheck.php create mode 100644 tests/system/Commands/Utilities/ConfigCheckTest.php diff --git a/system/Commands/Utilities/ConfigCheck.php b/system/Commands/Utilities/ConfigCheck.php new file mode 100644 index 000000000000..3a9abf821b0a --- /dev/null +++ b/system/Commands/Utilities/ConfigCheck.php @@ -0,0 +1,146 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Commands\Utilities; + +use CodeIgniter\CLI\BaseCommand; +use CodeIgniter\CLI\CLI; +use CodeIgniter\Config\BaseConfig; +use Kint\Kint; + +/** + * Check the Config values. + * + * @see \CodeIgniter\Commands\Utilities\ConfigCheckTest + */ +final class ConfigCheck extends BaseCommand +{ + /** + * The group the command is lumped under + * when listing commands. + * + * @var string + */ + protected $group = 'CodeIgniter'; + + /** + * The Command's name + * + * @var string + */ + protected $name = 'config:check'; + + /** + * The Command's short description + * + * @var string + */ + protected $description = 'Check your Config values.'; + + /** + * The Command's usage + * + * @var string + */ + protected $usage = 'config:check '; + + /** + * The Command's arguments + * + * @var array + */ + protected $arguments = [ + 'classname' => 'The config classname to check. Short classname or FQCN.', + ]; + + /** + * The Command's options + * + * @var array + */ + protected $options = []; + + /** + * {@inheritDoc} + */ + public function run(array $params) + { + if (! isset($params[0])) { + CLI::error('You must specify a Config classname.'); + CLI::write(' Usage: ' . $this->usage); + CLI::write('Example: config:check App'); + CLI::write(' config:check \'CodeIgniter\Shield\Config\Auth\''); + + return EXIT_ERROR; + } + + /** @var class-string $class */ + $class = $params[0]; + + $config = config($class); + + if ($config === null) { + CLI::error('No such Config class: ' . $class); + + return EXIT_ERROR; + } + + if (defined('KINT_DIR') && Kint::$enabled_mode !== false) { + CLI::write($this->getKintD($config)); + } else { + CLI::write( + CLI::color($this->getVarDump($config), 'cyan') + ); + } + + return EXIT_SUCCESS; + } + + /** + * Gets object dump by Kint d() + */ + private function getKintD(object $config): string + { + ob_start(); + d($config); + $output = ob_get_clean(); + + $output = trim($output); + $output = preg_replace( + '/\x1b\[36m.*┘\x1b\[0m/su', + '', + $output + ); + $output = preg_replace( + '/\x1b\[36m.*Called from .*\x1b\[0m/su', + '', + $output + ); + + return trim($output); + } + + /** + * Gets object dump by var_dump() + */ + private function getVarDump(object $config): string + { + ob_start(); + var_dump($config); + $output = ob_get_clean(); + + return preg_replace( + '!.*system/Commands/Utilities/ConfigCheck.php.*\n!u', + '', + $output + ); + } +} diff --git a/tests/system/Commands/Utilities/ConfigCheckTest.php b/tests/system/Commands/Utilities/ConfigCheckTest.php new file mode 100644 index 000000000000..664a9cf64b7a --- /dev/null +++ b/tests/system/Commands/Utilities/ConfigCheckTest.php @@ -0,0 +1,212 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Commands\Utilities; + +use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\StreamFilterTrait; +use Config\App; +use Config\Services; + +/** + * @internal + * + * @group Others + */ +final class ConfigCheckTest extends CIUnitTestCase +{ + use StreamFilterTrait; + + protected function setUp(): void + { + $this->resetServices(); + parent::setUp(); + } + + protected function tearDown(): void + { + $this->resetServices(); + parent::tearDown(); + } + + protected function getBuffer() + { + return $this->getStreamFilterBuffer(); + } + + public function testCommandConfigCheckNoArg(): void + { + command('config:check'); + + $this->assertStringContainsString( + 'You must specify a Config classname.', + $this->getBuffer() + ); + } + + public function testCommandConfigCheckApp(): void + { + command('config:check App'); + + $this->assertStringContainsString(App::class, $this->getBuffer()); + $this->assertStringContainsString("public 'baseURL", $this->getBuffer()); + } + + public function testCommandConfigCheckNonexistentClass(): void + { + command('config:check Nonexistent'); + + $this->assertStringContainsString( + 'No such Config class: Nonexistent', + $this->getBuffer() + ); + } + + public function testGetKintD() + { + $command = new ConfigCheck(Services::logger(), Services::commands()); + $getKintD = $this->getPrivateMethodInvoker($command, 'getKintD'); + + $output = $getKintD(new App()); + + $output = preg_replace( + '/(\033\[[0-9;]+m)|(\035\[[0-9;]+m)/u', + '', + $output + ); + + $this->assertStringContainsString( + 'Config\App#', + $output + ); + $this->assertStringContainsString( + <<<'EOL' + ( + public 'baseURL' -> string (19) "http://example.com/" + public 'allowedHostnames' -> array (0) [] + public 'indexPage' -> string (9) "index.php" + public 'uriProtocol' -> string (11) "REQUEST_URI" + public 'defaultLocale' -> string (2) "en" + public 'negotiateLocale' -> boolean false + public 'supportedLocales' -> array (1) [ + 0 => string (2) "en" + ] + public 'appTimezone' -> string (3) "UTC" + public 'charset' -> string (5) "UTF-8" + public 'forceGlobalSecureRequests' -> boolean false + public 'proxyIPs' -> array (0) [] + public 'CSPEnabled' -> boolean false + EOL, + $output + ); + } + + public function testGetVarDump() + { + $command = new ConfigCheck(Services::logger(), Services::commands()); + $getVarDump = $this->getPrivateMethodInvoker($command, 'getVarDump'); + + $output = $getVarDump(new App()); + + if ( + ini_get('xdebug.mode') + && in_array( + 'develop', + explode(',', ini_get('xdebug.mode')), + true + ) + ) { + // Xdebug overloads var_dump(). + $this->assertStringContainsString( + 'class Config\App#', + $output + ); + $this->assertStringContainsString( + <<<'EOL' + { + public string $baseURL => + string(19) "http://example.com/" + public array $allowedHostnames => + array(0) { + } + public string $indexPage => + string(9) "index.php" + public string $uriProtocol => + string(11) "REQUEST_URI" + public string $defaultLocale => + string(2) "en" + public bool $negotiateLocale => + bool(false) + public array $supportedLocales => + array(1) { + [0] => + string(2) "en" + } + public string $appTimezone => + string(3) "UTC" + public string $charset => + string(5) "UTF-8" + public bool $forceGlobalSecureRequests => + bool(false) + public array $proxyIPs => + array(0) { + } + public bool $CSPEnabled => + bool(false) + } + EOL, + $output + ); + } else { + // PHP's var_dump(). + $this->assertStringContainsString( + 'object(Config\App)#', + $output + ); + $this->assertStringContainsString( + <<<'EOL' + { + ["baseURL"]=> + string(19) "http://example.com/" + ["allowedHostnames"]=> + array(0) { + } + ["indexPage"]=> + string(9) "index.php" + ["uriProtocol"]=> + string(11) "REQUEST_URI" + ["defaultLocale"]=> + string(2) "en" + ["negotiateLocale"]=> + bool(false) + ["supportedLocales"]=> + array(1) { + [0]=> + string(2) "en" + } + ["appTimezone"]=> + string(3) "UTC" + ["charset"]=> + string(5) "UTF-8" + ["forceGlobalSecureRequests"]=> + bool(false) + ["proxyIPs"]=> + array(0) { + } + ["CSPEnabled"]=> + bool(false) + } + EOL, + $output + ); + } + } +} From 338edce7e5b75fea5fadf661cc8b8186c5652277 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 28 Oct 2023 19:04:20 +0900 Subject: [PATCH 2/3] docs: add docs --- user_guide_src/source/changelogs/v4.5.0.rst | 2 + .../source/general/configuration.rst | 48 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.5.0.rst b/user_guide_src/source/changelogs/v4.5.0.rst index 80ae4c87ac31..2c1ce4b00953 100644 --- a/user_guide_src/source/changelogs/v4.5.0.rst +++ b/user_guide_src/source/changelogs/v4.5.0.rst @@ -172,6 +172,8 @@ Enhancements Commands ======== +- Added ``spark config:check`` command to check Config values. See + :ref:`confirming-config-values` for the details. - Added ``spark lang:find`` command to update translations keys. See :ref:`generating-translation-files-via-command` for the details. Testing diff --git a/user_guide_src/source/general/configuration.rst b/user_guide_src/source/general/configuration.rst index 45ecce84108d..5006a49a1cf0 100644 --- a/user_guide_src/source/general/configuration.rst +++ b/user_guide_src/source/general/configuration.rst @@ -174,6 +174,8 @@ Some environments, e.g., Docker, CloudFormation, do not permit variable name wit app_forceGlobalSecureRequests = true app_CSPEnabled = true +.. _configuration-classes-and-environment-variables: + Configuration Classes and Environment Variables *********************************************** @@ -351,3 +353,49 @@ the three properties declared, but the value of the ``$target`` property will be by treating ``RegionalSales`` as a "registrar". The resulting configuration properties: .. literalinclude:: configuration/011.php + +.. _confirming-config-values: + +Confirming Config Values +************************ + +The actual Config object property values are changed at runtime by the :ref:`registrars` +and :ref:`Environment Variables `. + +CodeIgniter has the following :doc:`command <../cli/spark_commands>` to check +Config values. + +.. _spark-config-check: + +config:check +============ + +.. versionadded:: 4.5.0 + +For example, if you want to check the ``Config\App`` instance: + +.. code-block:: console + + php spark config:check App + +The output is like the following: + +.. code-block:: none + + Config\App#6 (12) ( + public 'baseURL' -> string (22) "http://localhost:8080/" + public 'allowedHostnames' -> array (0) [] + public 'indexPage' -> string (9) "index.php" + public 'uriProtocol' -> string (11) "REQUEST_URI" + public 'defaultLocale' -> string (2) "en" + public 'negotiateLocale' -> boolean false + public 'supportedLocales' -> array (1) [ + 0 => string (2) "en" + ] + public 'appTimezone' -> string (3) "UTC" + public 'charset' -> string (5) "UTF-8" + public 'forceGlobalSecureRequests' -> boolean false + public 'proxyIPs' -> array (0) [] + public 'CSPEnabled' -> boolean false + ) + From 7374b584e318d932405002564f108bb29f5dd349 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 28 Oct 2023 22:17:43 +0900 Subject: [PATCH 3/3] fix: can't output Config\Encryption if it has a binary string key --- system/Commands/Utilities/ConfigCheck.php | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/system/Commands/Utilities/ConfigCheck.php b/system/Commands/Utilities/ConfigCheck.php index 3a9abf821b0a..3ab45cc25f1f 100644 --- a/system/Commands/Utilities/ConfigCheck.php +++ b/system/Commands/Utilities/ConfigCheck.php @@ -114,18 +114,12 @@ private function getKintD(object $config): string $output = ob_get_clean(); $output = trim($output); - $output = preg_replace( - '/\x1b\[36m.*┘\x1b\[0m/su', - '', - $output - ); - $output = preg_replace( - '/\x1b\[36m.*Called from .*\x1b\[0m/su', - '', - $output - ); - return trim($output); + $lines = explode("\n", $output); + array_splice($lines, 0, 3); + array_splice($lines, -3); + + return implode("\n", $lines); } /**