Browse Source

Merge branch '4.x' into 4.x-connection-cache

Mark Story 6 years ago
parent
commit
ed37867924

+ 84 - 0
src/Command/SchemacacheBuildCommand.php

@@ -0,0 +1,84 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+ * @link          https://cakephp.org CakePHP(tm) Project
+ * @since         3.6.0
+ * @license       https://opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\Command;
+
+use Cake\Console\Arguments;
+use Cake\Console\Command;
+use Cake\Console\ConsoleIo;
+use Cake\Console\ConsoleOptionParser;
+use Cake\Database\SchemaCache;
+use Cake\Datasource\ConnectionManager;
+use RuntimeException;
+
+/**
+ * Provides CLI tool for updating schema cache.
+ */
+class SchemacacheBuildCommand extends Command
+{
+    /**
+     * Display all routes in an application
+     *
+     * @param \Cake\Console\Arguments $args The command arguments.
+     * @param \Cake\Console\ConsoleIo $io The console io
+     * @return null|int The exit code or null for success
+     */
+    public function execute(Arguments $args, ConsoleIo $io): ?int
+    {
+        try {
+            /** @var \Cake\Database\Connection $connection */
+            $connection = ConnectionManager::get((string)$args->getOption('connection'));
+
+            $cache = new SchemaCache($connection);
+        } catch (RuntimeException $e) {
+            $io->error($e->getMessage());
+
+            return static::CODE_ERROR;
+        }
+        $tables = $cache->build($args->getArgument('name'));
+
+        foreach ($tables as $table) {
+            $io->verbose(sprintf('Cached "%s"', $table));
+        }
+
+        $io->out('<success>Cache build complete</success>');
+
+        return static::CODE_SUCCESS;
+    }
+
+    /**
+     * Get the option parser.
+     *
+     * @param \Cake\Console\ConsoleOptionParser $parser The option parser to update
+     * @return \Cake\Console\ConsoleOptionParser
+     */
+    public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser
+    {
+        $parser->setDescription(
+            'Build all metadata caches for the connection. If a ' .
+            'table name is provided, only that table will be cached.'
+        )->addOption('connection', [
+            'help' => 'The connection to build/clear metadata cache data for.',
+            'short' => 'c',
+            'default' => 'default',
+        ])->addArgument('name', [
+            'help' => 'A specific table you want to refresh cached data for.',
+            'optional' => true,
+        ]);
+
+        return $parser;
+    }
+}

+ 84 - 0
src/Command/SchemacacheClearCommand.php

@@ -0,0 +1,84 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
+ * @link          https://cakephp.org CakePHP(tm) Project
+ * @since         3.6.0
+ * @license       https://opensource.org/licenses/mit-license.php MIT License
+ */
+namespace Cake\Command;
+
+use Cake\Console\Arguments;
+use Cake\Console\Command;
+use Cake\Console\ConsoleIo;
+use Cake\Console\ConsoleOptionParser;
+use Cake\Database\SchemaCache;
+use Cake\Datasource\ConnectionManager;
+use RuntimeException;
+
+/**
+ * Provides CLI tool for clearing schema cache.
+ */
+class SchemacacheClearCommand extends Command
+{
+    /**
+     * Display all routes in an application
+     *
+     * @param \Cake\Console\Arguments $args The command arguments.
+     * @param \Cake\Console\ConsoleIo $io The console io
+     * @return null|int The exit code or null for success
+     */
+    public function execute(Arguments $args, ConsoleIo $io): ?int
+    {
+        try {
+            /** @var \Cake\Database\Connection $connection */
+            $connection = ConnectionManager::get((string)$args->getOption('connection'));
+
+            $cache = new SchemaCache($connection);
+        } catch (RuntimeException $e) {
+            $io->error($e->getMessage());
+
+            return static::CODE_ERROR;
+        }
+        $tables = $cache->clear($args->getArgument('name'));
+
+        foreach ($tables as $table) {
+            $io->verbose(sprintf('Cleared "%s"', $table));
+        }
+
+        $io->out('<success>Cache clear complete</success>');
+
+        return static::CODE_SUCCESS;
+    }
+
+    /**
+     * Get the option parser.
+     *
+     * @param \Cake\Console\ConsoleOptionParser $parser The option parser to update
+     * @return \Cake\Console\ConsoleOptionParser
+     */
+    public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser
+    {
+        $parser->setDescription(
+            'Clear all metadata caches for the connection. If a ' .
+            'table name is provided, only that table will be removed.'
+        )->addOption('connection', [
+            'help' => 'The connection to build/clear metadata cache data for.',
+            'short' => 'c',
+            'default' => 'default',
+        ])->addArgument('name', [
+            'help' => 'A specific table you want to clear cached data for.',
+            'optional' => true,
+        ]);
+
+        return $parser;
+    }
+}

