Commit 0a81d4bb authored by Fabien Potencier's avatar Fabien Potencier

merged branch davedevelopment/service-controller-resolver (PR #575)

This PR was squashed before being merged into the master branch (closes #575).

Commits
-------

9ce84e86 Service based controller resolver

Discussion
----------

Service based controller resolver

As discussed in #512

I've extended `RouterTest` to ensure existing behaviour is not affected when using the `ServiceControllerResolver`, I can remove it if it is considered overkill.

---------------------------------------------------------------------------

by GromNaN at 2013-01-07T15:14:00Z

You could add a service provider, so that we only have to register it to get the feature.

---------------------------------------------------------------------------

by igorw at 2013-01-07T15:33:57Z

+1 for service provider.

---------------------------------------------------------------------------

by davedevelopment at 2013-01-07T16:35:03Z

Currently thinking of a reasonable name for a service provider, answers on a post card.

---------------------------------------------------------------------------

by simensen at 2013-01-09T19:37:17Z

Excited to see this get in. Thanks for your work on it @davedevelopment !

---------------------------------------------------------------------------

by igorw at 2013-01-09T23:20:47Z

👍
parents ff30deab 9ce84e86
<?php
/*
* This file is part of the Silex framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Silex\Provider;
use Silex\Application;
use Silex\ServiceProviderInterface;
use Silex\ServiceControllerResolver;
class ServiceControllerServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['resolver'] = $app->share($app->extend('resolver', function ($resolver, $app) {
return new ServiceControllerResolver($resolver, $app);
}));
}
public function boot(Application $app)
{
// noop
}
}
<?php
/*
* This file is part of the Silex framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Silex;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
/**
* Enables name_of_service:method_name syntax for declaring controllers.
*
* @link http://silex.sensiolabs.org/doc/cookbook/controllers_as_services.html
*/
class ServiceControllerResolver implements ControllerResolverInterface
{
const SERVICE_PATTERN = "/[A-Za-z0-9\._\-]+:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/";
protected $resolver;
protected $app;
/**
* Constructor.
*
* @param ControllerResolverInterface $resolver A ControllerResolverInterface instance to delegate to
* @param Application $app An Application instance
*/
public function __construct(ControllerResolverInterface $resolver, Application $app)
{
$this->resolver = $resolver;
$this->app = $app;
}
/**
* {@inheritdoc}
*/
public function getController(Request $request)
{
$controller = $request->attributes->get('_controller', null);
if (!is_string($controller) || !preg_match(static::SERVICE_PATTERN, $controller)) {
return $this->resolver->getController($request);
}
list($service, $method) = explode(':', $controller, 2);
if (!isset($this->app[$service])) {
throw new \InvalidArgumentException(sprintf('Service "%s" does not exist.', $service));
}
return array($this->app[$service], $method);
}
/**
* {@inheritdoc}
*/
public function getArguments(Request $request, $controller)
{
return $this->resolver->getArguments($request, $controller);
}
}
<?php
/*
* This file is part of the Silex framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Silex\Tests;
use Silex\Application;
use Silex\Provider\ServiceControllerServiceProvider;
use Symfony\Component\HttpFoundation\Request;
/**
* Router test cases, using the ServiceControllerResolver
*/
class ServiceControllerResolverRouterTest extends RouterTest
{
public function testServiceNameControllerSyntax()
{
$app = new Application();
$app['service_name'] = function () {
return new MyController;
};
$app->get('/bar', 'service_name:getBar');
$this->checkRouteResponse($app, '/bar', 'bar');
}
protected function checkRouteResponse($app, $path, $expectedContent, $method = 'get', $message = null)
{
$app->register(new ServiceControllerServiceProvider());
$request = Request::create($path, $method);
$response = $app->handle($request);
$this->assertEquals($expectedContent, $response->getContent(), $message);
}
}
<?php
/*
* This file is part of the Silex framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Silex\Tests;
use Silex\ServiceControllerResolver;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
/**
* Unit tests for ServiceControllerResolver, see ServiceControllerResolverRouterTest for some
* integration tests
*/
class ServiceControllerResolverTest extends \PHPUnit_Framework_Testcase
{
public function setup()
{
$this->mockResolver = $this->getMockBuilder('Symfony\Component\HttpKernel\Controller\ControllerResolverInterface')
->disableOriginalConstructor()
->getMock();
$this->app = new Application();
$this->resolver = new ServiceControllerResolver($this->mockResolver, $this->app);
}
public function testShouldResolveServiceController()
{
$this->app['some_service'] = function() { return new \stdClass(); };
$req = Request::create('/');
$req->attributes->set('_controller', 'some_service:methodName');
$this->assertEquals(
array($this->app['some_service'], 'methodName'),
$this->resolver->getController($req)
);
}
public function testShouldDelegateNonStrings()
{
$req = Request::create('/');
$req->attributes->set('_controller', function() {});
$this->mockResolver->expects($this->once())
->method('getController')
->with($req)
->will($this->returnValue(123));
$this->assertEquals(123, $this->resolver->getController($req));
}
/**
* Note: This doesn't test the regex extensively, just a common use case
*/
public function testShouldDelegateNonMatchingSyntax()
{
$req = Request::create('/');
$req->attributes->set('_controller', 'some_class::methodName');
$this->mockResolver->expects($this->once())
->method('getController')
->with($req)
->will($this->returnValue(123));
$this->assertEquals(123, $this->resolver->getController($req));
}
/**
* @expectedException InvalidArgumentException
* @expectedExceptionMessage Service "some_service" does not exist.
*/
public function testShouldThrowIfServiceIsMissing()
{
$req = Request::create('/');
$req->attributes->set('_controller', 'some_service:methodName');
$this->resolver->getController($req);
}
public function testShouldDelegateGetArguments()
{
$req = Request::create('/');
$this->mockResolver->expects($this->once())
->method('getArguments')
->with($req)
->will($this->returnValue(123));
$this->assertEquals(123, $this->resolver->getArguments($req, function() {}));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment