Browse Source

Load routing in console environments.

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
mark_story 8 years ago
parent
commit
933151f9f4
2 changed files with 54 additions and 11 deletions
  1. 19 0
      src/Console/CommandRunner.php
  2. 35 11
      tests/TestCase/Console/CommandRunnerTest.php

+ 19 - 0
src/Console/CommandRunner.php

@@ -26,6 +26,7 @@ use Cake\Core\PluginApplicationInterface;
 use Cake\Event\EventDispatcherInterface;
 use Cake\Event\EventDispatcherTrait;
 use Cake\Event\EventManager;
+use Cake\Routing\Router;
 use Cake\Utility\Inflector;
 use InvalidArgumentException;
 use RuntimeException;
@@ -145,6 +146,7 @@ class CommandRunner implements EventDispatcherInterface
         }
         $this->checkCollection($commands, 'pluginConsole');
         $this->dispatchEvent('Console.buildCommands', ['commands' => $commands]);
+        $this->loadRoutes();
 
         if (empty($argv)) {
             throw new RuntimeException("Cannot run any commands. No arguments received.");
@@ -358,4 +360,21 @@ class CommandRunner implements EventDispatcherInterface
 
         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);
+        }
+    }
 }

+ 35 - 11
tests/TestCase/Console/CommandRunnerTest.php

@@ -24,6 +24,7 @@ use Cake\Core\ConsoleApplicationInterface;
 use Cake\Event\EventList;
 use Cake\Event\EventManager;
 use Cake\Http\BaseApplication;
+use Cake\Routing\Router;
 use Cake\TestSuite\Stub\ConsoleOutput;
 use Cake\TestSuite\TestCase;
 use InvalidArgumentException;
@@ -160,7 +161,7 @@ class CommandRunnerTest extends TestCase
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionMessage('Cannot run any commands. No arguments received.');
         $app = $this->getMockBuilder(BaseApplication::class)
-            ->setMethods(['middleware', 'bootstrap'])
+            ->setMethods(['middleware', 'bootstrap', 'routes'])
             ->setConstructorArgs([$this->config])
             ->getMock();
 
@@ -178,7 +179,7 @@ class CommandRunnerTest extends TestCase
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionMessage('Unknown command `cake nope`. Run `cake --help` to get the list of valid commands.');
         $app = $this->getMockBuilder(BaseApplication::class)
-            ->setMethods(['middleware', 'bootstrap'])
+            ->setMethods(['middleware', 'bootstrap', 'routes'])
             ->setConstructorArgs([$this->config])
             ->getMock();
 
@@ -194,7 +195,7 @@ class CommandRunnerTest extends TestCase
     public function testRunHelpLongOption()
     {
         $app = $this->getMockBuilder(BaseApplication::class)
-            ->setMethods(['middleware', 'bootstrap'])
+            ->setMethods(['middleware', 'bootstrap', 'routes'])
             ->setConstructorArgs([$this->config])
             ->getMock();
 
@@ -216,7 +217,7 @@ class CommandRunnerTest extends TestCase
     public function testRunHelpShortOption()
     {
         $app = $this->getMockBuilder(BaseApplication::class)
-            ->setMethods(['middleware', 'bootstrap'])
+            ->setMethods(['middleware', 'bootstrap', 'routes'])
             ->setConstructorArgs([$this->config])
             ->getMock();
 
@@ -237,7 +238,7 @@ class CommandRunnerTest extends TestCase
     public function testRunNoCommand()
     {
         $app = $this->getMockBuilder(BaseApplication::class)
-            ->setMethods(['middleware', 'bootstrap'])
+            ->setMethods(['middleware', 'bootstrap', 'routes'])
             ->setConstructorArgs([$this->config])
             ->getMock();
 
@@ -260,7 +261,7 @@ class CommandRunnerTest extends TestCase
     public function testRunVersionAlias()
     {
         $app = $this->getMockBuilder(BaseApplication::class)
-            ->setMethods(['middleware', 'bootstrap'])
+            ->setMethods(['middleware', 'bootstrap', 'routes'])
             ->setConstructorArgs([$this->config])
             ->getMock();
 
@@ -278,7 +279,7 @@ class CommandRunnerTest extends TestCase
     public function testRunValidCommand()
     {
         $app = $this->getMockBuilder(BaseApplication::class)
-            ->setMethods(['middleware', 'bootstrap'])
+            ->setMethods(['middleware', 'bootstrap', 'routes'])
             ->setConstructorArgs([$this->config])
             ->getMock();
 
@@ -301,7 +302,7 @@ class CommandRunnerTest extends TestCase
     public function testRunValidCommandInflection()
     {
         $app = $this->getMockBuilder(BaseApplication::class)
-            ->setMethods(['middleware', 'bootstrap'])
+            ->setMethods(['middleware', 'bootstrap', 'routes'])
             ->setConstructorArgs([$this->config])
             ->getMock();
 
@@ -432,7 +433,7 @@ class CommandRunnerTest extends TestCase
     public function testRunTriggersBuildCommandsEvent()
     {
         $app = $this->getMockBuilder(BaseApplication::class)
-            ->setMethods(['middleware', 'bootstrap'])
+            ->setMethods(['middleware', 'bootstrap', 'routes'])
             ->setConstructorArgs([$this->config])
             ->getMock();
 
@@ -454,7 +455,10 @@ class CommandRunnerTest extends TestCase
     public function testRunCallsPluginHookMethods()
     {
         $app = $this->getMockBuilder(BaseApplication::class)
-            ->setMethods(['middleware', 'bootstrap', 'pluginBootstrap', 'pluginEvents', 'pluginConsole'])
+            ->setMethods([
+                'middleware', 'bootstrap', 'routes',
+                'pluginBootstrap', 'pluginConsole', 'pluginRoutes'
+            ])
             ->setConstructorArgs([$this->config])
             ->getMock();
 
@@ -468,6 +472,8 @@ class CommandRunnerTest extends TestCase
             ->will($this->returnCallback(function ($commands) {
                 return $commands;
             }));
+        $app->expects($this->at(3))->method('routes');
+        $app->expects($this->at(4))->method('pluginRoutes');
 
         $output = new ConsoleOutput();
         $runner = new CommandRunner($app, 'cake');
@@ -475,10 +481,28 @@ class CommandRunnerTest extends TestCase
         $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)
     {
         $app = $this->getMockBuilder(BaseApplication::class)
-            ->setMethods(['middleware', 'bootstrap', 'console'])
+            ->setMethods(['middleware', 'bootstrap', 'console', 'routes'])
             ->setConstructorArgs([$this->config])
             ->getMock();
         $collection = new CommandCollection($commands);