+ 10 - 0
src/Console/CommandScanner.php

@@ -67,6 +67,16 @@ class CommandScanner
             $command['name'] = str_replace('_', ' ', $command['name']);
             $command['fullName'] = str_replace('_', ' ', $command['fullName']);
             $commands[$i] = $command;
+
+            // Maintain backwards compatibility for schema_cache as it is likely
+            // hooked up to people's deploy tooling
+            if (strpos($command['name'], 'schemacache') === 0) {
+                $compat = [
+                    'name' => str_replace('schemacache', 'schema_cache', $command['name']),
+                    'fullName' => str_replace('schemacache', 'schema_cache', $command['fullName']),
+                ];
+                $commands[] = $compat + $command;
+            }
         }
 
         return $commands;

+ 0 - 116
src/Shell/SchemaCacheShell.php

@@ -1,116 +0,0 @@
-<?php
-declare(strict_types=1);
-
-/**
- * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- *
- * Licensed under The MIT License
- * For full copyright and license information, please see the LICENSE.txt
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- * @link          https://cakephp.org CakePHP(tm) Project
- * @since         3.6.0
- * @license       https://opensource.org/licenses/mit-license.php MIT License
- */
-namespace Cake\Shell;
-
-use Cake\Console\ConsoleOptionParser;
-use Cake\Console\Shell;
-use Cake\Database\SchemaCache;
-use Cake\Datasource\ConnectionManager;
-use RuntimeException;
-
-/**
- * Schema Cache Shell.
- *
- * Provides a CLI interface to the schema metadata caching features.
- * This tool is intended to be used by deployment scripts so that you
- * can prevent "thundering herd" effect on the metadata cache when new
- * versions of your application is deployed, or when migrations
- * requiring updated metadata are required.
- */
-class SchemaCacheShell extends Shell
-{
-    /**
-     * Build metadata.
-     *
-     * @param string|null $name The name of the table to build cache data for.
-     * @return bool
-     */
-    public function build(?string $name = null): bool
-    {
-        $cache = $this->_getSchemaCache();
-        $tables = $cache->build($name);
-
-        foreach ($tables as $table) {
-            $this->verbose(sprintf('Cached "%s"', $table));
-        }
-
-        $this->out('<success>Cache build complete</success>');
-
-        return true;
-    }
-
-    /**
-     * Clear metadata.
-     *
-     * @param string|null $name The name of the table to clear cache data for.
-     * @return void
-     */
-    public function clear(?string $name = null): void
-    {
-        $cache = $this->_getSchemaCache();
-        $tables = $cache->clear($name);
-
-        foreach ($tables as $table) {
-            $this->verbose(sprintf('Cleared "%s"', $table));
-        }
-
-        $this->out('<success>Cache clear complete</success>');
-    }
-
-    /**
-     * Gets the Schema Cache instance
-     *
-     * @return \Cake\Database\SchemaCache
-     */
-    protected function _getSchemaCache(): SchemaCache
-    {
-        try {
-            /** @var \Cake\Database\Connection $connection */
-            $connection = ConnectionManager::get($this->params['connection']);
-
-            return new SchemaCache($connection);
-        } catch (RuntimeException $e) {
-            $this->abort($e->getMessage());
-        }
-    }
-
-    /**
-     * Get the option parser for this shell.
-     *
-     * @return \Cake\Console\ConsoleOptionParser
-     */
-    public function getOptionParser(): ConsoleOptionParser
-    {
-        $parser = parent::getOptionParser();
-        $parser->addSubcommand('clear', [
-            'help' => 'Clear all metadata caches for the connection. If a ' .
-                'table name is provided, only that table will be removed.',
-        ])->addSubcommand('build', [
-            'help' => 'Build all metadata caches for the connection. If a ' .
-            'table name is provided, only that table will be cached.',
-        ])->addOption('connection', [
-            'help' => 'The connection to build/clear metadata cache data for.',
-            'short' => 'c',
-            'default' => 'default',
-        ])->addArgument('name', [
-            'help' => 'A specific table you want to clear/refresh cached data for.',
-            'optional' => true,
-        ]);
-
-        return $parser;
-    }
-}

