Skip to content

Commit 2b0e803

Browse files
author
Alex Rohleder
committed
Merge pull request #24 from codeburnerframework/dev
merge support to named routes
2 parents 022ed45 + e97db1f commit 2b0e803

File tree

10 files changed

+241
-7
lines changed

10 files changed

+241
-7
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ language: php
33
php:
44
- 5.5
55
- 5.6
6-
- hhvm
6+
- 7.0
77

88
before_script:
99
- composer self-update

README.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
# Codeburner Router
22

3-
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE)
3+
[![Latest Stable Version](https://poser.pugx.org/codeburner/router/v/stable)](https://packagist.org/packages/codeburner/router)
44
[![Build Status](https://travis-ci.org/codeburnerframework/router.svg?branch=master)](https://travis-ci.org/codeburnerframework/router)
55
[![Code Coverage](https://scrutinizer-ci.com/g/codeburnerframework/routing/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/codeburnerframework/routing/?branch=master)
66
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/codeburnerframework/routing/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/codeburnerframework/routing/?branch=master)
7+
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE)
78

89
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/d96c4a67-982b-4e16-a24d-7b490bf11bc7/big.png)](https://insight.sensiolabs.com/projects/d96c4a67-982b-4e16-a24d-7b490bf11bc7)
910

@@ -46,6 +47,7 @@ $ composer require codeburner/router --save
4647
- [PSR7](#psr7)
4748
- [Default Arguments](#default-arguments)
4849
- [Container Integration](#container-integration)
50+
- [Names](#names)
4951
- [Metadata](#metadata)
5052
- [Collector](#collector)
5153
- [Groups](#groups)
@@ -57,6 +59,7 @@ $ composer require codeburner/router --save
5759
- [Nesting Limit](#nesting-limit)
5860
- [Shallow Resources](#shallow-resources)
5961
- [Adding More Actions](#adding-more-actions)
62+
- [Resources Route Names](#resources-route-names)
6063
- [Translated Patterns](#translated-patterns)
6164
- [Controllers](#controllers)
6265
- [Annotated Definition](#annotated-definition)
@@ -247,6 +250,25 @@ $route->call(function ($class) use ($container) {
247250
```
248251

249252

253+
### Names
254+
255+
All the routes allow you to apply names to then, this names can be used to find a route in the `Collector` or to generate links with `Path`'s method `to(string name, array args = [])`. E.g.
256+
257+
```php
258+
// ...
259+
// The Path class will create several links for us, just give they new object a instance of the collector.
260+
$path = new Codeburner\Router\Path($collector);
261+
// ...
262+
// Setting the name of route to blog.article
263+
$collector->get("/blog/{article:slug+}", "blog::show")->setName("blog.article");
264+
// ...
265+
// this will print an anchor tag with "/blog/my-first-article" in href.
266+
echo "<a href='", $path->to("blog.article", ["article" => "my-first-article"]), "'>My First Article</a>";
267+
```
268+
269+
> **NOTE:** For best practice use the dot for delimiting namespaces in your route names, so you can group and find they names easily. The [resource](#resources-route-names) collector adopt this concept.
270+
271+
250272
### Metadata
251273

252274
Sometimes you want to delegate more information to a route, for post match filters or action execution strategies. For persist data that will not be passed to action but used in somewhere before the execution use the `setMetadata(string key, mixed value)` method.
@@ -400,6 +422,25 @@ $collector->resource("PhotosResource")->member(
400422
);
401423
```
402424

425+
426+
#### Resources Route Names
427+
428+
All the routes in resource receive a [name](#names) that will be composed by the resource name or prefix, a dot and the action name. e.g.
429+
430+
```php
431+
class PhotosResource {
432+
public function index() {
433+
434+
}
435+
}
436+
437+
$collector->resource("PhotosResource")->only("index");
438+
$collector->resource("PhotosResource", ["as" => "picture"])->only("index");
439+
440+
echo $path->to("photos.index"), "<br>", $path->to("picture.index");
441+
```
442+
443+
403444
#### Translated Patterns
404445

405446
If you prefer to translate the patterns generated by the resource, just define an `translate` option that receives an array with one or the two keys, `new` and `edit`.

src/Collector.php

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class Collector
5454
* dimension is indexed by an http method and hold an array indexed with the patterns
5555
* and holding the route. ex. [METHOD => [PATTERN => ROUTE]]
5656
*
57-
* @var array
57+
* @var Route[][]
5858
*/
5959

6060
protected $statics = [];
@@ -63,11 +63,17 @@ class Collector
6363
* The dynamic routes have parameters and are stored in a hashtable that every cell have
6464
* an array with route patterns as indexes and routes as values. ex. [INDEX => [PATTERN => ROUTE]]
6565
*
66-
* @var array
66+
* @var Route[][]
6767
*/
6868

6969
protected $dynamics = [];
7070

71+
/**
72+
* @var Route[]
73+
*/
74+
75+
protected $named = [];
76+
7177
/**
7278
* The pattern parser instance.
7379
*
@@ -200,6 +206,18 @@ public function forget($method, $pattern)
200206
} else unset($this->dynamics[$this->getDynamicIndex($method, $pattern)][$pattern]);
201207
}
202208

209+
/**
210+
* @param string $name
211+
* @return Route|false
212+
*/
213+
214+
public function findNamedRoute($name)
215+
{
216+
if (!isset($this->named[$name])) {
217+
return false;
218+
} else return $this->named[$name];
219+
}
220+
203221
/**
204222
* @param string $method
205223
* @param string $pattern
@@ -260,6 +278,19 @@ protected function getValidMethod($method)
260278
return $method;
261279
}
262280

281+
/**
282+
* @param string $name
283+
* @param Route $route
284+
*
285+
* @return self
286+
*/
287+
288+
public function setRouteName($name, Route $route)
289+
{
290+
$this->named[$name] = $route;
291+
return $this;
292+
}
293+
263294
/**
264295
* @return string[]
265296
*/

src/Collectors/ResourceCollectorTrait.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@
2727
trait ResourceCollectorTrait
2828
{
2929

30+
/**
31+
* @param string $method
32+
* @param string $pattern
33+
* @param string $action
34+
*
35+
* @return \Codeburner\Router\Group
36+
*/
37+
3038
abstract public function set($method, $pattern, $action);
3139

3240
/**
@@ -65,7 +73,14 @@ public function resource($controller, array $options = array())
6573
$resource = new RouteResource;
6674

6775
foreach ($actions as $action => $map) {
68-
$resource->set($this->set($map[0], $this->getResourcePath($action, $map[1], $name, $options), [$controller, $action]));
76+
$resource->set(
77+
$this->set(
78+
$map[0],
79+
$this->getResourcePath($action, $map[1], $name, $options),
80+
[$controller, $action]
81+
)
82+
->setName("$name.$action")
83+
);
6984
}
7085

7186
return $resource;

src/Group.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,4 +244,21 @@ public function setConstraint($name, $regex)
244244
return $this;
245245
}
246246

247+
/**
248+
* Set a name to a Route.
249+
*
250+
* @param string $name
251+
* @return self
252+
*/
253+
254+
public function setName($name)
255+
{
256+
if (count($this->routes) > 1) {
257+
throw new \LogicException("You cannot set the same name to several routes.");
258+
}
259+
260+
$this->routes[0]->setName($name);
261+
return $this;
262+
}
263+
247264
}

src/Parser.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
use Codeburner\Router\Exceptions\BadRouteException;
1414

1515
/**
16-
* Representation of a group of several routes with same
17-
* controller and respecting the resourceful actions.
16+
* All the parsing route paths logic are maintained by this class.
1817
*
1918
* @author Alex Rohleder <contato@alexrohleder.com.br>
2019
*/

src/Path.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
/**
4+
* Codeburner Framework.
5+
*
6+
* @author Alex Rohleder <contato@alexrohleder.com.br>
7+
* @copyright 2016 Alex Rohleder
8+
* @license http://opensource.org/licenses/MIT
9+
*/
10+
11+
namespace Codeburner\Router;
12+
13+
/**
14+
* Create paths based on registered routes.
15+
*
16+
* @author Alex Rohleder <contato@alexrohleder.com.br>
17+
*/
18+
19+
class Path
20+
{
21+
22+
/**
23+
* @var Collector
24+
*/
25+
26+
protected $collector;
27+
28+
/**
29+
* Link constructor.
30+
*
31+
* @param Collector $collector
32+
*/
33+
34+
public function __construct(Collector $collector)
35+
{
36+
$this->collector = $collector;
37+
}
38+
39+
/**
40+
* Generate a path to a route named by $name.
41+
*
42+
* @param string $name
43+
* @param array $args
44+
*
45+
* @throws \BadMethodCallException
46+
* @return string
47+
*/
48+
49+
public function to($name, array $args = [])
50+
{
51+
$route = $this->collector->findNamedRoute($name);
52+
$parser = $this->collector->getParser();
53+
$pattern = $route->getPattern();
54+
55+
preg_match_all("~" . $parser::DYNAMIC_REGEX . "~x", $pattern, $matches, PREG_SET_ORDER);
56+
57+
foreach ((array) $matches as $key => $match) {
58+
if (!isset($args[$match[1]])) {
59+
throw new \BadMethodCallException("Missing argument '{$match[1]}' on creation of link for '{$name}' route.");
60+
}
61+
62+
$pattern = str_replace($match[0], $args[$match[1]], $pattern);
63+
}
64+
65+
return $pattern;
66+
}
67+
68+
}

src/Route.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,14 @@ class Route
9999

100100
protected $matcher;
101101

102+
/**
103+
* Route name, or alias.
104+
*
105+
* @var string $name
106+
*/
107+
108+
protected $name;
109+
102110
/**
103111
* The function used to create controllers from name.
104112
*
@@ -415,6 +423,15 @@ public function getMatcher()
415423
return $this->matcher;
416424
}
417425

426+
/**
427+
* @return string
428+
*/
429+
430+
public function getName()
431+
{
432+
return $this->name;
433+
}
434+
418435
/**
419436
* Verify if a Route have already been blocked.
420437
*
@@ -591,6 +608,13 @@ public function setMatcher(Matcher $matcher)
591608
return $this;
592609
}
593610

611+
public function setName($name)
612+
{
613+
$this->name = $name;
614+
$this->collector->setRouteName($name, $this);
615+
return $this;
616+
}
617+
594618
/**
595619
* Set a constraint to a token in the route pattern.
596620
*

tests/BaseCollectorTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use Codeburner\Router\Collector;
44
use Codeburner\Router\Matcher;
5+
use Codeburner\Router\Path;
56

67
class BaseCollectorTest extends PHPUnit_Framework_TestCase
78
{
@@ -365,4 +366,28 @@ public function test_EnsureAssignments()
365366
$this->assertEquals($this->matcher, $route->getMatcher());
366367
}
367368

369+
public function test_NamedStaticRoutes()
370+
{
371+
$this->collector->get("/", "")->setName("test");
372+
$link = new Path($this->collector);
373+
$this->assertTrue("/" === $link->to("test"));
374+
}
375+
376+
public function test_NamedDynamicRoutes()
377+
{
378+
$this->collector->get("/myresource/{myresource_id:int+}/resource/{id:int+}", "")->setName("test");
379+
$link = new Path($this->collector);
380+
$this->assertTrue("/myresource/2/resource/3" === $link->to("test", ["myresource_id" => 2, "id" => 3]));
381+
}
382+
383+
public function test_GroupNamedRouteException()
384+
{
385+
$this->setExpectedException("LogicException");
386+
387+
$this->collector->group([
388+
$this->collector->get("/", ""),
389+
$this->collector->get("/1", "")
390+
])->setName("test");
391+
}
392+
368393
}

tests/ResourceCollectorTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use Codeburner\Router\Collector;
44
use Codeburner\Router\Matcher;
5+
use Codeburner\Router\Path;
56

67
class ResourceCollectorTest extends PHPUnit_Framework_TestCase
78
{
@@ -129,6 +130,19 @@ public function test_Shallow()
129130
$this->assertInstanceOf('Codeburner\Router\Route', $this->matcher->match('post', '/fst/1/snd/2/edit'));
130131
}
131132

133+
public function test_RouteNames()
134+
{
135+
$this->collector->resource('Resource');
136+
$this->collector->resource('Resource', ['as' => 'fst']);
137+
$link = new Path($this->collector);
138+
139+
foreach (['resource', 'fst'] as $prefix) {
140+
foreach ($this->actions as $action => $map) {
141+
$this->assertEquals(str_replace("{name}", $prefix, $map[1]), $link->to("$prefix.$action", ["id" => "123"]));
142+
}
143+
}
144+
}
145+
132146
private function doTestActions($actions)
133147
{
134148
foreach ($this->actions as $action => $inf) {

0 commit comments

Comments
 (0)