Skip to content

Instantly share code, notes, and snippets.

@jmather
Created September 29, 2012 22:48
Show Gist options
  • Select an option

  • Save jmather/3805361 to your computer and use it in GitHub Desktop.

Select an option

Save jmather/3805361 to your computer and use it in GitHub Desktop.

Revisions

  1. jmather revised this gist Oct 2, 2012. 1 changed file with 0 additions and 4 deletions.
    4 changes: 0 additions & 4 deletions AcceptHeaderMatchEventListener.php
    Original file line number Diff line number Diff line change
    @@ -16,10 +16,6 @@ public function __construct(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))
  2. jmather revised this gist Oct 2, 2012. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions AcceptHeaderRoute.php
    Original 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;
    }
    }
  3. jmather revised this gist Oct 2, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion AcceptHeaderKernelListener.php
    Original 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(function($line) { return trim($line); }, $raw_accepts);
    $accepts = array_map('trim', $raw_accepts);

    $event->getRequest()->request->set('_accept', $accepts);

  4. jmather revised this gist Oct 2, 2012. 7 changed files with 101 additions and 206 deletions.
    30 changes: 30 additions & 0 deletions AcceptHeaderKernelListener.php
    Original 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));
    }

    }
    41 changes: 41 additions & 0 deletions AcceptHeaderMatchEventListener.php
    Original 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));
    }
    }
    13 changes: 13 additions & 0 deletions AcceptHeaderRoute.php
    Original 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));
    }
    }
    39 changes: 17 additions & 22 deletions AcceptHeaderRoutingTest.php
    Original 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['dispatcher']->addSubscriber(new \VersionedRestKernelListener());
    $app['route_class'] = '\\AcceptHeaderRoute';

    $app['versioned_rest_controllers_factory'] = $app->protect(function ($version) use ($app) {
    return new \VersionedRestControllerCollection($app['route_factory'], $version);
    });
    $app['dispatcher']->addSubscriber(new \AcceptHeaderKernelListener());

    $app['url_matcher'] = $app->share(function () use ($app) {
    return new \VersionedRestUrlMatcher($app['routes'], $app['request_context'], $app['request']);
    $matcher = new RedirectableUrlMatcher($app['routes'], $app['request_context']);
    $matcher->setEventDispatcher($app['dispatcher']);
    return $matcher;
    });


    /** @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');
    $controllers1 = $app['controllers_factory'];

    if ($_format == 'json')
    $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' => $_api_version.'+'.$_format));
    }, array('json', 'xml'));
    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['versioned_rest_controllers_factory']('application/ven.test.v2');
    $controllers2 = $app['controllers_factory'];

    $controllers2->get('/test', function(Request $request) use ($app) {
    $_format = $request->request->get('_format');
    $_api_version = $request->request->get('_api_version');

    if ($_format == 'json')
    $controllers1->get('/test', function($accept_header) use ($app) {
    if ($accept_header == 'application/ven.test.v2+json')
    $cont = json_encode(array('content' => 'hiya'));
    elseif ($_format == 'xml')
    else
    $cont = '<content>hiya</content>';

    return new Response($cont, 200, array('Content-Type' => $_api_version.'+'.$_format));
    }, array('xml', 'json'));
    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);
    102 changes: 0 additions & 102 deletions VersionedRestControllerCollection.php
    Original file line number Diff line number Diff line change
    @@ -1,102 +0,0 @@
    <?php

    use Silex\Controller;
    use Silex\Route;

    class VersionedRestControllerCollection extends \Silex\ControllerCollection
    {
    private $accept_header;

    /**
    * Constructor.
    */
    public function __construct(Route $defaultRoute, $accept_header)
    {
    $this->defaultRoute = $defaultRoute;
    $this->accept_header = $accept_header;
    }

    /**
    * 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('_accept' => preg_quote($this->accept_header, '/')));
    $this->controllers[] = $controller = new Controller($route);

    $controller->bind(md5($this->accept_header.'_'.$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');
    }
    }
    46 changes: 0 additions & 46 deletions VersionedRestKernelListener.php
    Original file line number Diff line number Diff line change
    @@ -1,46 +0,0 @@
    <?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 = '|^(.*)(?:\+([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]);
    }
    }
    /**
    * 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));
    }

    }
    36 changes: 0 additions & 36 deletions VersionedRestUrlMatcher.php
    Original file line number Diff line number Diff line change
    @@ -1,36 +0,0 @@
    <?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;

    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);
    }
    }
  5. jmather revised this gist Sep 29, 2012. 3 changed files with 17 additions and 14 deletions.
    10 changes: 5 additions & 5 deletions VersionedRestControllerCollection.php
    Original file line number Diff line number Diff line change
    @@ -5,15 +5,15 @@

    class VersionedRestControllerCollection extends \Silex\ControllerCollection
    {
    private $version;
    private $accept_header;

    /**
    * Constructor.
    */
    public function __construct(Route $defaultRoute, $version)
    public function __construct(Route $defaultRoute, $accept_header)
    {
    $this->defaultRoute = $defaultRoute;
    $this->version = $version;
    $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('_api_version' => $this->version));
    $route->addRequirements(array('_accept' => preg_quote($this->accept_header, '/')));
    $this->controllers[] = $controller = new Controller($route);

    $controller->bind(md5($this->version.'_'.$pattern));
    $controller->bind(md5($this->accept_header.'_'.$pattern));
    return $controller;
    }

    7 changes: 4 additions & 3 deletions VersionedRestKernelListener.php
    Original file line number Diff line number Diff line change
    @@ -10,11 +10,12 @@ class VersionedRestKernelListener implements EventSubscriberInterface
    {
    public static function onKernelRequest(GetResponseEvent $event)
    {
    $pattern = '|(application/ven\.test\.v[0-9]+)\+([a-z]+)|';
    $pattern = '|^(.*)(?:\+([a-z]+))?$|U';
    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]);
    if (isset($matches[2]) && $matches[2] != '')
    $event->getRequest()->request->set('_format', $matches[2]);
    $event->getRequest()->request->set('_accept', $matches[1]);
    }
    }
    /**
    14 changes: 8 additions & 6 deletions VersionedRestUrlMatcher.php
    Original 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;

    $formats = $route->getRequirement('_format');
    if (!preg_match($formats, $this->request->request->get('_format')))
    return array(self::REQUIREMENT_MISMATCH, null);
    foreach($route->getRequirements() as $name => $value)
    {
    if ($name == '_method')
    continue;

    $version = $route->getRequirement('_api_version');
    if ($version !== $this->request->request->get('_api_version'))
    return array(self::REQUIREMENT_MISMATCH, null);
    if (false == preg_match('/^'.$value.'$/', $this->request->request->get($name)))
    return array(self::REQUIREMENT_MISMATCH, null);
    }

    return array(self::REQUIREMENT_MATCH, null);
    }
  6. jmather created this gist Sep 29, 2012.
    112 changes: 112 additions & 0 deletions AcceptHeaderRoutingTest.php
    Original 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());
    }
    }
    102 changes: 102 additions & 0 deletions VersionedRestControllerCollection.php
    Original 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');
    }
    }
    45 changes: 45 additions & 0 deletions VersionedRestKernelListener.php
    Original 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));
    }

    }
    34 changes: 34 additions & 0 deletions VersionedRestUrlMatcher.php
    Original 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);
    }
    }