diff --git a/src/Router/Helper.php b/src/Router/Helper.php index cf6f60804..413824d42 100644 --- a/src/Router/Helper.php +++ b/src/Router/Helper.php @@ -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.'/'; } @@ -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; } diff --git a/src/Router/Router.php b/src/Router/Router.php index a7d3caf23..e9ef67d5d 100644 --- a/src/Router/Router.php +++ b/src/Router/Router.php @@ -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 @@ -167,10 +172,13 @@ 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 @@ -178,29 +186,19 @@ public function urlFromPattern($pattern, $parameters = []) 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 @@ -278,4 +276,4 @@ public function sortRules() }); } -} \ No newline at end of file +} diff --git a/tests/Router/RouterTest.php b/tests/Router/RouterTest.php index 1244bfddd..962149ac3 100644 --- a/tests/Router/RouterTest.php +++ b/tests/Router/RouterTest.php @@ -6,7 +6,7 @@ class RouteTest extends TestCase { public function testResolveUrl() { - $params = array(); + $params = []; $router = new Router(); $rule = $router->reset()->route('testRuleId', 'blog/post'); @@ -160,7 +160,7 @@ public function testResolveUrl() public function testMatch() { - $params = array(); + $params = []; $router = new Router(); // Set up some dummy rules @@ -183,7 +183,7 @@ public function testMatch() public function testUrl() { - $params = array(); + $params = []; $router = new Router(); // Set up some dummy rules @@ -192,6 +192,7 @@ 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); @@ -199,25 +200,52 @@ public function testUrl() $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); } } \ No newline at end of file