Commit ea0b84a4 authored by Fabien Potencier's avatar Fabien Potencier

feature #1341 Added support for callables in CallbackResolver (ragboyjr)

This PR was merged into the 2.0.x-dev branch.

Discussion
----------

Added support for callables in CallbackResolver

Added the ability for the callback resolver to support any callable instead
of just the object and method callable type.

An alternate implementation to this would be to update the CallbackResolver to use an interface, then keep the old CallbackResolver as is and just add a new implementation that you can change if you'd like. I'd probably prefer to do the interface, but depends on what people think.

This fixes #1327
Signed-off-by: default avatarRJ Garcia <rj@bighead.net>

Commits
-------

65afac9f Added support for callables in CallbackResolver
parents ad67898b 65afac9f
......@@ -114,3 +114,29 @@ followed by a single colon (:), followed by the method name.
};
$app->get('/posts.json', "posts.controller:indexJsonAction");
In addition to using classes for service controllers, you can define any
callable as a service in the application to be used for a route.
.. code-block:: php
namespace Demo\Controller;
use Demo\Repository\PostRepository;
use Symfony\Component\HttpFoundation\JsonResponse;
function postIndexJson(PostRepository $repo) {
return function() use ($repo) {
return new JsonResponse($repo->findAll());
};
}
And when defining your route, the code would look like the following:
.. code-block:: php
$app['posts.controller'] = function($app) {
return Demo\Controller\postIndexJson($app['posts.repository']);
};
$app->get('/posts.json', 'posts.controller');
......@@ -33,7 +33,7 @@ class CallbackResolver
*/
public function isValid($name)
{
return is_string($name) && preg_match(static::SERVICE_PATTERN, $name);
return is_string($name) && (preg_match(static::SERVICE_PATTERN, $name) || isset($this->app[$name]));
}
/**
......@@ -41,19 +41,25 @@ class CallbackResolver
*
* @param string $name
*
* @return array A callable array
* @return callable A callable value
*
* @throws \InvalidArgumentException In case the method does not exist.
*/
public function convertCallback($name)
{
list($service, $method) = explode(':', $name, 2);
if (preg_match(static::SERVICE_PATTERN, $name)) {
list($service, $method) = explode(':', $name, 2);
$callback = array($this->app[$service], $method);
} else {
$service = $name;
$callback = $this->app[$name];
}
if (!isset($this->app[$service])) {
throw new \InvalidArgumentException(sprintf('Service "%s" does not exist.', $service));
if (!is_callable($callback)) {
throw new \InvalidArgumentException(sprintf('Service "%s" is not callable.', $service));
}
return array($this->app[$service], $method);
return $callback;
}
/**
......@@ -61,7 +67,7 @@ class CallbackResolver
*
* @param string $name
*
* @return array A callable array
* @return string|callable A callable value or the string passed in
*
* @throws \InvalidArgumentException In case the method does not exist.
*/
......
......@@ -27,27 +27,55 @@ class CallbackResolverTest extends \PHPUnit_Framework_Testcase
public function testShouldResolveCallback()
{
$this->app['some_service'] = function () { return new \stdClass(); };
$callable = function () {};
$this->app['some_service'] = function () { return new \ArrayObject(); };
$this->app['callable_service'] = function () use ($callable) {
return $callable;
};
$this->assertTrue($this->resolver->isValid('some_service:methodName'));
$this->assertTrue($this->resolver->isValid('callable_service'));
$this->assertEquals(
array($this->app['some_service'], 'methodName'),
$this->resolver->convertCallback('some_service:methodName')
array($this->app['some_service'], 'append'),
$this->resolver->convertCallback('some_service:append')
);
$this->assertSame($callable, $this->resolver->convertCallback('callable_service'));
}
public function testNonStringsAreNotValid()
/**
* @dataProvider nonStringsAreNotValidProvider
*/
public function testNonStringsAreNotValid($name)
{
$this->assertFalse($this->resolver->isValid($name));
}
public function nonStringsAreNotValidProvider()
{
$this->assertFalse($this->resolver->isValid(null));
$this->assertFalse($this->resolver->isValid('some_service::methodName'));
return array(
array(null),
array('some_service::methodName'),
array('missing_service'),
);
}
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage Service "some_service" does not exist.
* @expectedExceptionMessageRegExp /Service "[a-z_]+" is not callable./
* @dataProvider shouldThrowAnExceptionIfServiceIsNotCallableProvider
*/
public function testShouldThrowAnExceptionIfServiceIsMissing()
public function testShouldThrowAnExceptionIfServiceIsNotCallable($name)
{
$this->resolver->convertCallback('some_service:methodName');
$this->app['non_callable_obj'] = function () { return new \stdClass(); };
$this->app['non_callable'] = function () { return array(); };
$this->resolver->convertCallback($name);
}
public function shouldThrowAnExceptionIfServiceIsNotCallableProvider()
{
return array(
array('non_callable_obj:methodA'),
array('non_callable'),
);
}
}
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