Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
291aa96
Add RequestHandlerInterface to App
odan Feb 7, 2025
82eddad
Remove ConfigurationInterface
odan Feb 7, 2025
c0db693
Fix cs
odan Feb 7, 2025
7e34179
Add check for body parser handlers
odan May 29, 2025
5bc4169
Add body parser middleware
odan May 29, 2025
d9eba97
Add body parser middleware
odan May 29, 2025
e2419b8
Fix cs
odan May 29, 2025
427b277
Optimize FormUrlEncodedBodyParserMiddleware
odan May 29, 2025
7d9919f
Fix tests
odan May 29, 2025
f04a282
Fix tests
odan May 30, 2025
eeecc3e
Optimize JsonBodyParserMiddleware
odan May 30, 2025
afbf045
Rename ErrorHandlingMiddleware to ErrorExceptionMiddleware
odan May 31, 2025
4cf87ba
Update tests
odan May 31, 2025
d887787
Update tests
odan May 31, 2025
b141531
Fix HeadMethodMiddleware
odan May 31, 2025
b66dc02
Refactor error handling concept
odan May 31, 2025
ee5545e
Fix cs
odan May 31, 2025
7d8d01d
Update readme
odan May 31, 2025
b22b0d1
Remove JsonRenderer
odan May 31, 2025
155f718
Merge branch 'slimphp:5.x' into 5.x
odan Nov 17, 2025
1d00f64
Update
odan Nov 28, 2025
c1c0a14
Update
odan Nov 28, 2025
3f86883
Add RouterInterface
odan Nov 28, 2025
9d8aa7b
Update build
odan Nov 28, 2025
15a8e47
Fix cs
odan Nov 29, 2025
5820d13
Update
odan Nov 29, 2025
6e4cbe1
Remove RequestResponseTypedArgs
odan Nov 29, 2025
97c3889
Update
odan Nov 29, 2025
e9f17d0
Update
odan Nov 29, 2025
2dba987
Update
odan Nov 29, 2025
68077f5
Update
odan Nov 29, 2025
ab940c9
Update
odan Nov 29, 2025
3cb6b7b
Add withOrder to PipelineRunner
odan Nov 30, 2025
ccaa685
Update
odan Nov 30, 2025
978880a
Update
odan Nov 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 42 additions & 38 deletions .cs.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,70 +9,74 @@
[
'@PSR1' => true,
'@PSR2' => true,
'@Symfony' => true,
'psr_autoloading' => true,
// custom rules
'align_multiline_comment' => ['comment_type' => 'phpdocs_only'], // psr-5
'phpdoc_to_comment' => false,
'no_superfluous_phpdoc_tags' => false,
'align_multiline_comment' => ['comment_type' => 'phpdocs_only'],
'array_indentation' => true,
'array_syntax' => ['syntax' => 'short'],
'blank_line_between_import_groups' => true,
'cast_spaces' => ['space' => 'none'],
'concat_space' => ['spacing' => 'one'],
'class_definition' => [
'space_before_parenthesis' => true,
],
'compact_nullable_type_declaration' => true,
'declare_equal_normalize' => ['space' => 'single'],
'concat_space' => ['spacing' => 'one'],
'declare_equal_normalize' => ['space' => 'none'],
'declare_strict_types' => false,
'echo_tag_syntax' => ['format' => 'long'],
'fully_qualified_strict_types' => true,
'function_declaration' => [
'closure_fn_spacing' => 'none',
],
'general_phpdoc_annotation_remove' => [
'annotations' => [
'author',
'package',
],
],
'global_namespace_import' => [
'import_classes' => true,
'import_constants' => null,
'import_functions' => null,
],
'increment_style' => ['style' => 'post'],
'list_syntax' => ['syntax' => 'short'],
'echo_tag_syntax' => ['format' => 'long'],
'phpdoc_add_missing_param_annotation' => ['only_untyped' => false],
'phpdoc_align' => false,
'phpdoc_no_empty_return' => false,
'phpdoc_order' => true, // psr-5
'phpdoc_no_useless_inheritdoc' => false,
'protected_to_private' => false,
'yoda_style' => false,
'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
'ordered_imports' => [
'sort_algorithm' => 'alpha',
'imports_order' => ['class', 'function', 'const'],
],
'single_line_throw' => false,
'declare_strict_types' => false,
'blank_line_between_import_groups' => true,
'fully_qualified_strict_types' => true,
'no_null_property_initialization' => false,
'no_superfluous_phpdoc_tags' => false,
'no_unused_imports' => true,
'nullable_type_declaration_for_default_null_value' => false,
'operator_linebreak' => [
'only_booleans' => true,
'position' => 'beginning',
],
'global_namespace_import' => [
'import_classes' => true,
'import_constants' => null,
'import_functions' => null
'ordered_imports' => [
'sort_algorithm' => 'alpha',
'imports_order' => ['class', 'function', 'const'],
],
'class_definition' => [
'space_before_parenthesis' => true,
'phpdoc_add_missing_param_annotation' => ['only_untyped' => false],
'phpdoc_align' => false,
'phpdoc_no_empty_return' => false,
'phpdoc_no_useless_inheritdoc' => false,
'phpdoc_order' => true,
'phpdoc_to_comment' => false,
'protected_to_private' => false,
'psr_autoloading' => true,
'single_line_throw' => false,
'trailing_comma_in_multiline' => [
'after_heredoc' => true,
'elements' => ['array_destructuring', 'arrays', 'match'],
],
'yoda_style' => [
'equal' => false,
'identical' => false,
'less_and_greater' => false,
],
'declare_equal_normalize' => false,
'phpdoc_summary' => false,
'phpdoc_add_missing_param_annotation' => false,
'no_useless_concat_operator' => false,
'fully_qualified_strict_types' => false,
'trailing_comma_in_multiline' => ['elements' => ['arrays']],
]
],
)
->setFinder(
PhpCsFixer\Finder::create()
->in(__DIR__ . '/Slim')
->in(__DIR__ . '/tests')
->name('*.php')
->ignoreDotFiles(true)
->ignoreVCS(true)
->ignoreVCS(true),
);
9 changes: 3 additions & 6 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ jobs:
strategy:
fail-fast: false
matrix:
php: [ 8.2, 8.3, 8.4 ]
php: [ 8.2, 8.3, 8.4, 8.5 ]
include:
- php: 8.2
- php: 8.4
analysis: true

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Set up PHP ${{ matrix.php }}
uses: shivammathur/setup-php@v2
Expand All @@ -37,9 +37,6 @@ jobs:
- name: Coding standards
run: composer cs:check

- name: Code sniffer
run: composer sniffer:check

- name: Static analysis
run: composer stan

Expand Down
3 changes: 0 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

#### New Features

- New `AppBuilder` to create a Slim App instance for different scenarios. Replaces the `AppFactory`.
- Unified DI container resolution. All the factory logic has been removed and moved to the DI container. This reduces the internal complexity by delegating the building logic into the DI container.
- Provide FIFO (first in, first out) middleware order support. LIFO is not supported anymore.
- Optimized internal routing concept for better separation of concern and flexibility.
Expand Down Expand Up @@ -73,7 +72,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- `Slim/Builder/AppBuilder.php`: Introduced to replace `Slim/Factory/AppFactory.php`.
- `Slim/Container/CallableResolver.php`: New implementation of the Callable Resolver.
- `Slim/Container/DefaultDefinitions.php`: Default container definitions.
- `Slim/Handlers/ExceptionHandler.php`: New Exception Handler for better error handling.
Expand Down Expand Up @@ -115,7 +113,6 @@ New files for routing, middleware, and factories, including:

- `Slim/CallableResolver.php`
- `Slim/Handlers/ErrorHandler.php`
- `Slim/Factory/AppFactory.php` and related `Psr17` factories.
- `Slim/Interfaces/AdvancedCallableResolverInterface.php`
- `Slim/Interfaces/RouteCollectorInterface.php`,
- `RouteCollectorProxyInterface.php`,
Expand Down
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,15 @@ Then create file `public/index.php`.

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Builder\AppBuilder;
use Slim\Factory\AppFactory;
use Slim\Middleware\EndpointMiddleware;
use Slim\Middleware\ExceptionHandlingMiddleware;
use Slim\Middleware\RoutingMiddleware;

require __DIR__ . '/../vendor/autoload.php';

// Instantiate App using the builder
$builder = new AppBuilder();
$app = $builder->build();
// Instantiate the App
$app = AppFactory::build();

// Add middleware
$app->add(ExceptionHandlingMiddleware::class);
Expand Down
92 changes: 49 additions & 43 deletions Slim/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\Interfaces\EmitterInterface;
use Slim\Interfaces\RouteCollectionInterface;
use Slim\Interfaces\RouterInterface;
use Slim\Interfaces\ServerRequestCreatorInterface;
use Slim\RequestHandler\MiddlewareRequestHandler;
use Slim\Middleware\EndpointMiddleware;
use Slim\Middleware\ErrorExceptionMiddleware;
use Slim\Middleware\HtmlExceptionMiddleware;
use Slim\Middleware\JsonExceptionMiddleware;
use Slim\Middleware\RoutingMiddleware;
use Slim\Routing\Route;
use Slim\Routing\RouteCollectionTrait;
use Slim\Routing\RouteGroup;
use Slim\Routing\Router;

