Skip to content

Instantly share code, notes, and snippets.

@l0gicgate
Last active February 16, 2018 06:46
Show Gist options
  • Save l0gicgate/b47f084f7180ca119e06cc4fc55ee99b to your computer and use it in GitHub Desktop.
Save l0gicgate/b47f084f7180ca119e06cc4fc55ee99b to your computer and use it in GitHub Desktop.
Determine all allowed request methods for a request outside of slim app
<?php
use Slim\App;
$app = new App();
/**
* Routes
*/
$app->get('/foo', function ($req, ResponseInterface $res) {
return $res->withStatus(200);
});
$app->post('/foo', function ($req, ResponseInterface $res) {
return $res->withStatus(200);
});
/**
* @var Router $router
*/
$router = $app->getContainer()->get('router');
/**
* @var RequestInterface $request
* You will need to instantiate a Request object outside of the Slim app
* This can be done from Global variables easily, this is how it's done in a testing environment
*/
$env = Environment::mock([
'SCRIPT_NAME' => '/index.php',
'REQUEST_URI' => '/foo',
'REQUEST_METHOD' => 'GET,
]);
$uri = Uri::createFromEnvironment($env);
$headers = Headers::createFromEnvironment($env);
$cookies = [];
$serverParams = $env->all();
$body = new RequestBody();
$request = new Request($method, $uri, $headers, $cookies, $serverParams, $body);
/**
* Here we instantiate the RequestMethodDetector
* The results of the `RequestMethodDetector::getAllowedMethods()` is an array of allowed methods for the request's route
* In this instance, $allowedMethods will be ['GET', 'POST'] as per the routes defined above.
*/
$requestMethodDetector = new RequestMethodDetector($router);
$allowedMethods = $requestMethodDetector->getAllowedMethods($request);
<?php
use FastRoute\Dispatcher;
use FastRoute\RouteParser;
use FastRoute\RouteParser\Std as StdParser;
use FastRoute\RouteCollector;
use FastRoute\DataGenerator\GroupCountBased as GroupCountBasedDataGenerator;
use Psr\Http\Message\RequestInterface;
use Slim\Route;
use Slim\Router;
/**
* Class RequestMethodDetector
* @package RMD
*/
class RequestMethodDetector
{
/**
* @var Router
*/
protected $router;
/**
* @var Dispatcher|null
*/
protected $dispatcher;
/**
* @var RouteParser
*/
protected $routeParser;
/**
* @var array|null
*/
protected $cacheFile;
/**
* RequestMethodDetector constructor.
* @param Router $router
* @param array|null $cacheFile
*/
public function __construct(Router $router, $cacheFile = null)
{
$this->router = $router;
$this->cacheFile = $cacheFile;
$this->routeParser = new StdParser();
$this->dispatcher = $this->createDispatcher();
}
/**
* @return \FastRoute\Dispatcher
*/
protected function createDispatcher()
{
$routeMap = $this->getRouteMap();
return new RequestMethodDetectorDispatcher($routeMap);
}
/**
* @return array
*/
public function getRouteMap()
{
if ($this->cacheFile) {
$dispatchData = require $this->cacheFile;
if (!is_array($dispatchData)) {
throw new \RuntimeException("Invalid cache file `{$this->cacheFile}``.");
}
return $dispatchData;
}
$dataGenerator = new GroupCountBasedDataGenerator();
$routeCollector = new RouteCollector($this->routeParser, $dataGenerator);
foreach ($this->getRoutes() as $route) {
$routeCollector->addRoute($route->getMethods(), $route->getPattern(), $route->getIdentifier());
}
return $routeCollector->getData();
}
/**
* @return Route[]
*/
public function getRoutes()
{
return $this->router->getRoutes();
}
/**
* @return Dispatcher|null
*/
public function getDispatcher()
{
return $this->dispatcher;
}
/**
* @param RequestInterface $request
* @param bool $returnAllMethods
* @return array
*/
public function getAllowedMethods(RequestInterface $request, $returnAllMethods = true)
{
$method = $returnAllMethods ? 'UnknownMethod' : $request->getMethod();
$uri = '/' . ltrim($request->getUri()->getPath(), '/');
return $this->dispatcher->dispatch($method, $uri);
}
}
<?php
use FastRoute\Dispatcher\GroupCountBased;
/**
* Class RequestMethodDetectorDispatcher
* @package RMD
*/
class RequestMethodDetectorDispatcher extends GroupCountBased
{
/**
* @param string $httpMethod
* @param string $uri
* @return array
*/
public function dispatch($httpMethod, $uri)
{
$varRouteData = $this->variableRouteData;
$allowedMethods = [];
foreach ($this->staticRouteMap as $method => $uriMap) {
if ($method !== $httpMethod && isset($uriMap[$uri])) {
$allowedMethods[] = $method;
}
}
foreach ($varRouteData as $method => $routeData) {
if ($method === $httpMethod) {
continue;
}
$result = $this->dispatchVariableRoute($routeData, $uri);
if ($result[0] === self::FOUND) {
$allowedMethods[] = $method;
}
}
return $allowedMethods;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment