Created
September 29, 2012 22:48
-
-
Save jmather/3805361 to your computer and use it in GitHub Desktop.
Revisions
-
jmather revised this gist
Oct 2, 2012 . 1 changed file with 0 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -16,10 +16,6 @@ public function __construct(Request $request) public function onMatch(UrlMatcherEvent $event) { foreach($this->request->request->get('_accept') as $accept) { if (preg_match('/^('.$event->getRoute()->getRequirement('_accept').')$/', $accept)) -
jmather revised this gist
Oct 2, 2012 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -9,5 +9,7 @@ public function accept($content_types) $content_regexps = array_map(function($item) { return preg_quote($item, '/'); }, $content_types); $this->setRequirement('_accept', implode('|', $content_regexps)); return $this; } } -
jmather revised this gist
Oct 2, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -14,7 +14,7 @@ public static function onKernelRequest(GetResponseEvent $event) { $raw_accepts = explode(',', $event->getRequest()->headers->get('Accept')); $accepts = array_map('trim', $raw_accepts); $event->getRequest()->request->set('_accept', $accepts); -
jmather revised this gist
Oct 2, 2012 . 7 changed files with 101 additions and 206 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,30 @@ <?php use Symfony\Component\HttpKernel\Event\FilterControllerEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class AcceptHeaderKernelListener implements EventSubscriberInterface { public static function onKernelRequest(GetResponseEvent $event) { if ($event->getRequest()->headers->get('Accept') != '') { $raw_accepts = explode(',', $event->getRequest()->headers->get('Accept')); $accepts = array_map(function($line) { return trim($line); }, $raw_accepts); $event->getRequest()->request->set('_accept', $accepts); $event->getDispatcher()->addSubscriber(new \AcceptHeaderMatchEventListener($event->getRequest())); } } public static function getSubscribedEvents() { return array(KernelEvents::REQUEST => array('onKernelRequest', 100)); } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,41 @@ <?php use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Routing\Matcher\UrlMatcher; use Symfony\Component\Routing\Matcher\UrlMatcherEvent; use Symfony\Component\HttpFoundation\Request; class AcceptHeaderMatchEventListener implements EventSubscriberInterface { private $request; public function __construct(Request $request) { $this->request = $request; } public function onMatch(UrlMatcherEvent $event) { var_dump('GOT'); var_dump($this->request->request->get('_accept')); var_dump($event->getRoute()->getRequirement('_accept')); foreach($this->request->request->get('_accept') as $accept) { if (preg_match('/^('.$event->getRoute()->getRequirement('_accept').')$/', $accept)) { $event->getRoute()->setDefault('accept_header', $accept); $event->setStatus(UrlMatcherEvent::REQUIREMENT_MATCH); return; } } $event->setStatus(UrlMatcherEvent::REQUIREMENT_MISMATCH); } public static function getSubscribedEvents() { return array(UrlMatcher::EVENT_HANDLE_REQUIREMENTS => array('onMatch', 100)); } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,13 @@ <?php use Silex\Route; class AcceptHeaderRoute extends Route { public function accept($content_types) { $content_regexps = array_map(function($item) { return preg_quote($item, '/'); }, $content_types); $this->setRequirement('_accept', implode('|', $content_regexps)); } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -7,6 +7,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\KernelEvents; use Silex\RedirectableUrlMatcher; class AcceptHeaderRoutingTest extends WebTestCase { @@ -19,47 +20,41 @@ public function createApplication() { $app = new \Silex\Application(); $app['route_class'] = '\\AcceptHeaderRoute'; $app['dispatcher']->addSubscriber(new \AcceptHeaderKernelListener()); $app['url_matcher'] = $app->share(function () use ($app) { $matcher = new RedirectableUrlMatcher($app['routes'], $app['request_context']); $matcher->setEventDispatcher($app['dispatcher']); return $matcher; }); /** @var $controllers1 VersionedRestControllerCollection */ $controllers1 = $app['controllers_factory']; $controllers1->get('/test', function($accept_header) use ($app) { if ($accept_header == 'application/ven.test.v1+json') $cont = json_encode(array('content' => 'hello')); else $cont = '<content>hello</content>'; return new Response($cont, 200, array('Content-Type' => $accept_header)); })->accept(array('application/ven.test.v1+json', 'application/ven.test.v1+xml')); /** @var $controllers1 VersionedRestControllerCollection */ $controllers2 = $app['controllers_factory']; $controllers1->get('/test', function($accept_header) use ($app) { if ($accept_header == 'application/ven.test.v2+json') $cont = json_encode(array('content' => 'hiya')); else $cont = '<content>hiya</content>'; return new Response($cont, 200, array('Content-Type' => $accept_header)); })->accept(array('application/ven.test.v2+json', 'application/ven.test.v2+xml')); $app->mount('/', $controllers1); This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,102 +0,0 @@ This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,46 +0,0 @@ This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,36 +0,0 @@ -
jmather revised this gist
Sep 29, 2012 . 3 changed files with 17 additions and 14 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,15 +5,15 @@ class VersionedRestControllerCollection extends \Silex\ControllerCollection { private $accept_header; /** * Constructor. */ public function __construct(Route $defaultRoute, $accept_header) { $this->defaultRoute = $defaultRoute; $this->accept_header = $accept_header; } /** @@ -36,10 +36,10 @@ public function match($pattern, $to, $formats = array()) $route->setPattern($pattern); $route->setDefault('_controller', $to); $route->addRequirements(array('_format' => '('.implode('|', $formats).')')); $route->addRequirements(array('_accept' => preg_quote($this->accept_header, '/'))); $this->controllers[] = $controller = new Controller($route); $controller->bind(md5($this->accept_header.'_'.$pattern)); return $controller; } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -10,11 +10,12 @@ class VersionedRestKernelListener implements EventSubscriberInterface { public static function onKernelRequest(GetResponseEvent $event) { $pattern = '|^(.*)(?:\+([a-z]+))?$|U'; if (preg_match($pattern, $event->getRequest()->headers->get('Accept'), $matches)) { if (isset($matches[2]) && $matches[2] != '') $event->getRequest()->request->set('_format', $matches[2]); $event->getRequest()->request->set('_accept', $matches[1]); } } /** This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -4,6 +4,7 @@ use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RequestContext; use Symfony\Component\HttpFoundation\Request; class VersionedRestUrlMatcher extends Silex\RedirectableUrlMatcher { private $request; @@ -21,13 +22,14 @@ protected function handleRouteRequirements($pathinfo, $name, Route $route) if ($ret[0] == self::REQUIREMENT_MISMATCH) return $ret; foreach($route->getRequirements() as $name => $value) { if ($name == '_method') continue; if (false == preg_match('/^'.$value.'$/', $this->request->request->get($name))) return array(self::REQUIREMENT_MISMATCH, null); } return array(self::REQUIREMENT_MATCH, null); } -
jmather created this gist
Sep 29, 2012 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,112 @@ <?php use Silex\WebTestCase; use Symfony\Component\HttpKernel\HttpKernel; use Silex\Controller; use Silex\ControllerCollection; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\KernelEvents; class AcceptHeaderRoutingTest extends WebTestCase { /** * Creates the application. * * @return HttpKernel */ public function createApplication() { $app = new \Silex\Application(); $app['dispatcher']->addSubscriber(new \VersionedRestKernelListener()); $app['versioned_rest_controllers_factory'] = $app->protect(function ($version) use ($app) { return new \VersionedRestControllerCollection($app['route_factory'], $version); }); $app['url_matcher'] = $app->share(function () use ($app) { return new \VersionedRestUrlMatcher($app['routes'], $app['request_context'], $app['request']); }); /** @var $controllers1 VersionedRestControllerCollection */ $controllers1 = $app['versioned_rest_controllers_factory']('application/ven.test.v1'); $controllers1->get('/test', function(Request $request) use ($app) { $_format = $request->request->get('_format'); $_api_version = $request->request->get('_api_version'); if ($_format == 'json') $cont = json_encode(array('content' => 'hello')); else $cont = '<content>hello</content>'; return new Response($cont, 200, array('Content-Type' => $_api_version.'+'.$_format)); }, array('json', 'xml')); /** @var $controllers1 VersionedRestControllerCollection */ $controllers2 = $app['versioned_rest_controllers_factory']('application/ven.test.v2'); $controllers2->get('/test', function(Request $request) use ($app) { $_format = $request->request->get('_format'); $_api_version = $request->request->get('_api_version'); if ($_format == 'json') $cont = json_encode(array('content' => 'hiya')); elseif ($_format == 'xml') $cont = '<content>hiya</content>'; return new Response($cont, 200, array('Content-Type' => $_api_version.'+'.$_format)); }, array('xml', 'json')); $app->mount('/', $controllers1); $app->mount('/', $controllers2); $app['debug'] = true; unset($app['exception_handler']); return $app; } public function testValidV1Call() { $client = $this->createClient(); $crawler = $client->request('GET', '/test', array(), array(), array('HTTP_ACCEPT' => 'application/ven.test.v1+xml')); $this->assertEquals(200, $client->getResponse()->getStatusCode()); $result = $client->getResponse()->getContent(); $this->assertEquals('<content>hello</content>', $result, 'response is correct'); } public function testValidV2Call() { $client = $this->createClient(); $crawler = $client->request('GET', '/test', array(), array(), array('HTTP_ACCEPT' => 'application/ven.test.v2+xml')); $this->assertEquals(200, $client->getResponse()->getStatusCode()); $result = $client->getResponse()->getContent(); $this->assertEquals('<content>hiya</content>', $result, 'response is correct'); } /** * @expectedException Symfony\Component\HttpKernel\Exception\NotFoundHttpException */ public function testInvalidV3Call() { $client = $this->createClient(); $crawler = $client->request('GET', '/test', array(), array(), array('HTTP_ACCEPT' => 'application/ven.test.v3+xml')); $this->assertEquals(404, $client->getResponse()->getStatusCode()); } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,102 @@ <?php use Silex\Controller; use Silex\Route; class VersionedRestControllerCollection extends \Silex\ControllerCollection { private $version; /** * Constructor. */ public function __construct(Route $defaultRoute, $version) { $this->defaultRoute = $defaultRoute; $this->version = $version; } /** * Maps a pattern to a callable. * * You can optionally specify HTTP methods that should be matched. * * @param string $pattern Matched route pattern * @param mixed $to Callback that returns the response when matched * @param array $formats * * @return Controller */ public function match($pattern, $to, $formats = array()) { if (!is_array($formats)) $formats = array($formats); $route = clone $this->defaultRoute; $route->setPattern($pattern); $route->setDefault('_controller', $to); $route->addRequirements(array('_format' => '('.implode('|', $formats).')')); $route->addRequirements(array('_api_version' => $this->version)); $this->controllers[] = $controller = new Controller($route); $controller->bind(md5($this->version.'_'.$pattern)); return $controller; } /** * Maps a GET request to a callable. * * @param string $pattern Matched route pattern * @param mixed $to Callback that returns the response when matched * @param array $formats * * @return Controller */ public function get($pattern, $to, $formats = array()) { return $this->match($pattern, $to, $formats)->method('GET'); } /** * Maps a POST request to a callable. * * @param string $pattern Matched route pattern * @param mixed $to Callback that returns the response when matched * @param array $formats * * @return Controller */ public function post($pattern, $to, $formats = array()) { return $this->match($pattern, $to, $formats)->method('POST'); } /** * Maps a PUT request to a callable. * * @param string $pattern Matched route pattern * @param mixed $to Callback that returns the response when matched * @param array $formats * * @return Controller */ public function put($pattern, $to, $formats = array()) { return $this->match($pattern, $to, $formats)->method('PUT'); } /** * Maps a DELETE request to a callable. * * @param string $pattern Matched route pattern * @param mixed $to Callback that returns the response when matched * @param array $formats * * @return Controller */ public function delete($pattern, $to, $formats = array()) { return $this->match($pattern, $to, $formats)->method('DELETE'); } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,45 @@ <?php use Symfony\Component\HttpKernel\Event\FilterControllerEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class VersionedRestKernelListener implements EventSubscriberInterface { public static function onKernelRequest(GetResponseEvent $event) { $pattern = '|(application/ven\.test\.v[0-9]+)\+([a-z]+)|'; if (preg_match($pattern, $event->getRequest()->headers->get('Accept'), $matches)) { $event->getRequest()->request->set('_format', $matches[2]); $event->getRequest()->request->set('_api_version', $matches[1]); } } /** * Returns an array of event names this subscriber wants to listen to. * * The array keys are event names and the value can be: * * * The method name to call (priority defaults to 0) * * An array composed of the method name to call and the priority * * An array of arrays composed of the method names to call and respective * priorities, or 0 if unset * * For instance: * * * array('eventName' => 'methodName') * * array('eventName' => array('methodName', $priority)) * * array('eventName' => array(array('methodName1', $priority), array('methodName2')) * * @return array The event names to listen to * * @api */ public static function getSubscribedEvents() { return array(KernelEvents::REQUEST => array('onKernelRequest', 100)); } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,34 @@ <?php use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RequestContext; use Symfony\Component\HttpFoundation\Request; class VersionedRestUrlMatcher extends Silex\RedirectableUrlMatcher { private $request; public function __construct(RouteCollection $routes, RequestContext $context, Request $request) { parent::__construct($routes, $context); $this->request = $request; } protected function handleRouteRequirements($pathinfo, $name, Route $route) { $ret = parent::handleRouteRequirements($pathinfo, $name, $route); if ($ret[0] == self::REQUIREMENT_MISMATCH) return $ret; $formats = $route->getRequirement('_format'); if (!preg_match($formats, $this->request->request->get('_format'))) return array(self::REQUIREMENT_MISMATCH, null); $version = $route->getRequirement('_api_version'); if ($version !== $this->request->request->get('_api_version')) return array(self::REQUIREMENT_MISMATCH, null); return array(self::REQUIREMENT_MATCH, null); } }