/**
* App
Expand All @@ -31,11 +34,9 @@
* running the application. It provides methods for defining routes, adding middleware, and managing
* the application's lifecycle, including handling HTTP requests and emitting responses.
*
* @template TContainerInterface of (ContainerInterface|null)
*
* @api
*/
class App implements RequestHandlerInterface, RouteCollectionInterface
class App implements RequestHandlerInterface
{
use RouteCollectionTrait;

Expand Down Expand Up @@ -64,7 +65,7 @@ class App implements RequestHandlerInterface, RouteCollectionInterface
/**
* The router instance for handling route definitions and matching.
*/
private Router $router;
private RouterInterface $router;

/**
* The emitter instance for sending the HTTP response to the client.
Expand All @@ -84,14 +85,12 @@ public function __construct(ContainerInterface $container)
$this->container = $container;
$this->serverRequestCreator = $container->get(ServerRequestCreatorInterface::class);
$this->requestHandler = $container->get(RequestHandlerInterface::class);
$this->router = $container->get(Router::class);
$this->router = $container->get(RouterInterface::class);
$this->emitter = $container->get(EmitterInterface::class);
}

/**
* Get the dependency injection container.
*
* @return ContainerInterface The DI container instance
*/
public function getContainer(): ContainerInterface
{
Expand All @@ -101,7 +100,7 @@ public function getContainer(): ContainerInterface
/**
* Define a new route with the specified HTTP methods and URI pattern.
*
* @param array $methods The HTTP methods the route should respond to
* @param array<string> $methods The HTTP methods the route should respond to
* @param string $path The URI pattern for the route
* @param callable|string $handler The route handler callable or controller method
*
Expand All @@ -125,22 +124,9 @@ public function group(string $path, callable $handler): RouteGroup
return $this->router->group($path, $handler);
}

/**
* Get the base path used for routing.
*
* @return string The base path used for routing
*/
public function getBasePath(): string
{
return $this->router->getBasePath();
}

/**
* Set the base path used for routing.
*
* @param string $basePath The base path to use for routing
*
* @return self The current App instance for method chaining
* @param string $basePath
*/
public function setBasePath(string $basePath): self
{
Expand All @@ -149,8 +135,17 @@ public function setBasePath(string $basePath): self
return $this;
}

/**
* Get the base path used for routing.
*/
public function getBasePath(): string
{
return $this->router->getBasePath();
}

/**
* Add a new middleware to the stack.
* @param MiddlewareInterface|callable|string $middleware
*/
public function add(MiddlewareInterface|callable|string $middleware): self
{
Expand All @@ -161,10 +156,7 @@ public function add(MiddlewareInterface|callable|string $middleware): self

/**
* Add a new middleware to the application's middleware stack.
*
* @param MiddlewareInterface $middleware The middleware to add
*
* @return self The current App instance for method chaining
* @param MiddlewareInterface $middleware
*/
public function addMiddleware(MiddlewareInterface $middleware): self
{
Expand All @@ -173,42 +165,56 @@ public function addMiddleware(MiddlewareInterface $middleware): self
return $this;
}

/**
* Add routing middleware.
*
* @return self
*/
public function addRoutingMiddleware(): self
{
return $this
->add(RoutingMiddleware::class)
->add(EndpointMiddleware::class);
}

/**
* Add set of default error handling middleware.
*
* @return self
*/
public function addErrorMiddleware(): self
{
return $this
->add(ErrorExceptionMiddleware::class)
->add(HtmlExceptionMiddleware::class)
->add(JsonExceptionMiddleware::class);
}

/**
* Run the Slim application.
*
* This method traverses the application's middleware stack, processes the incoming HTTP request,
* and emits the resultant HTTP response to the client.
*
* @param ServerRequestInterface|null $request The HTTP request to handle.
* If null, it creates a request from globals.
*
* @return void
* @param ?ServerRequestInterface $request
*/
public function run(?ServerRequestInterface $request = null): void
{
if (!$request) {
$request = $this->serverRequestCreator->createServerRequestFromGlobals();
}

$response = $this->handle($request);

$this->emitter->emit($response);
$this->emitter->emit($this->handle($request));
}

/**
* Handle an incoming HTTP request.
*
* This method processes the request through the application's middleware stack and router,
* returning the resulting HTTP response.
*
* @param ServerRequestInterface $request The HTTP request to handle
*
* @return ResponseInterface The HTTP response
* @param ServerRequestInterface $request
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
$request = $request->withAttribute(MiddlewareRequestHandler::MIDDLEWARE, $this->router->getMiddlewareStack());

return $this->requestHandler->handle($request);
}
}
Loading