Skip to content

Commit

Permalink
Fix optional parameters in url generator (#2246)
Browse files Browse the repository at this point in the history
* Fix route collection getting wrong path when optional parameters present, add unit tests
  • Loading branch information
askvortsov1 authored Jul 29, 2020
1 parent db83003 commit 8a73cc5
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 4 deletions.
24 changes: 20 additions & 4 deletions src/Http/RouteCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use FastRoute\DataGenerator;
use FastRoute\RouteParser;
use Illuminate\Support\Arr;

class RouteCollection
{
Expand Down Expand Up @@ -88,10 +89,25 @@ protected function fixPathPart(&$part, $key, array $parameters)
public function getPath($name, array $parameters = [])
{
if (isset($this->reverse[$name])) {
$parts = $this->reverse[$name][0];
array_walk($parts, [$this, 'fixPathPart'], $parameters);

return '/'.ltrim(implode('', $parts), '/');
$maxMatches = 0;
$matchingParts = $this->reverse[$name][0];

// For a given route name, we want to choose the option that best matches the given parameters.
// Each routing option is an array of parts. Each part is either a constant string
// (which we don't care about here), or an array where the first element is the parameter name
// and the second element is a regex into which the parameter value is inserted, if the parameter matches.
foreach ($this->reverse[$name] as $parts) {
foreach ($parts as $i => $part) {
if (is_array($part) && Arr::exists($parameters, $part[0]) && $i > $maxMatches) {
$maxMatches = $i;
$matchingParts = $parts;
}
}
}

array_walk($matchingParts, [$this, 'fixPathPart'], $parameters);

return '/'.ltrim(implode('', $matchingParts), '/');
}

throw new \RuntimeException("Route $name not found");
Expand Down
76 changes: 76 additions & 0 deletions tests/unit/Foundation/RouteCollectionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/

namespace Flarum\Tests\unit\Foundation;

use Flarum\Http\RouteCollection;
use Flarum\Tests\unit\TestCase;
use RuntimeException;

class RouteCollectionTest extends TestCase
{
/** @test */
public function it_errors_when_nonexistent_route_requested()
{
$collection = new RouteCollection();

$this->expectException(RuntimeException::class);

$collection->getPath('nonexistent');
}

/** @test */
public function it_properly_processes_a_simple_route_with_no_parameters()
{
$collection = new RouteCollection();
// We can use anything for the handler since we're only testing getPath
$collection->addRoute('GET', '/custom/route', 'custom', '');

$this->assertEquals('/custom/route', $collection->getPath('custom'));
}

/** @test */
public function it_properly_processes_a_route_with_all_parameters_required()
{
$collection = new RouteCollection();
// We can use anything for the handler since we're only testing getPath
$collection->addRoute('GET', '/custom/{route}/{has}/{parameters}', 'custom', '');

$this->assertEquals('/custom/something/something_else/anything_else', $collection->getPath('custom', [
'route' => 'something',
'has' => 'something_else',
'parameters' => 'anything_else'
]));
}

/** @test */
public function it_works_if_optional_parameters_are_missing()
{
$collection = new RouteCollection();
// We can use anything for the handler since we're only testing getPath
$collection->addRoute('GET', '/custom/{route}[/{has}]', 'custom', '');

$this->assertEquals('/custom/something', $collection->getPath('custom', [
'route' => 'something'
]));
}

/** @test */
public function it_works_with_optional_parameters()
{
$collection = new RouteCollection();
// We can use anything for the handler since we're only testing getPath
$collection->addRoute('GET', '/custom/{route}[/{has}]', 'custom', '');

$this->assertEquals('/custom/something/something_else', $collection->getPath('custom', [
'route' => 'something',
'has' => 'something_else'
]));
}
}

0 comments on commit 8a73cc5

Please sign in to comment.