Skip to content

Commit

Permalink
Load routing in console environments.
Browse files Browse the repository at this point in the history
Ensure that the CommandRunner framework uses the application routes()
hook to load routes. This enables the routes shell and other
commands/shells to generate URLs properly.

Refs #12030
  • Loading branch information
markstory committed May 1, 2018
1 parent 0cb6d51 commit 933151f
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 11 deletions.
19 changes: 19 additions & 0 deletions src/Console/CommandRunner.php
Expand Up @@ -26,6 +26,7 @@
use Cake\Event\EventDispatcherInterface; use Cake\Event\EventDispatcherInterface;
use Cake\Event\EventDispatcherTrait; use Cake\Event\EventDispatcherTrait;
use Cake\Event\EventManager; use Cake\Event\EventManager;
use Cake\Routing\Router;
use Cake\Utility\Inflector; use Cake\Utility\Inflector;
use InvalidArgumentException; use InvalidArgumentException;
use RuntimeException; use RuntimeException;
Expand Down Expand Up @@ -145,6 +146,7 @@ public function run(array $argv, ConsoleIo $io = null)
} }
$this->checkCollection($commands, 'pluginConsole'); $this->checkCollection($commands, 'pluginConsole');
$this->dispatchEvent('Console.buildCommands', ['commands' => $commands]); $this->dispatchEvent('Console.buildCommands', ['commands' => $commands]);
$this->loadRoutes();


if (empty($argv)) { if (empty($argv)) {
throw new RuntimeException("Cannot run any commands. No arguments received."); throw new RuntimeException("Cannot run any commands. No arguments received.");
Expand Down Expand Up @@ -358,4 +360,21 @@ protected function createShell($className, ConsoleIo $io)


return $shell; return $shell;
} }

/**
* Ensure that the application's routes are loaded.
*
* Console commands and shells often need to generate URLs.
*
* @return void
*/
protected function loadRoutes()
{
$builder = Router::createRouteBuilder('/');

$this->app->routes($builder);
if ($this->app instanceof PluginApplicationInterface) {
$this->app->pluginRoutes($builder);
}
}
} }
46 changes: 35 additions & 11 deletions tests/TestCase/Console/CommandRunnerTest.php
Expand Up @@ -24,6 +24,7 @@
use Cake\Event\EventList; use Cake\Event\EventList;
use Cake\Event\EventManager; use Cake\Event\EventManager;
use Cake\Http\BaseApplication; use Cake\Http\BaseApplication;
use Cake\Routing\Router;
use Cake\TestSuite\Stub\ConsoleOutput; use Cake\TestSuite\Stub\ConsoleOutput;
use Cake\TestSuite\TestCase; use Cake\TestSuite\TestCase;
use InvalidArgumentException; use InvalidArgumentException;
Expand Down Expand Up @@ -160,7 +161,7 @@ public function testRunMissingRootCommand()
$this->expectException(\RuntimeException::class); $this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Cannot run any commands. No arguments received.'); $this->expectExceptionMessage('Cannot run any commands. No arguments received.');
$app = $this->getMockBuilder(BaseApplication::class) $app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap']) ->setMethods(['middleware', 'bootstrap', 'routes'])
->setConstructorArgs([$this->config]) ->setConstructorArgs([$this->config])
->getMock(); ->getMock();


Expand All @@ -178,7 +179,7 @@ public function testRunInvalidCommand()
$this->expectException(\RuntimeException::class); $this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('Unknown command `cake nope`. Run `cake --help` to get the list of valid commands.'); $this->expectExceptionMessage('Unknown command `cake nope`. Run `cake --help` to get the list of valid commands.');
$app = $this->getMockBuilder(BaseApplication::class) $app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap']) ->setMethods(['middleware', 'bootstrap', 'routes'])
->setConstructorArgs([$this->config]) ->setConstructorArgs([$this->config])
->getMock(); ->getMock();


