diff --git a/system/Commands/Utilities/Optimize.php b/system/Commands/Utilities/Optimize.php index 46b24efb2da9..613029297e0c 100644 --- a/system/Commands/Utilities/Optimize.php +++ b/system/Commands/Utilities/Optimize.php @@ -25,6 +25,11 @@ */ final class Optimize extends BaseCommand { + private const CONFIG_CACHE = '$configCacheEnabled'; + private const LOCATOR_CACHE = '$locatorCacheEnabled'; + private const CONFIG_PATH = APPPATH . 'Config/Optimize.php'; + private const CACHE_PATH = WRITEPATH . 'cache/FactoriesCache_config'; + /** * The group the command is lumped under * when listing commands. @@ -52,17 +57,37 @@ final class Optimize extends BaseCommand * * @var string */ - protected $usage = 'optimize'; + protected $usage = 'optimize [-c] [-l] [-d]'; + + /** + * The Command's options + * + * @var array + */ + protected $options = [ + 'c' => 'Enable only config caching.', + 'l' => 'Enable only locator caching.', + 'd' => 'Disable config and locator caching.', + ]; /** * {@inheritDoc} */ public function run(array $params) { + // Parse options + $enableConfigCache = CLI::getOption('c'); + $enableLocatorCache = CLI::getOption('l'); + $disable = CLI::getOption('d'); + try { - $this->enableCaching(); + $this->runCaching($enableConfigCache, $enableLocatorCache, $disable); $this->clearCache(); - $this->removeDevPackages(); + if ($disable === true) { + $this->reinstallDevPackages(); + } else { + $this->removeDevPackages(); + } } catch (RuntimeException) { CLI::error('The "spark optimize" failed.'); @@ -78,8 +103,7 @@ private function clearCache(): void $locator->deleteCache(); CLI::write('Removed FileLocatorCache.', 'green'); - $cache = WRITEPATH . 'cache/FactoriesCache_config'; - $this->removeFile($cache); + $this->removeFile(self::CACHE_PATH); } private function removeFile(string $cache): void @@ -99,32 +123,100 @@ private function removeFile(string $cache): void } } - private function enableCaching(): void + private function runCaching(?bool $enableConfigCache, ?bool $enableLocatorCache, ?bool $disable): void { - $publisher = new Publisher(APPPATH, APPPATH); + // Prepare search and replace mappings + $searchReplace = []; - $config = APPPATH . 'Config/Optimize.php'; + if ($disable === true) { + $searchReplace = $this->disableCaching(); + } else { + $searchReplace = $this->enableCaching(['config' => $enableConfigCache, 'locator' => $enableLocatorCache]); + } - $result = $publisher->replace( - $config, - [ - 'public bool $configCacheEnabled = false;' => 'public bool $configCacheEnabled = true;', - 'public bool $locatorCacheEnabled = false;' => 'public bool $locatorCacheEnabled = true;', - ] - ); + // Apply replacements if necessary + if ($searchReplace !== []) { + $publisher = new Publisher(APPPATH, APPPATH); - if ($result) { - CLI::write( - 'Config Caching and FileLocator Caching are enabled in "app/Config/Optimize.php".', - 'green' - ); + $result = $publisher->replace(self::CONFIG_PATH, $searchReplace); - return; + if ($result === true) { + $messages = []; + + if (in_array('public bool ' . self::CONFIG_CACHE . ' = true;', $searchReplace, true)) { + $messages[] = 'Config Caching is enabled in "app/Config/Optimize.php".'; + } + + if (in_array('public bool ' . self::LOCATOR_CACHE . ' = true;', $searchReplace, true)) { + $messages[] = 'FileLocator Caching is enabled in "app/Config/Optimize.php".'; + } + + if (in_array('public bool ' . self::CONFIG_CACHE . ' = false;', $searchReplace, true)) { + $messages[] = 'Config Caching is disabled in "app/Config/Optimize.php".'; + } + + if (in_array('public bool ' . self::LOCATOR_CACHE . ' = false;', $searchReplace, true)) { + $messages[] = 'FileLocator Caching is disabled in "app/Config/Optimize.php".'; + } + + foreach ($messages as $message) { + CLI::write($message, 'green'); + CLI::newLine(); + } + + CLI::newLine(); + + return; + } + + CLI::error('Error in updating file: ' . clean_path(self::CONFIG_PATH)); + + throw new RuntimeException(__METHOD__); } + CLI::write('No changes to caching settings.', 'yellow'); + } - CLI::error('Error in updating file: ' . clean_path($config)); + /** + * Disable Caching + * + * @return array + */ + private function disableCaching(): array + { + return [ + 'public bool ' . self::CONFIG_CACHE . ' = true;' => 'public bool ' . self::CONFIG_CACHE . ' = false;', + 'public bool ' . self::LOCATOR_CACHE . ' = true;' => 'public bool ' . self::LOCATOR_CACHE . ' = false;', + ]; + } - throw new RuntimeException(__METHOD__); + /** + * Enable Caching + * + * @param array $options + * + * @return array + */ + private function enableCaching(array $options): array + { + $searchReplace = []; + + if ($options['config'] === true) { + $searchReplace['public bool ' . self::CONFIG_CACHE . ' = false;'] = 'public bool ' . self::CONFIG_CACHE . ' = true;'; + } + + if ($options['locator'] === true) { + $searchReplace['public bool ' . self::LOCATOR_CACHE . ' = false;'] = 'public bool ' . self::LOCATOR_CACHE . ' = true;'; + } + + // If no options provided, update both + if ($options['config'] === null && $options['locator'] === null) { + $searchReplace = [ + 'public bool ' . self::CONFIG_CACHE . ' = false;' => 'public bool ' . self::CONFIG_CACHE . ' = true;', + 'public bool ' . self::LOCATOR_CACHE . ' = false;' => 'public bool ' . self::LOCATOR_CACHE . ' = true;', + ]; + } + + return $searchReplace; } private function removeDevPackages(): void @@ -146,4 +238,24 @@ private function removeDevPackages(): void throw new RuntimeException(__METHOD__); } + + private function reinstallDevPackages(): void + { + if (! defined('VENDORPATH')) { + return; + } + + chdir(ROOTPATH); + passthru('composer install', $status); + + if ($status === 0) { + CLI::write('Installed Composer dev packages.', 'green'); + + return; + } + + CLI::error('Error in installing Composer dev packages.'); + + throw new RuntimeException(__METHOD__); + } } diff --git a/tests/system/Commands/Utilities/OptimizeTest.php b/tests/system/Commands/Utilities/OptimizeTest.php new file mode 100644 index 000000000000..48fe4fbe3b27 --- /dev/null +++ b/tests/system/Commands/Utilities/OptimizeTest.php @@ -0,0 +1,99 @@ + + * + * 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 PHPUnit\Framework\Attributes\Group; + +/** + * @internal + */ +#[Group('Others')] +final class OptimizeTest extends CIUnitTestCase +{ + use StreamFilterTrait; + + protected function setUp(): void + { + $this->resetServices(); + + parent::setUp(); + } + + protected function getBuffer(): string + { + return $this->getStreamFilterBuffer(); + } + + public function testEnableConfigCaching(): void + { + $command = new Optimize(service('logger'), service('commands')); + + $runCaching = $this->getPrivateMethodInvoker($command, 'runCaching'); + + // private function runCaching(?bool $enableConfigCache, ?bool $enableLocatorCache, ?bool $disable): void + $runCaching(true, null, null); + + // Check if config caching is enabled + $this->assertFileContains('public bool $configCacheEnabled = true;', APPPATH . 'Config/Optimize.php'); + } + + public function testEnableLocatorCaching(): void + { + $command = new Optimize(service('logger'), service('commands')); + + $runCaching = $this->getPrivateMethodInvoker($command, 'runCaching'); + + // private function runCaching(?bool $enableConfigCache, ?bool $enableLocatorCache, ?bool $disable): void + $runCaching(null, true, null); + + // Check if locator caching is enabled + $this->assertFileContains('public bool $locatorCacheEnabled = true;', APPPATH . 'Config/Optimize.php'); + } + + public function testDisableCaching(): void + { + $command = new Optimize(service('logger'), service('commands')); + + $runCaching = $this->getPrivateMethodInvoker($command, 'runCaching'); + + // private function runCaching(?bool $enableConfigCache, ?bool $enableLocatorCache, ?bool $disable): void + $runCaching(null, null, true); + + // Check if both caches are disabled + $this->assertFileContains('public bool $configCacheEnabled = false;', APPPATH . 'Config/Optimize.php'); + $this->assertFileContains('public bool $locatorCacheEnabled = false;', APPPATH . 'Config/Optimize.php'); + } + + public function testWithoutOptions(): void + { + $command = new Optimize(service('logger'), service('commands')); + + $runCaching = $this->getPrivateMethodInvoker($command, 'runCaching'); + + // private function runCaching(?bool $enableConfigCache, ?bool $enableLocatorCache, ?bool $disable): void + $runCaching(null, null, null); + + // Check if both caches are disabled + $this->assertFileContains('public bool $configCacheEnabled = true;', APPPATH . 'Config/Optimize.php'); + $this->assertFileContains('public bool $locatorCacheEnabled = true;', APPPATH . 'Config/Optimize.php'); + } + + protected function assertFileContains(string $needle, string $filePath): void + { + $this->assertFileExists($filePath); + $this->assertStringContainsString($needle, file_get_contents($filePath)); + } +} diff --git a/user_guide_src/source/installation/deployment.rst b/user_guide_src/source/installation/deployment.rst index 0eb206ee9d04..cf5ac4a396eb 100644 --- a/user_guide_src/source/installation/deployment.rst +++ b/user_guide_src/source/installation/deployment.rst @@ -28,6 +28,21 @@ The ``spark optimize`` command performs the following optimizations: - Enabling `Config Caching`_ - Enabling `FileLocator Caching`_ +If you want disable or restore the actions above, run ``spark optimize -d`` +it will do a restore to default settings, as follow: + +.. versionadded:: 4.6.0 + +- Reinstall Dev Packages +- Disabling `Config Caching`_ +- Disabling `FileLocator Caching`_ + +Available options: + +- `-c` Enable only config caching. +- `-l` Enable only locator caching. +- `-d` Disable config and locator caching. + Composer Optimization =====================