Browse Source

Ensure base path is always part of URL context.

In scenarios where there is no active request (CLI tools) the current
request context was missing the base path. By setting the request
context earlier in the method we can add the base path when necessary.

Refs #12375
mark_story 7 years ago
parent
commit
793ff89587
2 changed files with 37 additions and 10 deletions
  1. 9 10
      src/Routing/Router.php
  2. 28 0
      tests/TestCase/Routing/RouterTest.php

+ 9 - 10
src/Routing/Router.php

@@ -616,23 +616,21 @@ class Router
             'action' => 'index',
             '_ext' => null,
         ];
-        $here = $base = $output = $frag = null;
+        $here = $output = $frag = null;
 
+        $context = static::$_requestContext;
         // In 4.x this should be replaced with state injected via setRequestContext
         $request = static::getRequest(true);
         if ($request) {
             $params = $request->getAttribute('params');
             $here = $request->getRequestTarget();
-            $base = $request->getAttribute('base');
-        } else {
-            $base = Configure::read('App.base');
-            if (isset(static::$_requestContext['_base'])) {
-                $base = static::$_requestContext['_base'];
-            }
+            $context['_base'] = $request->getAttribute('base');
+        } elseif (!isset($context['_base'])) {
+            $context['_base'] = Configure::read('App.base');
         }
 
         if (empty($url)) {
-            $output = $base . (isset($here) ? $here : '/');
+            $output = $context['_base'] . (isset($here) ? $here : '/');
             if ($full) {
                 $output = static::fullBaseUrl() . $output;
             }
@@ -680,8 +678,9 @@ class Router
             if ($full && isset($url['_scheme']) && !isset($url['_host'])) {
                 $url['_host'] = parse_url(static::fullBaseUrl(), PHP_URL_HOST);
             }
+            $context['params'] = $params;
 
-            $output = static::$_collection->match($url, static::$_requestContext + ['params' => $params]);
+            $output = static::$_collection->match($url, $context);
         } else {
             $plainString = (
                 strpos($url, 'javascript:') === 0 ||
@@ -697,7 +696,7 @@ class Router
             if ($plainString) {
                 return $url;
             }
-            $output = $base . $url;
+            $output = $context['_base'] . $url;
         }
         $protocol = preg_match('#^[a-z][a-z0-9+\-.]*\://#i', $output);
         if ($protocol === 0) {

+ 28 - 0
tests/TestCase/Routing/RouterTest.php

@@ -97,6 +97,34 @@ class RouterTest extends TestCase
     }
 
     /**
+     * Test that Router uses App.base to build URL's when there are no stored
+     * request objects.
+     *
+     * @return void
+     */
+    public function testBaseUrlWithBasePathArrayUrl()
+    {
+        Configure::write('App.base', '/cakephp');
+        Router::fullBaseUrl('http://example.com');
+        Router::scope('/', function ($routes) {
+            $routes->get('/:controller/:action', []);
+        });
+
+        $out = Router::url([
+            'controller' => 'tasks',
+            'action' => 'index'
+        ], true);
+        $this->assertEquals('http://example.com/cakephp/tasks', $out);
+
+        $out = Router::url([
+            'controller' => 'tasks',
+            'action' => 'index',
+            '_base' => false
+        ], true);
+        $this->assertEquals('http://example.com/tasks', $out);
+    }
+
+    /**
      * Test that Router uses the correct url including base path for requesting the current actions.
      *
      * @return void