Skip to content

Commit

Permalink
Merge branch '4.x' into 4.3-Release
Browse files Browse the repository at this point in the history
  • Loading branch information
l0gicgate committed Oct 5, 2019
2 parents 8f0652f + 3224271 commit fc79a96
Show file tree
Hide file tree
Showing 25 changed files with 176 additions and 90 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Expand Up @@ -4,7 +4,7 @@

1. Fork the Slim Framework repository
2. Create a new branch for each feature or improvement
3. Send a pull request from each feature branch to the **develop** branch
3. Send a pull request from each feature branch to the **4.x** branch

It is very important to separate new features or improvements into separate feature branches, and to send a
pull request for each branch. This allows me to review and pull in new features or improvements individually.
Expand Down
13 changes: 10 additions & 3 deletions README.md
Expand Up @@ -35,7 +35,7 @@ To install the Slim-Http library simply run the following command:
composer require slim/http
```

The `ServerRequest` and `Response` object decorators are automatically detected and applied by the internal factories. If you have installed Slim-Http and wish to turn off automatic object decoration you can use the following statements:
The `ServerRequest` and `Response` object decorators are automatically detected and applied by the internal factories. If you have installed Slim-Http and wish to turn off automatic object decoration then you can use the following statements:
```php
<?php

Expand All @@ -57,6 +57,8 @@ In order for auto-detection to work and enable you to use `AppFactory::create()`
- [Guzzle/psr7](https://github.com/guzzle/psr7) & [http-interop/http-factory-guzzle](https://github.com/http-interop/http-factory-guzzle) - Install using `composer require guzzlehttp/psr7 http-interop/http-factory-guzzle`
- [zend-diactoros](https://github.com/zendframework/zend-diactoros) - Install using `composer require zendframework/zend-diactoros`

Then create file _public/index.php_.

```php
<?php
use Psr\Http\Message\ResponseInterface as Response;
Expand All @@ -71,7 +73,12 @@ $app = AppFactory::create();
// Add error middleware
$app->addErrorMiddleware(true, true, true);

// Add route
// Add routes
$app->get('/', function (Request $request, Response $response) {
$response->getBody()->write('<a href="/hello/world">Try /hello/world</a>');
return $response;
});

$app->get('/hello/{name}', function (Request $request, Response $response, $args) {
$name = $args['name'];
$response->getBody()->write("Hello, $name");
Expand All @@ -83,7 +90,7 @@ $app->run();

You may quickly test this using the built-in PHP server:
```bash
$ php -S localhost:8000
$ php -S localhost:8000 -t public
```

Going to http://localhost:8000/hello/world will now display "Hello, world".
Expand Down
4 changes: 3 additions & 1 deletion Slim/App.php
Expand Up @@ -70,7 +70,7 @@ public function __construct(
);

$this->routeResolver = $routeResolver ?? new RouteResolver($this->routeCollector);
$routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser());
$routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser(), $this);

if (!$middlewareDispatcher) {
$middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container);
Expand Down Expand Up @@ -120,6 +120,8 @@ public function addMiddleware(MiddlewareInterface $middleware): self
/**
* Add the Slim built-in routing middleware to the app middleware stack
*
* This method can be used to control middleware order and is not required for default routing operation.
*
* @return RoutingMiddleware
*/
public function addRoutingMiddleware(): RoutingMiddleware
Expand Down
1 change: 1 addition & 0 deletions Slim/Exception/HttpMethodNotAllowedException.php
Expand Up @@ -36,6 +36,7 @@ public function getAllowedMethods(): array
public function setAllowedMethods(array $methods): HttpMethodNotAllowedException
{
$this->allowedMethods = $methods;
$this->message = 'Method not allowed. Must be one of: ' . implode(', ', $methods);
return $this;
}
}
24 changes: 14 additions & 10 deletions Slim/Middleware/ErrorMiddleware.php
Expand Up @@ -142,13 +142,15 @@ public function getDefaultErrorHandler()
/**
* Set callable as the default Slim application error handler.
*
* This service MUST return a callable that accepts
* three arguments optionally four arguments.
* The callable signature MUST match the ErrorHandlerInterface
*
* @see \Slim\Interfaces\ErrorHandlerInterface
*
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
* 2. Instance of \Psr\Http\Message\ResponseInterface
* 3. Instance of \Exception
* 4. Boolean displayErrorDetails (optional)
* 2. Instance of \Throwable
* 3. Boolean displayErrorDetails
* 4. Boolean $logErrors
* 5. Boolean $logErrorDetails
*
* The callable MUST return an instance of
* \Psr\Http\Message\ResponseInterface.
Expand All @@ -166,13 +168,15 @@ public function setDefaultErrorHandler($handler): self
* Set callable to handle scenarios where an error
* occurs when processing the current request.
*
* This service MUST return a callable that accepts
* three arguments optionally four arguments.
* The callable signature MUST match the ErrorHandlerInterface
*
* @see \Slim\Interfaces\ErrorHandlerInterface
*
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
* 2. Instance of \Psr\Http\Message\ResponseInterface
* 3. Instance of \Exception
* 4. Boolean displayErrorDetails (optional)
* 2. Instance of \Throwable
* 3. Boolean displayErrorDetails
* 4. Boolean $logErrors
* 5. Boolean $logErrorDetails
*
* The callable MUST return an instance of
* \Psr\Http\Message\ResponseInterface.
Expand Down
8 changes: 5 additions & 3 deletions Slim/Routing/Dispatcher.php
Expand Up @@ -3,7 +3,7 @@

namespace Slim\Routing;

use FastRoute\RouteCollector;
use FastRoute\RouteCollector as FastRouteCollector;
use FastRoute\RouteParser\Std;
use Slim\Interfaces\DispatcherInterface;
use Slim\Interfaces\RouteCollectorInterface;
Expand Down Expand Up @@ -37,9 +37,11 @@ protected function createDispatcher(): FastRouteDispatcher
return $this->dispatcher;
}

$routeDefinitionCallback = function (RouteCollector $r) {
$routeDefinitionCallback = function (FastRouteCollector $r) {
$basePath = $this->routeCollector->getBasePath();

foreach ($this->routeCollector->getRoutes() as $route) {
$r->addRoute($route->getMethods(), $route->getPattern(), $route->getIdentifier());
$r->addRoute($route->getMethods(), $basePath . $route->getPattern(), $route->getIdentifier());
}
};

Expand Down
57 changes: 24 additions & 33 deletions Slim/Routing/FastRouteDispatcher.php
Expand Up @@ -21,64 +21,56 @@ class FastRouteDispatcher extends GroupCountBased
/**
* @param string $httpMethod
* @param string $uri
*
* @return array
*/
public function dispatch($httpMethod, $uri): array
{
if (isset($this->staticRouteMap[$httpMethod][$uri])) {
return [self::FOUND, $this->staticRouteMap[$httpMethod][$uri], []];
}

$varRouteData = $this->variableRouteData;
if (isset($varRouteData[$httpMethod])) {
$result = $this->dispatchVariableRoute($varRouteData[$httpMethod], $uri);
$routingResults = $this->routingResultsFromVariableRouteResults($result);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}
$routingResults = $this->routingResults($httpMethod, $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}

// For HEAD requests, attempt fallback to GET
if ($httpMethod === 'HEAD') {
if (isset($this->staticRouteMap['GET'][$uri])) {
return [self::FOUND, $this->staticRouteMap['GET'][$uri], []];
}
if (isset($varRouteData['GET'])) {
$result = $this->dispatchVariableRoute($varRouteData['GET'], $uri);
return $this->routingResultsFromVariableRouteResults($result);
$routingResults = $this->routingResults('GET', $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}
}

// If nothing else matches, try fallback routes
if (isset($this->staticRouteMap['*'][$uri])) {
return [self::FOUND, $this->staticRouteMap['*'][$uri], []];
}
if (isset($varRouteData['*'])) {
$result = $this->dispatchVariableRoute($varRouteData['*'], $uri);
return $this->routingResultsFromVariableRouteResults($result);
$routingResults = $this->routingResults('*', $uri);
if ($routingResults[0] === self::FOUND) {
return $routingResults;
}

if (count($this->getAllowedMethods($uri))) {
if (!empty($this->getAllowedMethods($uri))) {
return [self::METHOD_NOT_ALLOWED, null, []];
}

return [self::NOT_FOUND, null, []];
}

/**
* @param array $result
* @return array
*/
protected function routingResultsFromVariableRouteResults(array $result): array
private function routingResults(string $httpMethod, string $uri): array
{
if ($result[0] === self::FOUND) {
return [self::FOUND, $result[1], $result[2]];
if (isset($this->staticRouteMap[$httpMethod][$uri])) {
return [self::FOUND, $this->staticRouteMap[$httpMethod][$uri], []];
}

if (isset($this->variableRouteData[$httpMethod])) {
$result = $this->dispatchVariableRoute($this->variableRouteData[$httpMethod], $uri);
if ($result[0] === self::FOUND) {
return [self::FOUND, $result[1], $result[2]];
}
}

return [self::NOT_FOUND, null, []];
}

/**
* @param string $uri
*
* @return array
*/
public function getAllowedMethods(string $uri): array
Expand All @@ -94,8 +86,7 @@ public function getAllowedMethods(string $uri): array
}
}

$varRouteData = $this->variableRouteData;
foreach ($varRouteData as $method => $routeData) {
foreach ($this->variableRouteData as $method => $routeData) {
$result = $this->dispatchVariableRoute($routeData, $uri);
if ($result[0] === self::FOUND) {
$this->allowedMethods[$uri][] = $method;
Expand Down
3 changes: 1 addition & 2 deletions Slim/Routing/RouteCollector.php
Expand Up @@ -179,7 +179,7 @@ public function getBasePath(): string
}

/**
* Set the base path used in pathFor()
* Set the base path used in urlFor()
*
* @param string $basePath
*
Expand Down Expand Up @@ -262,7 +262,6 @@ public function group(string $pattern, $callable): RouteGroupInterface
*/
public function map(array $methods, string $pattern, $handler): RouteInterface
{

$route = $this->createRoute($methods, $pattern, $handler);
$this->routes[$route->getIdentifier()] = $route;
$this->routeCounter++;
Expand Down
19 changes: 10 additions & 9 deletions Slim/Routing/RouteCollectorProxy.php
Expand Up @@ -9,7 +9,6 @@

namespace Slim\Routing;

use Closure;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Slim\Interfaces\CallableResolverInterface;
Expand Down Expand Up @@ -43,27 +42,27 @@ class RouteCollectorProxy implements RouteCollectorProxyInterface
/**
* @var string
*/
protected $basePath;
protected $groupPattern;

/**
* @param ResponseFactoryInterface $responseFactory
* @param CallableResolverInterface $callableResolver
* @param RouteCollectorInterface|null $routeCollector
* @param ContainerInterface|null $container
* @param string $basePath
* @param string $groupPattern
*/
public function __construct(
ResponseFactoryInterface $responseFactory,
CallableResolverInterface $callableResolver,
?ContainerInterface $container = null,
?RouteCollectorInterface $routeCollector = null,
string $basePath = ''
string $groupPattern = ''
) {
$this->responseFactory = $responseFactory;
$this->callableResolver = $callableResolver;
$this->container = $container;
$this->routeCollector = $routeCollector ?? new RouteCollector($responseFactory, $callableResolver, $container);
$this->basePath = $basePath;
$this->groupPattern = $groupPattern;
}

/**
Expand Down Expand Up @@ -103,15 +102,16 @@ public function getRouteCollector(): RouteCollectorInterface
*/
public function getBasePath(): string
{
return $this->basePath;
return $this->routeCollector->getBasePath();
}

/**
* {@inheritdoc}
*/
public function setBasePath(string $basePath): RouteCollectorProxyInterface
{
$this->basePath = $basePath;
$this->routeCollector->setBasePath($basePath);

return $this;
}

Expand Down Expand Up @@ -176,7 +176,7 @@ public function any(string $pattern, $callable): RouteInterface
*/
public function map(array $methods, string $pattern, $callable): RouteInterface
{
$pattern = $this->basePath . $pattern;
$pattern = $this->groupPattern . $pattern;

return $this->routeCollector->map($methods, $pattern, $callable);
}
Expand All @@ -186,7 +186,8 @@ public function map(array $methods, string $pattern, $callable): RouteInterface
*/
public function group(string $pattern, $callable): RouteGroupInterface
{
$pattern = $this->basePath . $pattern;
$pattern = $this->groupPattern . $pattern;

return $this->routeCollector->group($pattern, $callable);
}

Expand Down
24 changes: 22 additions & 2 deletions Slim/Routing/RouteContext.php
Expand Up @@ -25,12 +25,13 @@ public static function fromRequest(ServerRequestInterface $serverRequest): self
$route = $serverRequest->getAttribute('route');
$routeParser = $serverRequest->getAttribute('routeParser');
$routingResults = $serverRequest->getAttribute('routingResults');
$basePath = $serverRequest->getAttribute('basePath');

if ($routeParser === null || $routingResults === null) {
throw new RuntimeException('Cannot create RouteContext before routing has been completed');
}

return new self($route, $routeParser, $routingResults);
return new self($route, $routeParser, $routingResults, $basePath);
}

/**
Expand All @@ -48,19 +49,27 @@ public static function fromRequest(ServerRequestInterface $serverRequest): self
*/
private $routingResults;

/**
* @var string|null
*/
private $basePath;

/**
* @param RouteInterface|null $route
* @param RouteParserInterface $routeParser
* @param RoutingResults $routingResults
* @param string|null $basePath
*/
private function __construct(
?RouteInterface $route,
RouteParserInterface $routeParser,
RoutingResults $routingResults
RoutingResults $routingResults,
?string $basePath = null
) {
$this->route = $route;
$this->routeParser = $routeParser;
$this->routingResults = $routingResults;
$this->basePath = $basePath;
}

/**
Expand All @@ -86,4 +95,15 @@ public function getRoutingResults(): RoutingResults
{
return $this->routingResults;
}

/**
* @return string
*/
public function getBasePath(): string
{
if ($this->basePath === null) {
throw new RuntimeException('No base path defined.');
}
return $this->basePath;
}
}

0 comments on commit fc79a96

Please sign in to comment.