+ 2 - 1
tests/TestCase/Command/HelpCommandTest.php

@@ -121,7 +121,8 @@ class HelpCommandTest extends TestCase
         $find = '<shell name="sample" call_as="sample" provider="TestApp\Shell\SampleShell" help="sample -h"';
         $this->assertOutputContains($find);
 
-        $find = '<shell name="schema_cache" call_as="schema_cache" provider="Cake\Shell\SchemaCacheShell" help="schema_cache -h"';
+        $find = '<shell name="schema_cache build" call_as="schema_cache build" ' .
+            'provider="Cake\Command\SchemacacheBuildCommand" help="schema_cache build -h"';
         $this->assertOutputContains($find);
 
         $find = '<shell name="test_plugin.sample" call_as="test_plugin.sample" provider="TestPlugin\Shell\SampleShell" help="test_plugin.sample -h"';

+ 26 - 40
tests/TestCase/Shell/SchemaCacheShellTest.php

@@ -14,21 +14,20 @@ declare(strict_types=1);
  * @since         3.6.0
  * @license       https://opensource.org/licenses/mit-license.php MIT License
  */
-namespace Cake\Test\TestCase\Shell;
+namespace Cake\Test\TestCase\Command;
 
 use Cake\Cache\Cache;
-use Cake\Console\ConsoleIo;
-use Cake\Console\Exception\StopException;
-use Cake\Database\SchemaCache;
 use Cake\Datasource\ConnectionManager;
-use Cake\Shell\SchemaCacheShell;
+use Cake\TestSuite\ConsoleIntegrationTestTrait;
 use Cake\TestSuite\TestCase;
 
 /**
- * SchemaCacheShell test.
+ * SchemacacheCommands test.
  */
-class SchemaCacheShellTest extends TestCase
+class SchemacacheCommandsTest extends TestCase
 {
+    use ConsoleIntegrationTestTrait;
+
     /**
      * Fixtures.
      *
@@ -46,6 +45,8 @@ class SchemaCacheShellTest extends TestCase
     public function setUp(): void
     {
         parent::setUp();
+        $this->setAppNamespace();
+        $this->useCommandRunner();
 
         $this->cache = $this->getMockBuilder('Cake\Cache\CacheEngine')->getMock();
         $this->cache->expects($this->any())
@@ -96,9 +97,8 @@ class SchemaCacheShellTest extends TestCase
     {
         $this->connection->cacheMetadata(false);
 
-        $shell = $this->getShell();
-        $shell->params['connection'] = 'test';
-        $shell->clear();
+        $this->exec('schema_cache clear --connection test');
+        $this->assertExitSuccess();
         $this->assertInstanceOf('Cake\Database\Schema\CachedCollection', $this->connection->getSchemaCollection());
     }
 
@@ -111,9 +111,8 @@ class SchemaCacheShellTest extends TestCase
     {
         $this->connection->cacheMetadata(false);
 
-        $shell = $this->getShell();
-        $shell->params['connection'] = 'test';
-        $shell->build();
+        $this->exec('schema_cache build --connection test');
+        $this->assertExitSuccess();
         $this->assertInstanceOf('Cake\Database\Schema\CachedCollection', $this->connection->getSchemaCollection());
     }
 
@@ -132,9 +131,8 @@ class SchemaCacheShellTest extends TestCase
             ->with('test_articles')
             ->will($this->returnValue(true));
 
-        $shell = $this->getShell();
-        $shell->params['connection'] = 'test';
-        $shell->build();
+        $this->exec('schema_cache build --connection test');
+        $this->assertExitSuccess();
     }
 
     /**
@@ -152,9 +150,8 @@ class SchemaCacheShellTest extends TestCase
             ->method('delete')
             ->will($this->returnValue(false));
 
-        $shell = $this->getShell();
-        $shell->params['connection'] = 'test';
-        $shell->build('articles');
+        $this->exec('schema_cache build --connection test articles');
+        $this->assertExitSuccess();
     }
 
     /**
@@ -174,9 +171,8 @@ class SchemaCacheShellTest extends TestCase
             ->method('delete')
             ->will($this->returnValue(false));
 
-        $shell = $this->getShell();
-        $shell->params['connection'] = 'test';
-        $shell->build('articles');
+        $this->exec('schema_cache build --connection test articles');
+        $this->assertExitSuccess();
     }
 
     /**
@@ -186,12 +182,8 @@ class SchemaCacheShellTest extends TestCase
      */
     public function testBuildInvalidConnection()
     {
-        $this->expectException(StopException::class);
-
-        $io = $this->getMockBuilder(ConsoleIo::class)->getMock();
-        $shell = new SchemaCacheShell($io);
-        $shell->params['connection'] = 'derpy-derp';
-        $shell->build('articles');
+        $this->exec('schema_cache build --connection derpy-derp articles');
+        $this->assertExitError();
     }
 
     /**
@@ -201,12 +193,8 @@ class SchemaCacheShellTest extends TestCase
      */
     public function testClearInvalidConnection()
     {
-        $this->expectException(StopException::class);
-
-        $io = $this->getMockBuilder(ConsoleIo::class)->getMock();
-        $shell = new SchemaCacheShell($io);
-        $shell->params['connection'] = 'derpy-derp';
-        $shell->clear('articles');
+        $this->exec('schema_cache clear --connection derpy-derp articles');
+        $this->assertExitError();
     }
 
     /**
@@ -222,9 +210,8 @@ class SchemaCacheShellTest extends TestCase
             ->method('delete')
             ->with('test_articles');
 
-        $shell = $this->getShell();
-        $shell->params['connection'] = 'test';
-        $shell->clear();
+        $this->exec('schema_cache clear --connection test');
+        $this->assertExitSuccess();
     }
 
     /**
@@ -242,8 +229,7 @@ class SchemaCacheShellTest extends TestCase
             ->with('test_articles')
             ->will($this->returnValue(false));
 
-        $shell = $this->getShell();
-        $shell->params['connection'] = 'test';
-        $shell->clear('articles');
+        $this->exec('schema_cache clear --connection test articles');
+        $this->assertExitSuccess();
     }
 }

+ 2 - 1
tests/TestCase/Console/CommandCollectionTest.php

@@ -263,7 +263,8 @@ class CommandCollectionTest extends TestCase
         $this->assertTrue($collection->has('version'));
         $this->assertTrue($collection->has('routes'));
         $this->assertTrue($collection->has('i18n'));
-        $this->assertTrue($collection->has('schema_cache'));
+        $this->assertTrue($collection->has('schema_cache build'));
+        $this->assertTrue($collection->has('schema_cache clear'));
         $this->assertTrue($collection->has('server'));
         $this->assertTrue($collection->has('cache clear'));
         $this->assertFalse($collection->has('command_list'), 'Hidden commands should stay hidden');

+ 1 - 1
tests/TestCase/Console/CommandRunnerTest.php

@@ -259,7 +259,7 @@ class CommandRunnerTest extends TestCase
         $output = new ConsoleOutput();
 
         $runner = new CommandRunner($app, 'cake');
-        $result = $runner->run(['cake', 'SchemaCache', 'build'], $this->getMockIo($output));
+        $result = $runner->run(['cake', 'schema_cache', 'build'], $this->getMockIo($output));
         $this->assertSame(Shell::CODE_SUCCESS, $result);
 
         $contents = implode("\n", $output->messages());