Expand All @@ -194,7 +195,7 @@ public function testRunInvalidCommand()
public function testRunHelpLongOption() public function testRunHelpLongOption()
{ {
$app = $this->getMockBuilder(BaseApplication::class) $app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap']) ->setMethods(['middleware', 'bootstrap', 'routes'])
->setConstructorArgs([$this->config]) ->setConstructorArgs([$this->config])
->getMock(); ->getMock();


Expand All @@ -216,7 +217,7 @@ public function testRunHelpLongOption()
public function testRunHelpShortOption() public function testRunHelpShortOption()
{ {
$app = $this->getMockBuilder(BaseApplication::class) $app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap']) ->setMethods(['middleware', 'bootstrap', 'routes'])
->setConstructorArgs([$this->config]) ->setConstructorArgs([$this->config])
->getMock(); ->getMock();


Expand All @@ -237,7 +238,7 @@ public function testRunHelpShortOption()
public function testRunNoCommand() public function testRunNoCommand()
{ {
$app = $this->getMockBuilder(BaseApplication::class) $app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap']) ->setMethods(['middleware', 'bootstrap', 'routes'])
->setConstructorArgs([$this->config]) ->setConstructorArgs([$this->config])
->getMock(); ->getMock();


Expand All @@ -260,7 +261,7 @@ public function testRunNoCommand()
public function testRunVersionAlias() public function testRunVersionAlias()
{ {
$app = $this->getMockBuilder(BaseApplication::class) $app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap']) ->setMethods(['middleware', 'bootstrap', 'routes'])
->setConstructorArgs([$this->config]) ->setConstructorArgs([$this->config])
->getMock(); ->getMock();


Expand All @@ -278,7 +279,7 @@ public function testRunVersionAlias()
public function testRunValidCommand() public function testRunValidCommand()
{ {
$app = $this->getMockBuilder(BaseApplication::class) $app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap']) ->setMethods(['middleware', 'bootstrap', 'routes'])
->setConstructorArgs([$this->config]) ->setConstructorArgs([$this->config])
->getMock(); ->getMock();


Expand All @@ -301,7 +302,7 @@ public function testRunValidCommand()
public function testRunValidCommandInflection() public function testRunValidCommandInflection()
{ {
$app = $this->getMockBuilder(BaseApplication::class) $app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap']) ->setMethods(['middleware', 'bootstrap', 'routes'])
->setConstructorArgs([$this->config]) ->setConstructorArgs([$this->config])
->getMock(); ->getMock();


Expand Down Expand Up @@ -432,7 +433,7 @@ public function testRunValidCommandClassHelp()
public function testRunTriggersBuildCommandsEvent() public function testRunTriggersBuildCommandsEvent()
{ {
$app = $this->getMockBuilder(BaseApplication::class) $app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap']) ->setMethods(['middleware', 'bootstrap', 'routes'])
->setConstructorArgs([$this->config]) ->setConstructorArgs([$this->config])
->getMock(); ->getMock();


Expand All @@ -454,7 +455,10 @@ public function testRunTriggersBuildCommandsEvent()
public function testRunCallsPluginHookMethods() public function testRunCallsPluginHookMethods()
{ {
$app = $this->getMockBuilder(BaseApplication::class) $app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap', 'pluginBootstrap', 'pluginEvents', 'pluginConsole']) ->setMethods([
'middleware', 'bootstrap', 'routes',
'pluginBootstrap', 'pluginConsole', 'pluginRoutes'
])
->setConstructorArgs([$this->config]) ->setConstructorArgs([$this->config])
->getMock(); ->getMock();


Expand All @@ -468,17 +472,37 @@ public function testRunCallsPluginHookMethods()
->will($this->returnCallback(function ($commands) { ->will($this->returnCallback(function ($commands) {
return $commands; return $commands;
})); }));
$app->expects($this->at(3))->method('routes');
$app->expects($this->at(4))->method('pluginRoutes');


$output = new ConsoleOutput(); $output = new ConsoleOutput();
$runner = new CommandRunner($app, 'cake'); $runner = new CommandRunner($app, 'cake');
$result = $runner->run(['cake', '--version'], $this->getMockIo($output)); $result = $runner->run(['cake', '--version'], $this->getMockIo($output));
$this->assertContains(Configure::version(), $output->messages()[0]); $this->assertContains(Configure::version(), $output->messages()[0]);
} }


/**
* Test that run() loads routing.
*
* @return void
*/
public function testRunLoadsRoutes()
{
$app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap'])
->setConstructorArgs([TEST_APP . 'config' . DS])
->getMock();

$output = new ConsoleOutput();
$runner = new CommandRunner($app, 'cake');
$runner->run(['cake', '--version'], $this->getMockIo($output));
$this->assertGreaterThan(2, count(Router::getRouteCollection()->routes()));
}

protected function makeAppWithCommands($commands) protected function makeAppWithCommands($commands)
{ {
$app = $this->getMockBuilder(BaseApplication::class) $app = $this->getMockBuilder(BaseApplication::class)
->setMethods(['middleware', 'bootstrap', 'console']) ->setMethods(['middleware', 'bootstrap', 'console', 'routes'])
->setConstructorArgs([$this->config]) ->setConstructorArgs([$this->config])
->getMock(); ->getMock();
$collection = new CommandCollection($commands); $collection = new CommandCollection($commands);
Expand Down

0 comments on commit 933151f

Please sign in to comment.