Browse Source

Improve url filter error.

Give file and line where the method/closure is defined.
Mark Story 7 years ago
parent
commit
3a7db5a90e
2 changed files with 59 additions and 5 deletions
  1. 15 3
      src/Routing/Router.php
  2. 44 2
      tests/TestCase/Routing/RouterTest.php

+ 15 - 3
src/Routing/Router.php

@@ -20,6 +20,8 @@ use Cake\Routing\Exception\MissingRouteException;
 use Cake\Utility\Inflector;
 use Exception;
 use Psr\Http\Message\ServerRequestInterface;
+use ReflectionFunction;
+use ReflectionMethod;
 use RuntimeException;
 use Throwable;
 
@@ -589,7 +591,7 @@ class Router
     {
         $request = static::getRequest(true);
         $e = null;
-        foreach (static::$_urlFilters as $index => $filter) {
+        foreach (static::$_urlFilters as $filter) {
             try {
                 $url = $filter($url, $request);
             } catch (Exception $e) {
@@ -598,8 +600,18 @@ class Router
                 // fall through
             }
             if ($e !== null) {
-                $message = 'URL filter at index %s could not be applied. The filter failed with: %s';
-                throw new RuntimeException(sprintf($message, $index, $e->getMessage()), $e->getCode(), $e);
+                if (is_array($filter)) {
+                    $ref = new ReflectionMethod($filter[0], $filter[1]);
+                } else {
+                    $ref = new ReflectionFunction($filter);
+                }
+                $message = sprintf(
+                    'URL filter defined in %s on line %s could not be applied. The filter failed with: %s',
+                    $ref->getFileName(),
+                    $ref->getStartLine(),
+                    $e->getMessage()
+                );
+                throw new RuntimeException($message, $e->getCode(), $e);
             }
         }
 

+ 44 - 2
tests/TestCase/Routing/RouterTest.php

@@ -24,6 +24,8 @@ use Cake\Routing\Router;
 use Cake\Routing\Route\Route;
 use Cake\TestSuite\TestCase;
 use RuntimeException;
+use stdClass;
+
 
 /**
  * RouterTest class
@@ -1344,10 +1346,13 @@ class RouterTest extends TestCase
      *
      * @return void
      */
-    public function testUrlGenerationWithUrlFilterFailure()
+    public function testUrlGenerationWithUrlFilterFailureClosure()
     {
         $this->expectException(RuntimeException::class);
-        $this->expectExceptionMessage('URL filter at index 0 could not be applied. The filter failed with: nope');
+        $this->expectExceptionMessageRegExp(
+            '/URL filter defined in .*RouterTest\.php on line \d+ could not be applied\.' .
+            ' The filter failed with: nope/'
+        );
         Router::connect('/:lang/:controller/:action/*');
         $request = new ServerRequest([
             'params' => [
@@ -1366,6 +1371,43 @@ class RouterTest extends TestCase
     }
 
     /**
+     * Test that url filter failure gives better errors
+     *
+     * @return void
+     */
+    public function testUrlGenerationWithUrlFilterFailureMethod()
+    {
+        $this->expectException(RuntimeException::class);
+        $this->expectExceptionMessageRegExp(
+            '/URL filter defined in .*RouterTest\.php on line \d+ could not be applied\.' .
+            ' The filter failed with: /'
+        );
+        Router::connect('/:lang/:controller/:action/*');
+        $request = new ServerRequest([
+            'params' => [
+                'plugin' => null,
+                'lang' => 'en',
+                'controller' => 'posts',
+                'action' => 'index'
+            ]
+        ]);
+        Router::pushRequest($request);
+
+        Router::addUrlFilter([$this, 'badFilter']);
+        Router::url(['controller' => 'posts', 'action' => 'index', 'lang' => 'en']);
+    }
+
+    /**
+     * Testing stub for broken URL filters.
+     *
+     * @throws \RuntimeException
+     */
+    public function badFilter()
+    {
+        throw new RuntimeException('nope');
+    }
+
+    /**
      * Test url param persistence.
      *
      * @return void