Skip to content
This repository was archived by the owner on Jan 31, 2020. It is now read-only.

Commit b8b4ff1

Browse files
committed
Initial Regex route refactoring
1 parent 28792cc commit b8b4ff1

File tree

2 files changed

+61
-48
lines changed

2 files changed

+61
-48
lines changed

src/Route/Regex.php

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,22 @@
99
namespace Zend\Router\Route;
1010

1111
use Psr\Http\Message\ServerRequestInterface as Request;
12+
use Psr\Http\Message\UriInterface;
1213
use Traversable;
14+
use Zend\Diactoros\Uri;
1315
use Zend\Router\Exception;
16+
use Zend\Router\PartialRouteInterface;
17+
use Zend\Router\PartialRouteResult;
18+
use Zend\Router\RouteInterface;
19+
use Zend\Router\RouteMatch;
1420
use Zend\Stdlib\ArrayUtils;
15-
use Zend\Router\RouteMatch as BaseRouteMatch;
1621

1722
/**
1823
* Regex route.
1924
*/
20-
class Regex implements RouteInterface
25+
class Regex implements PartialRouteInterface
2126
{
27+
use PartialRouteTrait;
2228
/**
2329
* Regex to match.
2430
*
@@ -56,7 +62,7 @@ class Regex implements RouteInterface
5662
* @param string $spec
5763
* @param array $defaults
5864
*/
59-
public function __construct($regex, $spec, array $defaults = [])
65+
public function __construct(string $regex, $spec, array $defaults = [])
6066
{
6167
$this->regex = $regex;
6268
$this->spec = $spec;
@@ -71,7 +77,7 @@ public function __construct($regex, $spec, array $defaults = [])
7177
* @return Regex
7278
* @throws \Zend\Router\Exception\InvalidArgumentException
7379
*/
74-
public static function factory($options = [])
80+
public static function factory($options = []) : RouteInterface
7581
{
7682
if ($options instanceof Traversable) {
7783
$options = ArrayUtils::iteratorToArray($options);
@@ -97,26 +103,15 @@ public static function factory($options = [])
97103
return new static($options['regex'], $options['spec'], $options['defaults']);
98104
}
99105

100-
/**
101-
* match(): defined by RouteInterface interface.
102-
*
103-
* @param Request $request
104-
* @param int $pathOffset
105-
* @return RouteMatch|null
106-
*/
107-
public function match(Request $request, $pathOffset = null) : ?BaseRouteMatch
106+
public function partialMatch(Request $request, int $pathOffset = 0, array $options = []): PartialRouteResult
108107
{
109108
$uri = $request->getUri();
110109
$path = $uri->getPath();
111110

112-
if ($pathOffset !== null) {
113-
$result = preg_match('(\G' . $this->regex . ')', $path, $matches, 0, $pathOffset);
114-
} else {
115-
$result = preg_match('(^' . $this->regex . '$)', $path, $matches);
116-
}
111+
$result = preg_match('(\G' . $this->regex . ')', $path, $matches, 0, $pathOffset);
117112

118113
if (! $result) {
119-
return null;
114+
return PartialRouteResult::fromRouteFailure();
120115
}
121116

122117
$matchedLength = strlen($matches[0]);
@@ -129,7 +124,11 @@ public function match(Request $request, $pathOffset = null) : ?BaseRouteMatch
129124
}
130125
}
131126

132-
return new RouteMatch(array_merge($this->defaults, $matches), $matchedLength);
127+
return PartialRouteResult::fromRouteMatch(
128+
new RouteMatch(null, array_merge($this->defaults, $matches)),
129+
$pathOffset,
130+
$matchedLength
131+
);
133132
}
134133

135134
/**
@@ -140,7 +139,7 @@ public function match(Request $request, $pathOffset = null) : ?BaseRouteMatch
140139
* @param array $options
141140
* @return mixed
142141
*/
143-
public function assemble(array $params = [], array $options = [])
142+
public function assemble(array $params = [], array $options = []) : UriInterface
144143
{
145144
$url = $this->spec;
146145
$mergedParams = array_merge($this->defaults, $params);
@@ -156,7 +155,18 @@ public function assemble(array $params = [], array $options = [])
156155
}
157156
}
158157

159-
return $url;
158+
if (! isset($options['uri'])) {
159+
return new Uri($url);
160+
}
161+
$uri = $options['uri'];
162+
if (! $uri instanceof UriInterface) {
163+
throw new Exception\DomainException(\sprintf(
164+
'Route assemble option \'uri\' must be instance of %s, got %s',
165+
UriInterface::class,
166+
(is_object($uri) ? get_class($uri) : gettype($uri))
167+
));
168+
}
169+
return $uri->withPath($uri->getPath() . $url);
160170
}
161171

162172
/**
@@ -165,7 +175,7 @@ public function assemble(array $params = [], array $options = [])
165175
* @see RouteInterface::getAssembledParams
166176
* @return array
167177
*/
168-
public function getAssembledParams()
178+
public function getLastAssembledParams() : array
169179
{
170180
return $this->assembledParams;
171181
}

