Skip to content

Commit 6b0a5c6

Browse files
committed
Updating ObjectRouteLoader to use a service_id:methodName format
1 parent 7ed22ce commit 6b0a5c6

File tree

4 files changed

+106
-74
lines changed

4 files changed

+106
-74
lines changed

src/Symfony/Component/Routing/Loader/DependencyInjection/ServiceRouterLoader.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public function __construct(ContainerInterface $container)
3434
$this->container = $container;
3535
}
3636

37-
protected function getRouteLoaderService($id)
37+
protected function getServiceObject($id)
3838
{
3939
return $this->container->get($id);
4040
}

src/Symfony/Component/Routing/Loader/ObjectRouteLoader.php

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,56 @@
2222
*/
2323
abstract class ObjectRouteLoader extends Loader
2424
{
25+
/**
26+
* Returns the object that the method will be called on to load routes.
27+
*
28+
* For example, if your application uses a service container,
29+
* the $id may be a service id.
30+
*
31+
* @param string $id
32+
*
33+
* @return object
34+
*/
35+
abstract protected function getServiceObject($id);
36+
2537
/**
2638
* Calls the service that will load the routes.
2739
*
28-
* @param string $resource The name of the service to load
40+
* @param mixed $resource Some value that will resolve to a callable
2941
* @param string|null $type The resource type
3042
*
3143
* @return RouteCollection
3244
*/
3345
public function load($resource, $type = null)
3446
{
35-
$routeLoader = $this->getRouteLoaderService($resource);
47+
$parts = explode(':', $resource);
48+
if (count($parts) != 2) {
49+
throw new \InvalidArgumentException(sprintf('Invalid resource "%s" passed to the "service" route loader: use the format "service_name:methodName"', $resource));
50+
}
51+
52+
$serviceString = $parts[0];
53+
$method = $parts[1];
54+
55+
$loaderObject = $this->getServiceObject($serviceString);
56+
57+
if (!is_object($loaderObject)) {
58+
throw new \LogicException(sprintf('%s:getServiceObject() must return an object: %s returned', get_class($this), $loaderObject));
59+
}
3660

37-
if (!$routeLoader instanceof RouteLoaderInterface) {
38-
throw new \LogicException(sprintf('Service "%s" must implement RouteLoaderInterface.', $resource));
61+
if (!method_exists($loaderObject, $method)) {
62+
throw new \BadMethodCallException(sprintf('Method "%s" not found on "%s" when importing routing resource "%s"', $method, get_class($loaderObject), $resource));
3963
}
4064

41-
$routeCollection = $routeLoader->getRouteCollection($this);
65+
$routeCollection = call_user_func(array($loaderObject, $method), $this);
66+
67+
if (!$routeCollection instanceof RouteCollection) {
68+
$type = is_object($routeCollection) ? get_class($routeCollection) : gettype($routeCollection);
69+
70+
throw new \LogicException(sprintf('The %s::%s method must return a RouteCollection: %s returned', get_class($loaderObject), $method, $type));
71+
}
4272

4373
// make the service file tracked so that if it changes, the cache rebuilds
44-
$this->addClassResource(new \ReflectionClass($routeLoader), $routeCollection);
74+
$this->addClassResource(new \ReflectionClass($loaderObject), $routeCollection);
4575

4676
return $routeCollection;
4777
}
@@ -56,18 +86,6 @@ public function supports($resource, $type = null)
5686
return 'service' === $type;
5787
}
5888

59-
/**
60-
* Returns a RouteLoaderInterface object matching the id.
61-
*
62-
* For example, if your application uses a service container,
63-
* the $id may be a service id.
64-
*
65-
* @param string $id
66-
*
67-
* @return RouteLoaderInterface
68-
*/
69-
abstract protected function getRouteLoaderService($id);
70-
7189
private function addClassResource(\ReflectionClass $class, RouteCollection $collection)
7290
{
7391
do {

src/Symfony/Component/Routing/Loader/RouteLoaderInterface.php

Lines changed: 0 additions & 30 deletions
This file was deleted.

src/Symfony/Component/Routing/Tests/Loader/ObjectRouteLoaderTest.php

Lines changed: 69 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,53 +19,97 @@ class ObjectRouteLoaderTest extends \PHPUnit_Framework_TestCase
1919
{
2020
public function testLoadCallsServiceAndReturnsCollection()
2121
{
22-
$routeLoader = $this->getMock('Symfony\Component\Routing\Loader\RouteLoaderInterface');
23-
$serviceRouteLoader = new ObjectRouteLoaderForTest();
24-
25-
$serviceRouteLoader->loaderMap = array(
26-
'my_route_provider_service' => $routeLoader,
27-
);
22+
$loader = new ObjectRouteLoaderForTest();
2823

2924
// create a basic collection that will be returned
30-
$routes = new RouteCollection();
31-
$routes->add('foo', new Route('/foo'));
25+
$collection = new RouteCollection();
26+
$collection->add('foo', new Route('/foo'));
3227

33-
$routeLoader
34-
->expects($this->any())
35-
->method('getRouteCollection')
36-
// the loader itself is passed
37-
->with($serviceRouteLoader)
38-
->will($this->returnValue($routes));
28+
// create some callable object
29+
$service = $this->getMockBuilder('stdClass')
30+
->setMethods(array('loadRoutes'))
31+
->getMock();
32+
$service->expects($this->once())
33+
->method('loadRoutes')
34+
->with($loader)
35+
->will($this->returnValue($collection));
3936

40-
$actualRoutes = $serviceRouteLoader->load('my_route_provider_service', 'service');
37+
$loader->loaderMap = array(
38+
'my_route_provider_service' => $service,
39+
);
4140

42-
$this->assertSame($routes, $actualRoutes);
41+
$actualRoutes = $loader->load(
42+
'my_route_provider_service:loadRoutes',
43+
'service'
44+
);
45+
46+
$this->assertSame($collection, $actualRoutes);
4347
// the service file should be listed as a resource
4448
$this->assertNotEmpty($actualRoutes->getResources());
4549
}
4650

4751
/**
48-
* @expectedException \LogicException
52+
* @expectedException \InvalidArgumentException
53+
* @dataProvider getBadResourceStrings
4954
*/
50-
public function testExceptionOnInterfaceNotImplemented()
55+
public function testExceptionWithoutSyntax($resourceString)
5156
{
52-
// anything that doesn't implement the interface
53-
$routeLoader = new \stdClass();
57+
$loader = new ObjectRouteLoaderForTest();
58+
$loader->load($resourceString);
59+
}
5460

55-
$serviceRouteLoader = new ObjectRouteLoaderForTest();
56-
$serviceRouteLoader->loaderMap = array(
57-
'any_service_name' => $routeLoader,
61+
public function getBadResourceStrings()
62+
{
63+
return array(
64+
array('Foo'),
65+
array('Bar::baz'),
66+
array('Foo:Bar:baz'),
5867
);
68+
}
69+
70+
/**
71+
* @expectedException \LogicException
72+
*/
73+
public function testExceptionOnNoObjectReturned()
74+
{
75+
$loader = new ObjectRouteLoaderForTest();
76+
$loader->loaderMap = array('my_service' => 'NOT_AN_OBJECT');
77+
$loader->load('my_service:method');
78+
}
79+
80+
/**
81+
* @expectedException \BadMethodCallException
82+
*/
83+
public function testExceptionOnBadMethod()
84+
{
85+
$loader = new ObjectRouteLoaderForTest();
86+
$loader->loaderMap = array('my_service' => new \stdClass());
87+
$loader->load('my_service:method');
88+
}
89+
90+
/**
91+
* @expectedException \LogicException
92+
*/
93+
public function testExceptionOnMethodNotReturningCollection()
94+
{
95+
$service = $this->getMockBuilder('stdClass')
96+
->setMethods(array('loadRoutes'))
97+
->getMock();
98+
$service->expects($this->once())
99+
->method('loadRoutes')
100+
->will($this->returnValue('NOT_A_COLLECTION'));
59101

60-
$serviceRouteLoader->load('any_service_name', 'service');
102+
$loader = new ObjectRouteLoaderForTest();
103+
$loader->loaderMap = array('my_service' => $service);
104+
$loader->load('my_service:loadRoutes');
61105
}
62106
}
63107

64108
class ObjectRouteLoaderForTest extends ObjectRouteLoader
65109
{
66110
public $loaderMap = array();
67111

68-
protected function getRouteLoaderService($id)
112+
protected function getServiceObject($id)
69113
{
70114
return isset($this->loaderMap[$id]) ? $this->loaderMap[$id] : null;
71115
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy