Commit 65afac9f authored by RJ Garcia's avatar RJ Garcia

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.
- Updated the service_controller documentation to note about all callables
Signed-off-by: default avatarRJ Garcia <rj@bighead.net>
parent 5f0fc5c1
...@@ -114,3 +114,29 @@ followed by a single colon (:), followed by the method name. ...@@ -114,3 +114,29 @@ followed by a single colon (:), followed by the method name.
}; };
$app->get('/posts.json', "posts.controller:indexJsonAction"); $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 ...@@ -33,7 +33,7 @@ class CallbackResolver
*/ */
public function isValid($name) 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 ...@@ -41,19 +41,25 @@ class CallbackResolver
* *
* @param string $name * @param string $name
* *
* @return array A callable array * @return callable A callable value
* *
* @throws \InvalidArgumentException In case the method does not exist. * @throws \InvalidArgumentException In case the method does not exist.
*/ */
public function convertCallback($name) 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])) { if (!is_callable($callback)) {
throw new \InvalidArgumentException(sprintf('Service "%s" does not exist.', $service)); throw new \InvalidArgumentException(sprintf('Service "%s" is not callable.', $service));
} }
return array($this->app[$service], $method); return $callback;
} }
/** /**
...@@ -61,7 +67,7 @@ class CallbackResolver ...@@ -61,7 +67,7 @@ class CallbackResolver
* *
* @param string $name * @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. * @throws \InvalidArgumentException In case the method does not exist.
*/ */
......
...@@ -27,27 +27,55 @@ class CallbackResolverTest extends \PHPUnit_Framework_Testcase ...@@ -27,27 +27,55 @@ class CallbackResolverTest extends \PHPUnit_Framework_Testcase
public function testShouldResolveCallback() 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('some_service:methodName'));
$this->assertTrue($this->resolver->isValid('callable_service'));
$this->assertEquals( $this->assertEquals(
array($this->app['some_service'], 'methodName'), array($this->app['some_service'], 'append'),
$this->resolver->convertCallback('some_service:methodName') $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)); return array(
$this->assertFalse($this->resolver->isValid('some_service::methodName')); array(null),
array('some_service::methodName'),
array('missing_service'),
);
} }
/** /**
* @expectedException \InvalidArgumentException * @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