test/Route/RegexTest.php

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,19 @@ public static function routeProvider()
2222
'simple-match' => [
2323
new Regex('/(?<foo>[^/]+)', '/%foo%'),
2424
'/bar',
25-
null,
25+
0,
2626
['foo' => 'bar']
2727
],
2828
'no-match-without-leading-slash' => [
2929
new Regex('(?<foo>[^/]+)', '%foo%'),
3030
'/bar',
31-
null,
31+
0,
3232
null
3333
],
3434
'no-match-with-trailing-slash' => [
3535
new Regex('/(?<foo>[^/]+)', '/%foo%'),
3636
'/bar/',
37-
null,
37+
0,
3838
null
3939
],
4040
'offset-skips-beginning' => [
@@ -43,22 +43,16 @@ public static function routeProvider()
4343
1,
4444
['foo' => 'bar']
4545
],
46-
'offset-enables-partial-matching' => [
47-
new Regex('/(?<foo>[^/]+)', '/%foo%'),
48-
'/bar/baz',
49-
0,
50-
['foo' => 'bar']
51-
],
5246
'url-encoded-parameters-are-decoded' => [
5347
new Regex('/(?<foo>[^/]+)', '/%foo%'),
5448
'/foo%20bar',
55-
null,
49+
0,
5650
['foo' => 'foo bar']
5751
],
5852
'empty-matches-are-replaced-with-defaults' => [
5953
new Regex('/foo(?:/(?<bar>[^/]+))?/baz-(?<baz>[^/]+)', '/foo/baz-%baz%', ['bar' => 'bar']),
6054
'/foo/baz-baz',
61-
null,
55+
0,
6256
['bar' => 'bar', 'baz' => 'baz']
6357
],
6458
];
@@ -74,23 +68,30 @@ public static function routeProvider()
7468
public function testMatching(Regex $route, $path, $offset, array $params = null)
7569
{
7670
$request = new ServerRequest([], [], new Uri('http://example.com' . $path));
77-
$match = $route->match($request, $offset);
71+
$result = $route->match($request, $offset);
7872

7973
if ($params === null) {
80-
$this->assertNull($match);
74+
$this->assertFalse($result->isSuccess());
8175
} else {
82-
$this->assertInstanceOf(RouteMatch::class, $match);
83-
84-
if ($offset === null) {
85-
$this->assertEquals(strlen($path), $match->getLength());
86-
}
76+
$this->assertTrue($result->isSuccess());
77+
$match = $result->getRouteMatch();
8778

8879
foreach ($params as $key => $value) {
8980
$this->assertEquals($value, $match->getParam($key));
9081
}
9182
}
9283
}
9384

85+
public function testPartialMatching()
86+
{
87+
$route = new Regex('/(?<foo>[^/]+)', '/%foo%');
88+
$request = new ServerRequest([], [], new Uri('http://example.com/bar/baz'));
89+
$result = $route->partialMatch($request, 0);
90+
91+
$this->assertTrue($result->isSuccess());
92+
$this->assertEquals('bar', $result->getRouteMatch()->getParam('foo'));
93+
}
94+
9495
/**
9596
* @dataProvider routeProvider
9697
* @param Regex $route
@@ -104,12 +105,12 @@ public function testAssembling(Regex $route, $path, $offset, array $params = nul
104105
self::markTestSkipped('Data which will not match are not tested for assembling.');
105106
}
106107

107-
$result = $route->assemble($params);
108+
$uri = $route->assemble($params);
108109

109110
if ($offset !== null) {
110-
$this->assertEquals($offset, strpos($path, $result, $offset));
111+
$this->assertEquals($offset, strpos($path, $uri->getPath(), $offset));
111112
} else {
112-
$this->assertEquals($path, $result);
113+
$this->assertEquals($path, $uri->getPath());
113114
}
114115
}
115116

@@ -118,7 +119,7 @@ public function testGetAssembledParams()
118119
$route = new Regex('/(?<foo>.+)', '/%foo%');
119120
$route->assemble(['foo' => 'bar', 'baz' => 'bat']);
120121

121-
$this->assertEquals(['foo'], $route->getAssembledParams());
122+
$this->assertEquals(['foo'], $route->getLastAssembledParams());
122123
}
123124

124125
public function testFactory()
@@ -144,9 +145,10 @@ public function testRawDecode()
144145
$raw = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`-=[]\\;\',.~!@$^&*()_+{}|:"<>';
145146
$request = new ServerRequest([], [], new Uri('http://example.com/' . $raw));
146147
$route = new Regex('/(?<foo>[^/]+)', '/%foo%');
147-
$match = $route->match($request);
148+
$result = $route->match($request);
148149

149-
$this->assertSame($raw, $match->getParam('foo'));
150+
$this->assertTrue($result->isSuccess());
151+
$this->assertSame($raw, $result->getRouteMatch()->getParam('foo'));
150152
}
151153

152154
public function testEncodedDecode()
@@ -159,8 +161,9 @@ public function testEncodedDecode()
159161

160162
$request = new ServerRequest([], [], new Uri('http://example.com/' . $in));
161163
$route = new Regex('/(?<foo>[^/]+)', '/%foo%');
162-
$match = $route->match($request);
164+
$result = $route->match($request);
163165

164-
$this->assertSame($out, $match->getParam('foo'));
166+
$this->assertTrue($result->isSuccess());
167+
$this->assertSame($out, $result->getRouteMatch()->getParam('foo'));
165168
}
166169
}

0 commit comments

Comments
 (0)