Skip to content

Commit

Permalink
Improve reverse routing logic
Browse files Browse the repository at this point in the history
  • Loading branch information
daftspunk committed Dec 30, 2015
1 parent 26096e5 commit 7c41953
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 38 deletions.
12 changes: 8 additions & 4 deletions src/Router/Helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,9 @@ public static function getSegmentRegExp($segment)
{
if (($pos = mb_strpos($segment, '|')) !== false) {
$regexp = mb_substr($segment, $pos+1);
if (!mb_strlen($regexp))
if (!mb_strlen($regexp)) {
return false;
}

return '/'.$regexp.'/';
}
Expand All @@ -196,16 +197,19 @@ public static function getSegmentRegExp($segment)
public static function getSegmentDefaultValue($segment)
{
$optMarkerPos = mb_strpos($segment, '?');
if ($optMarkerPos === false)
if ($optMarkerPos === false) {
return false;
}

$regexMarkerPos = mb_strpos($segment, '|');
$value = false;

if ($regexMarkerPos !== false)
if ($regexMarkerPos !== false) {
$value = mb_substr($segment, $optMarkerPos+1, $regexMarkerPos-$optMarkerPos-1);
else
}
else {
$value = mb_substr($segment, $optMarkerPos+1);
}

return strlen($value) ? $value : false;
}
Expand Down
48 changes: 23 additions & 25 deletions src/Router/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,36 +129,41 @@ public function urlFromPattern($pattern, $parameters = [])
unset($parameters[$param]);
}

// Build a URL
/*
* Build the URL segments, remember the last populated index
*/
$url = [];
foreach ($patternSegments as $index => $patternSegment) {
$lastPopulatedIndex = 0;

foreach ($patternSegments as $index => $patternSegment) {
/*
* Static segment
*/
if (strpos($patternSegment, ':') !== 0) {
$url[] = $patternSegment;
continue;
}
/*
* Dynamic segment
*/
else {
/*
* Get the parameter name
*/
$paramName = Helper::getParameterName($patternSegment);

/*
* Determine whether it is optional
*/

$optional = Helper::segmentIsOptional($patternSegment);

/*
* Check if parameter has been supplied
* Default value
*/
$defaultValue = Helper::getSegmentDefaultValue($patternSegment);

/*
* Check if parameter has been supplied and is not a default value
*/
$parameterExists = array_key_exists($paramName, $parameters);
$parameterExists = array_key_exists($paramName, $parameters) &&
strlen($parameters[$paramName]) &&
$parameters[$paramName] !== $defaultValue;

/*
* Use supplied parameter value
Expand All @@ -167,40 +172,33 @@ public function urlFromPattern($pattern, $parameters = [])
$url[] = $parameters[$paramName];
}
/*
* Look for default value or set as false
* Look for a specified default value
*/
elseif ($optional) {
$url[] = Helper::getSegmentDefaultValue($patternSegment);
$url[] = $defaultValue ?: static::$defaultValue;

// Do not set $lastPopulatedIndex
continue;
}
/*
* Non optional field, use the default value
*/
else {
$url[] = static::$defaultValue;
}

}

$lastPopulatedIndex = $index;
}

/*
* Trim the URL array and set any empty inbetween values to default value
* Trim the URL to only include populated segments
*/
$lastPopulatedIndex = 0;
foreach ($url as $index => $segment) {
if ($segment) {
$lastPopulatedIndex = $index;
}
else {
$url[$index] = static::$defaultValue;
}
}

$url = array_slice($url, 0, $lastPopulatedIndex + 1);

return Helper::rebuildUrl($url);
}


/**
* Returns the active list of router rule objects
* @return array An associative array with keys matching the route rule names and
Expand Down Expand Up @@ -278,4 +276,4 @@ public function sortRules()
});
}

}
}
46 changes: 37 additions & 9 deletions tests/Router/RouterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class RouteTest extends TestCase
{
public function testResolveUrl()
{
$params = array();
$params = [];
$router = new Router();

$rule = $router->reset()->route('testRuleId', 'blog/post');
Expand Down Expand Up @@ -160,7 +160,7 @@ public function testResolveUrl()

public function testMatch()
{
$params = array();
$params = [];
$router = new Router();

// Set up some dummy rules
Expand All @@ -183,7 +183,7 @@ public function testMatch()

public function testUrl()
{
$params = array();
$params = [];
$router = new Router();

// Set up some dummy rules
Expand All @@ -192,32 +192,60 @@ public function testUrl()
$router->route('userProfile', 'profile/:username');
$router->route('jobRequest', 'job/:type?request/:id');
$router->route('productPage', '/product/:category?/:id');
$router->route('portfolioPage', '/portfolio/:year?noYear/:category?noCategory/:budget?noBudget');

$result = $router->url('blogPost');
$this->assertEquals('/blog/post', $result);

$result = $router->url('authorDetails');
$this->assertEquals('/authors', $result);

$result = $router->url('authorDetails', array('author_id' => 20));
$result = $router->url('authorDetails', ['author_id' => 20]);
$this->assertEquals('/authors/20', $result);

$result = $router->url('authorDetails', array('details' => 'history'));
$result = $router->url('authorDetails', ['details' => 'history']);
$this->assertEquals('/authors/default/history', $result);

$result = $router->url('userProfile', array('username' => 'shaq'));
$result = $router->url('authorDetails', ['author_id' => 'default']);
$this->assertEquals('/authors/default', $result);

$result = $router->url('userProfile', ['username' => 'shaq']);
$this->assertEquals('/profile/shaq', $result);

$result = $router->url('jobRequest', array('id' => '9'));
$result = $router->url('jobRequest', ['id' => '9']);
$this->assertEquals('/job/request/9', $result);

$result = $router->url('jobRequest');
$this->assertEquals('/job/request/default', $result);

$result = $router->url('productPage', array('id' => '7'));
$result = $router->url('productPage', ['id' => '7']);
$this->assertEquals('/product/default/7', $result);

$result = $router->url('productPage', array('id' => '7', 'category' => 'helmets'));
$result = $router->url('productPage', ['id' => '7', 'category' => 'helmets']);
$this->assertEquals('/product/helmets/7', $result);

$result = $router->url('portfolioPage');
$this->assertEquals('/portfolio', $result);

$result = $router->url('portfolioPage', ['year' => '2020']);
$this->assertEquals('/portfolio/2020', $result);

$result = $router->url('portfolioPage', ['category' => 'shoes']);
$this->assertEquals('/portfolio/noYear/shoes', $result);

$result = $router->url('portfolioPage', ['category' => null, 'budget' => '50000-above']);
$this->assertEquals('/portfolio/noYear/noCategory/50000-above', $result);

$result = $router->url('portfolioPage', ['year' => false, 'category' => null, 'budget' => 0]);
$this->assertEquals('/portfolio/noYear/noCategory/0', $result);

$result = $router->url('portfolioPage', ['budget' => 0]);
$this->assertEquals('/portfolio/noYear/noCategory/0', $result);

$result = $router->url('portfolioPage', ['year' => '2020', 'category' => 'noCategory']);
$this->assertEquals('/portfolio/2020', $result);

$result = $router->url('portfolioPage', ['year' => 'default', 'category' => 'noCategory', 'budget' => '200-500']);
$this->assertEquals('/portfolio/default/noCategory/200-500', $result);
}
}

0 comments on commit 7c41953

Please sign in to comment.