Browse Source

Update PluginUnloadCommand to modify new plugins config file.

ADmad 3 years ago
parent
commit
4c4bf66a15
2 changed files with 69 additions and 144 deletions
  1. 35 35
      src/Command/PluginUnloadCommand.php
  2. 34 109
      tests/TestCase/Command/PluginUnloadCommandTest.php

+ 35 - 35
src/Command/PluginUnloadCommand.php

@@ -19,6 +19,7 @@ namespace Cake\Command;
 use Cake\Console\Arguments;
 use Cake\Console\ConsoleIo;
 use Cake\Console\ConsoleOptionParser;
+use Cake\Utility\Hash;
 
 /**
  * Command for unloading plugins.
@@ -26,6 +27,13 @@ use Cake\Console\ConsoleOptionParser;
 class PluginUnloadCommand extends Command
 {
     /**
+     * Config file
+     *
+     * @var string
+     */
+    protected string $configFile = CONFIG . 'plugins.php';
+
+    /**
      * @inheritDoc
      */
     public static function defaultName(): string
@@ -42,55 +50,46 @@ class PluginUnloadCommand extends Command
      */
     public function execute(Arguments $args, ConsoleIo $io): ?int
     {
-        $plugin = $args->getArgument('plugin');
-        if (!$plugin) {
-            $io->err('You must provide a plugin name in CamelCase format.');
-            $io->err('To unload an "Example" plugin, run `cake plugin unload Example`.');
-
-            return static::CODE_ERROR;
-        }
-
-        $app = APP . 'Application.php';
-        if (file_exists($app) && $this->modifyApplication($app, $plugin)) {
-            $io->out('');
-            $io->out(sprintf('%s modified', $app));
+        $plugin = (string)$args->getArgument('plugin');
 
+        $result = $this->modifyConfigFile($plugin);
+        if ($result === null) {
             return static::CODE_SUCCESS;
         }
 
+        $io->err($result);
+
         return static::CODE_ERROR;
     }
 
     /**
-     * Modify the application class.
+     * Modify the plugins config file.
      *
-     * @param string $app Path to the application to update.
-     * @param string $plugin Name of plugin.
-     * @return bool If modify passed.
+     * @param string $plugin Plugin name.
+     * @return string|null
      */
-    protected function modifyApplication(string $app, string $plugin): bool
+    protected function modifyConfigFile(string $plugin): ?string
     {
-        $plugin = preg_quote($plugin, '/');
-        $finder = "/
-            # whitespace and addPlugin call
-            \s*\\\$this\-\>addPlugin\(
-            # plugin name in quotes of any kind
-            \s*['\"]{$plugin}['\"]
-            # method arguments assuming a literal array with multiline args
-            (\s*,[\s\\n]*\[(\\n.*|.*){0,5}\][\\n\s]*)?
-            # closing paren of method
-            \);/mx";
-
-        $content = file_get_contents($app);
-        $newContent = preg_replace($finder, '', $content);
-
-        if ($newContent === $content) {
-            return false;
+        // phpcs:ignore
+        $config = @include $this->configFile;
+        if (!is_array($config)) {
+            return '`CONFIG/plugins.php` not found or does not return an array';
+        }
+
+        $config = Hash::normalize($config);
+        if (!array_key_exists($plugin, $config)) {
+            return sprintf('Plugin `%s` could not be found', $plugin);
         }
 
-        file_put_contents($app, $newContent);
+        unset($config[$plugin]);
+
+        $contents = '<?php' . "\n" . 'return ' . var_export($config, true) . ';';
+
+        if (file_put_contents($this->configFile, $contents)) {
+            return null;
+        }
 
-        return true;
+        return 'Failed to update `CONFIG/plugins.php`';
     }
 
     /**
@@ -106,6 +105,7 @@ class PluginUnloadCommand extends Command
         ])
         ->addArgument('plugin', [
             'help' => 'Name of the plugin to unload.',
+            'required' => true,
         ]);
 
         return $parser;

+ 34 - 109
tests/TestCase/Command/PluginUnloadCommandTest.php

@@ -29,12 +29,12 @@ class PluginUnloadCommandTest extends TestCase
     /**
      * @var string
      */
-    protected $app;
+    protected $configFile;
 
     /**
      * @var string
      */
-    protected $originalAppContent;
+    protected $originalContent;
 
     /**
      * setUp method
@@ -42,9 +42,20 @@ class PluginUnloadCommandTest extends TestCase
     public function setUp(): void
     {
         parent::setUp();
-        $this->app = APP . DS . 'Application.php';
 
-        $this->originalAppContent = file_get_contents($this->app);
+        $this->configFile = CONFIG . 'plugins.php';
+        $this->originalContent = file_get_contents($this->configFile);
+
+        $contents = <<<CONTENTS
+        <?php
+        return [
+            'TestPlugin' => ['routes' => false],
+            'TestPluginTwo',
+            'Company/TestPluginThree'
+        ];
+        CONTENTS;
+
+        file_put_contents($this->configFile, $contents);
 
         $this->setAppNamespace();
     }
@@ -55,133 +66,47 @@ class PluginUnloadCommandTest extends TestCase
     public function tearDown(): void
     {
         parent::tearDown();
-        $this->clearPlugins();
 
-        file_put_contents($this->app, $this->originalAppContent);
+        file_put_contents($this->configFile, $this->originalContent);
     }
 
     /**
      * testUnload
+     *
+     * @dataProvider pluginNameProvider
      */
-    public function testUnload(): void
+    public function testUnload($plugin): void
     {
-        $plugin1 = "\$this->addPlugin('TestPlugin', ['bootstrap' => false, 'routes' => false]);";
-        $plugin2 = "\$this->addPlugin('TestPluginTwo', ['bootstrap' => false, 'routes' => false]);";
-        $this->addPluginToApp($plugin1);
-        $this->addPluginToApp($plugin2);
-        $this->exec('plugin unload TestPlugin');
+        $this->exec('plugin unload ' . $plugin);
 
         $this->assertExitCode(CommandInterface::CODE_SUCCESS);
-        $contents = file_get_contents($this->app);
+        $contents = file_get_contents($this->configFile);
 
-        $this->assertStringNotContainsString($plugin1, $contents);
-        $this->assertStringContainsString($plugin2, $contents);
+        $this->assertStringNotContainsString("'" . $plugin . "'", $contents);
+        $this->assertStringContainsString("'Company/TestPluginThree'", $contents);
     }
 
-    /**
-     * test removing the first plugin leaves the second behind.
-     */
-    public function testUnloadFirstPlugin(): void
-    {
-        $plugin1 = "\$this->addPlugin('TestPlugin');";
-        $plugin2 = "\$this->addPlugin('Vendor/TestPluginTwo');";
-        $this->addPluginToApp($plugin1);
-        $this->addPluginToApp($plugin2);
-        $this->exec('plugin unload Vendor/TestPluginTwo');
-
-        $this->assertExitCode(CommandInterface::CODE_SUCCESS);
-        $contents = file_get_contents($this->app);
-
-        $this->assertStringNotContainsString($plugin2, $contents);
-        $this->assertStringContainsString($plugin1, $contents);
-    }
-
-    /**
-     * Data provider for various forms.
-     *
-     * @return array
-     */
-    public function variantProvider(): array
+    public function pluginNameProvider()
     {
         return [
-            //  $this->addPlugin('TestPlugin', [
-            //      'bootstrap' => false
-            //  ]);
-            ["        \$this->addPlugin('TestPlugin', [\n\t'bootstrap' => false\n]);\n"],
-
-            //  $this->addPlugin(
-            //      'TestPlugin',
-            //      [ 'bootstrap' => false]
-            //  );
-            ["        \$this->addPlugin(\n\t'TestPlugin',\n\t[ 'bootstrap' => false]\n);\n"],
-
-            //  $this->addPlugin(
-            //      'Foo',
-            //      [
-            //          'bootstrap' => false
-            //      ]
-            //  );
-            ["        \$this->addPlugin(\n\t'TestPlugin',\n\t[\n\t\t'bootstrap' => false\n\t]\n);\n"],
-
-            //  $this->addPlugin('Test', [
-            //      'bootstrap' => true,
-            //      'routes' => true
-            //  ]);
-            ["        \$this->addPlugin('TestPlugin', [\n\t'bootstrap' => true,\n\t'routes' => true\n]);\n"],
-
-            //  $this->addPlugin('Test',
-            //      [
-            //          'bootstrap' => true,
-            //          'routes' => true
-            //      ]
-            //  );
-            ["        \$this->addPlugin('TestPlugin',\n\t[\n\t\t'bootstrap' => true,\n\t\t'routes' => true\n\t]\n);\n"],
-
-            //  $this->addPlugin('Test',
-            //      [
-            //
-            //      ]
-            //  );
-            ["        \$this->addPlugin('TestPlugin',\n\t[\n\t\n\t]\n);\n"],
-
-            //  $this->addPlugin('Test');
-            ["        \$this->addPlugin('TestPlugin');\n"],
-
-            //  $this->addPlugin('Test', ['bootstrap' => true, 'route' => false]);
-            ["        \$this->addPlugin('TestPlugin', ['bootstrap' => true, 'route' => false]);\n"],
+            ['TestPlugin'],
+            ['TestPluginTwo'],
         ];
     }
 
-    /**
-     * This method will tests multiple notations of plugin loading in the application class
-     *
-     * @dataProvider variantProvider
-     */
-    public function testRegularExpressionsApplication(string $content): void
+    public function testUnloadNoConfigFile(): void
     {
-        $this->addPluginToApp($content);
+        unlink($this->configFile);
 
         $this->exec('plugin unload TestPlugin');
-        $this->assertExitCode(CommandInterface::CODE_SUCCESS);
-
-        $result = file_get_contents($this->app);
-
-        $this->assertStringNotContainsString("addPlugin('TestPlugin'", $result);
-        $this->assertDoesNotMatchRegularExpression("/this\-\>addPlugin\([\'\"]TestPlugin'[\'\"][^\)]*\)\;/mi", $result);
+        $this->assertExitCode(CommandInterface::CODE_ERROR);
+        $this->assertErrorContains('`CONFIG/plugins.php` not found or does not return an array');
     }
 
-    /**
-     * _addPluginToApp
-     *
-     * Quick method to add a plugin to the Application file.
-     * This is useful for the tests
-     *
-     * @param string $insert The addPlugin line to add.
-     */
-    protected function addPluginToApp($insert): void
+    public function testUnloadUnknownPlugin(): void
     {
-        $contents = file_get_contents($this->app);
-        $contents = preg_replace('/(function bootstrap\(\)(?:\s*)\:(?:\s*)void(?:\s+)\{)/m', "\$1\n        " . $insert, $contents);
-        file_put_contents($this->app, $contents);
+        $this->exec('plugin unload NopeNotThere');
+        $this->assertExitCode(CommandInterface::CODE_ERROR);
+        $this->assertErrorContains('Plugin `NopeNotThere` could not be found');
     }
 }