Skip to content

Commit fc79a96

Browse files
authored
Merge branch '4.x' into 4.3-Release
2 parents 8f0652f + 3224271 commit fc79a96

25 files changed

+176
-90
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

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

99
It is very important to separate new features or improvements into separate feature branches, and to send a
1010
pull request for each branch. This allows me to review and pull in new features or improvements individually.

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ To install the Slim-Http library simply run the following command:
3535
composer require slim/http
3636
```
3737

38-
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:
38+
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:
3939
```php
4040
<?php
4141

@@ -57,6 +57,8 @@ In order for auto-detection to work and enable you to use `AppFactory::create()`
5757
- [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`
5858
- [zend-diactoros](https://github.com/zendframework/zend-diactoros) - Install using `composer require zendframework/zend-diactoros`
5959

60+
Then create file _public/index.php_.
61+
6062
```php
6163
<?php
6264
use Psr\Http\Message\ResponseInterface as Response;
@@ -71,7 +73,12 @@ $app = AppFactory::create();
7173
// Add error middleware
7274
$app->addErrorMiddleware(true, true, true);
7375

74-
// Add route
76+
// Add routes
77+
$app->get('/', function (Request $request, Response $response) {
78+
$response->getBody()->write('<a href="/hello/world">Try /hello/world</a>');
79+
return $response;
80+
});
81+
7582
$app->get('/hello/{name}', function (Request $request, Response $response, $args) {
7683
$name = $args['name'];
7784
$response->getBody()->write("Hello, $name");
@@ -83,7 +90,7 @@ $app->run();
8390

8491
You may quickly test this using the built-in PHP server:
8592
```bash
86-
$ php -S localhost:8000
93+
$ php -S localhost:8000 -t public
8794
```
8895

8996
Going to http://localhost:8000/hello/world will now display "Hello, world".

Slim/App.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public function __construct(
7070
);
7171

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

7575
if (!$middlewareDispatcher) {
7676
$middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container);
@@ -120,6 +120,8 @@ public function addMiddleware(MiddlewareInterface $middleware): self
120120
/**
121121
* Add the Slim built-in routing middleware to the app middleware stack
122122
*
123+
* This method can be used to control middleware order and is not required for default routing operation.
124+
*
123125
* @return RoutingMiddleware
124126
*/
125127
public function addRoutingMiddleware(): RoutingMiddleware

Slim/Exception/HttpMethodNotAllowedException.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public function getAllowedMethods(): array
3636
public function setAllowedMethods(array $methods): HttpMethodNotAllowedException
3737
{
3838
$this->allowedMethods = $methods;
39+
$this->message = 'Method not allowed. Must be one of: ' . implode(', ', $methods);
3940
return $this;
4041
}
4142
}

Slim/Middleware/ErrorMiddleware.php

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,15 @@ public function getDefaultErrorHandler()
142142
/**
143143
* Set callable as the default Slim application error handler.
144144
*
145-
* This service MUST return a callable that accepts
146-
* three arguments optionally four arguments.
145+
* The callable signature MUST match the ErrorHandlerInterface
146+
*
147+
* @see \Slim\Interfaces\ErrorHandlerInterface
147148
*
148149
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
149-
* 2. Instance of \Psr\Http\Message\ResponseInterface
150-
* 3. Instance of \Exception
151-
* 4. Boolean displayErrorDetails (optional)
150+
* 2. Instance of \Throwable
151+
* 3. Boolean displayErrorDetails
152+
* 4. Boolean $logErrors
153+
* 5. Boolean $logErrorDetails
152154
*
153155
* The callable MUST return an instance of
154156
* \Psr\Http\Message\ResponseInterface.
@@ -166,13 +168,15 @@ public function setDefaultErrorHandler($handler): self
166168
* Set callable to handle scenarios where an error
167169
* occurs when processing the current request.
168170
*
169-
* This service MUST return a callable that accepts
170-
* three arguments optionally four arguments.
171+
* The callable signature MUST match the ErrorHandlerInterface
172+
*
173+
* @see \Slim\Interfaces\ErrorHandlerInterface
171174
*
172175
* 1. Instance of \Psr\Http\Message\ServerRequestInterface
173-
* 2. Instance of \Psr\Http\Message\ResponseInterface
174-
* 3. Instance of \Exception
175-
* 4. Boolean displayErrorDetails (optional)
176+
* 2. Instance of \Throwable
177+
* 3. Boolean displayErrorDetails
178+
* 4. Boolean $logErrors
179+
* 5. Boolean $logErrorDetails
176180
*
177181
* The callable MUST return an instance of
178182
* \Psr\Http\Message\ResponseInterface.

Slim/Routing/Dispatcher.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace Slim\Routing;
55

6-
use FastRoute\RouteCollector;
6+
use FastRoute\RouteCollector as FastRouteCollector;
77
use FastRoute\RouteParser\Std;
88
use Slim\Interfaces\DispatcherInterface;
99
use Slim\Interfaces\RouteCollectorInterface;
@@ -37,9 +37,11 @@ protected function createDispatcher(): FastRouteDispatcher
3737
return $this->dispatcher;
3838
}
3939

40-
$routeDefinitionCallback = function (RouteCollector $r) {
40+
$routeDefinitionCallback = function (FastRouteCollector $r) {
41+
$basePath = $this->routeCollector->getBasePath();
42+
4143
foreach ($this->routeCollector->getRoutes() as $route) {
42-
$r->addRoute($route->getMethods(), $route->getPattern(), $route->getIdentifier());
44+
$r->addRoute($route->getMethods(), $basePath . $route->getPattern(), $route->getIdentifier());
4345
}
4446
};
4547

Slim/Routing/FastRouteDispatcher.php

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -21,64 +21,56 @@ class FastRouteDispatcher extends GroupCountBased
2121
/**
2222
* @param string $httpMethod
2323
* @param string $uri
24+
*
2425
* @return array
2526
*/
2627
public function dispatch($httpMethod, $uri): array
2728
{
28-
if (isset($this->staticRouteMap[$httpMethod][$uri])) {
29-
return [self::FOUND, $this->staticRouteMap[$httpMethod][$uri], []];
30-
}
31-
32-
$varRouteData = $this->variableRouteData;
33-
if (isset($varRouteData[$httpMethod])) {
34-
$result = $this->dispatchVariableRoute($varRouteData[$httpMethod], $uri);
35-
$routingResults = $this->routingResultsFromVariableRouteResults($result);
36-
if ($routingResults[0] === self::FOUND) {
37-
return $routingResults;
38-
}
29+
$routingResults = $this->routingResults($httpMethod, $uri);
30+
if ($routingResults[0] === self::FOUND) {
31+
return $routingResults;
3932
}
4033

4134
// For HEAD requests, attempt fallback to GET
4235
if ($httpMethod === 'HEAD') {
43-
if (isset($this->staticRouteMap['GET'][$uri])) {
44-
return [self::FOUND, $this->staticRouteMap['GET'][$uri], []];
45-
}
46-
if (isset($varRouteData['GET'])) {
47-
$result = $this->dispatchVariableRoute($varRouteData['GET'], $uri);
48-
return $this->routingResultsFromVariableRouteResults($result);
36+
$routingResults = $this->routingResults('GET', $uri);
37+
if ($routingResults[0] === self::FOUND) {
38+
return $routingResults;
4939
}
5040
}
5141

5242
// If nothing else matches, try fallback routes
53-
if (isset($this->staticRouteMap['*'][$uri])) {
54-
return [self::FOUND, $this->staticRouteMap['*'][$uri], []];
55-
}
56-
if (isset($varRouteData['*'])) {
57-
$result = $this->dispatchVariableRoute($varRouteData['*'], $uri);
58-
return $this->routingResultsFromVariableRouteResults($result);
43+
$routingResults = $this->routingResults('*', $uri);
44+
if ($routingResults[0] === self::FOUND) {
45+
return $routingResults;
5946
}
6047

61-
if (count($this->getAllowedMethods($uri))) {
48+
if (!empty($this->getAllowedMethods($uri))) {
6249
return [self::METHOD_NOT_ALLOWED, null, []];
6350
}
6451

6552
return [self::NOT_FOUND, null, []];
6653
}
6754

68-
/**
69-
* @param array $result
70-
* @return array
71-
*/
72-
protected function routingResultsFromVariableRouteResults(array $result): array
55+
private function routingResults(string $httpMethod, string $uri): array
7356
{
74-
if ($result[0] === self::FOUND) {
75-
return [self::FOUND, $result[1], $result[2]];
57+
if (isset($this->staticRouteMap[$httpMethod][$uri])) {
58+
return [self::FOUND, $this->staticRouteMap[$httpMethod][$uri], []];
7659
}
60+
61+
if (isset($this->variableRouteData[$httpMethod])) {
62+
$result = $this->dispatchVariableRoute($this->variableRouteData[$httpMethod], $uri);
63+
if ($result[0] === self::FOUND) {
64+
return [self::FOUND, $result[1], $result[2]];
65+
}
66+
}
67+
7768
return [self::NOT_FOUND, null, []];
7869
}
7970

8071
/**
8172
* @param string $uri
73+
*
8274
* @return array
8375
*/
8476
public function getAllowedMethods(string $uri): array
@@ -94,8 +86,7 @@ public function getAllowedMethods(string $uri): array
9486
}
9587
}
9688

97-
$varRouteData = $this->variableRouteData;
98-
foreach ($varRouteData as $method => $routeData) {
89+
foreach ($this->variableRouteData as $method => $routeData) {
9990
$result = $this->dispatchVariableRoute($routeData, $uri);
10091
if ($result[0] === self::FOUND) {
10192
$this->allowedMethods[$uri][] = $method;

Slim/Routing/RouteCollector.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ public function getBasePath(): string
179179
}
180180

181181
/**
182-
* Set the base path used in pathFor()
182+
* Set the base path used in urlFor()
183183
*
184184
* @param string $basePath
185185
*
@@ -262,7 +262,6 @@ public function group(string $pattern, $callable): RouteGroupInterface
262262
*/
263263
public function map(array $methods, string $pattern, $handler): RouteInterface
264264
{
265-
266265
$route = $this->createRoute($methods, $pattern, $handler);
267266
$this->routes[$route->getIdentifier()] = $route;
268267
$this->routeCounter++;

Slim/Routing/RouteCollectorProxy.php

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
namespace Slim\Routing;
1111

12-
use Closure;
1312
use Psr\Container\ContainerInterface;
1413
use Psr\Http\Message\ResponseFactoryInterface;
1514
use Slim\Interfaces\CallableResolverInterface;
@@ -43,27 +42,27 @@ class RouteCollectorProxy implements RouteCollectorProxyInterface
4342
/**
4443
* @var string
4544
*/
46-
protected $basePath;
45+
protected $groupPattern;
4746

4847
/**
4948
* @param ResponseFactoryInterface $responseFactory
5049
* @param CallableResolverInterface $callableResolver
5150
* @param RouteCollectorInterface|null $routeCollector
5251
* @param ContainerInterface|null $container
53-
* @param string $basePath
52+
* @param string $groupPattern
5453
*/
5554
public function __construct(
5655
ResponseFactoryInterface $responseFactory,
5756
CallableResolverInterface $callableResolver,
5857
?ContainerInterface $container = null,
5958
?RouteCollectorInterface $routeCollector = null,
60-
string $basePath = ''
59+
string $groupPattern = ''
6160
) {
6261
$this->responseFactory = $responseFactory;
6362
$this->callableResolver = $callableResolver;
6463
$this->container = $container;
6564
$this->routeCollector = $routeCollector ?? new RouteCollector($responseFactory, $callableResolver, $container);
66-
$this->basePath = $basePath;
65+
$this->groupPattern = $groupPattern;
6766
}
6867

6968
/**
@@ -103,15 +102,16 @@ public function getRouteCollector(): RouteCollectorInterface
103102
*/
104103
public function getBasePath(): string
105104
{
106-
return $this->basePath;
105+
return $this->routeCollector->getBasePath();
107106
}
108107

109108
/**
110109
* {@inheritdoc}
111110
*/
112111
public function setBasePath(string $basePath): RouteCollectorProxyInterface
113112
{
114-
$this->basePath = $basePath;
113+
$this->routeCollector->setBasePath($basePath);
114+
115115
return $this;
116116
}
117117

@@ -176,7 +176,7 @@ public function any(string $pattern, $callable): RouteInterface
176176
*/
177177
public function map(array $methods, string $pattern, $callable): RouteInterface
178178
{
179-
$pattern = $this->basePath . $pattern;
179+
$pattern = $this->groupPattern . $pattern;
180180

181181
return $this->routeCollector->map($methods, $pattern, $callable);
182182
}
@@ -186,7 +186,8 @@ public function map(array $methods, string $pattern, $callable): RouteInterface
186186
*/
187187
public function group(string $pattern, $callable): RouteGroupInterface
188188
{
189-
$pattern = $this->basePath . $pattern;
189+
$pattern = $this->groupPattern . $pattern;
190+
190191
return $this->routeCollector->group($pattern, $callable);
191192
}
192193

Slim/Routing/RouteContext.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ public static function fromRequest(ServerRequestInterface $serverRequest): self
2525
$route = $serverRequest->getAttribute('route');
2626
$routeParser = $serverRequest->getAttribute('routeParser');
2727
$routingResults = $serverRequest->getAttribute('routingResults');
28+
$basePath = $serverRequest->getAttribute('basePath');
2829

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

33-
return new self($route, $routeParser, $routingResults);
34+
return new self($route, $routeParser, $routingResults, $basePath);
3435
}
3536

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

52+
/**
53+
* @var string|null
54+
*/
55+
private $basePath;
56+
5157
/**
5258
* @param RouteInterface|null $route
5359
* @param RouteParserInterface $routeParser
5460
* @param RoutingResults $routingResults
61+
* @param string|null $basePath
5562
*/
5663
private function __construct(
5764
?RouteInterface $route,
5865
RouteParserInterface $routeParser,
59-
RoutingResults $routingResults
66+
RoutingResults $routingResults,
67+
?string $basePath = null
6068
) {
6169
$this->route = $route;
6270
$this->routeParser = $routeParser;
6371
$this->routingResults = $routingResults;
72+
$this->basePath = $basePath;
6473
}
6574

6675
/**
@@ -86,4 +95,15 @@ public function getRoutingResults(): RoutingResults
8695
{
8796
return $this->routingResults;
8897
}
98+
99+
/**
100+
* @return string
101+
*/
102+
public function getBasePath(): string
103+
{
104+
if ($this->basePath === null) {
105+
throw new RuntimeException('No base path defined.');
106+
}
107+
return $this->basePath;
108+
}
89109
}

0 commit comments

Comments
 (0)