├── .gitignore ├── config └── psr15middleware.php ├── phpunit.xml ├── CONTRIBUTING.md ├── LICENSE.md ├── composer.json ├── src ├── Handler.php ├── Psr15Middleware.php ├── exampleMiddleware.php ├── Psr15MiddlewareServiceProvider.php └── Dispatcher.php ├── tests └── Psr15MiddlewareTest.php └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | .idea/ 3 | .DS_Store 4 | composer.lock 5 | .vscode/ -------------------------------------------------------------------------------- /config/psr15middleware.php: -------------------------------------------------------------------------------- 1 | [ 4 | [\Jshannon63\Psr15Middleware\exampleMiddleware::class, 'prepend', 'after'], 5 | ], 6 | 'groups' => [ 7 | 'web' => [ 8 | ], 9 | 'api' => [ 10 | ], 11 | 'custom' => [ 12 | ], 13 | ], 14 | 'aliases' => [ 15 | ] 16 | ]; 17 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribute to Psr7Middleware! 2 | 3 | Thanks for your interest in contributing! I always appreciate the help and will be certain to give credit when merged. Contributions are only accepted via pull requests on [Github](https://github.com/jshannon63/laravel-baton). 4 | 5 | 6 | ## Always Open an Issue 7 | 8 | If you have an idea for a feature, you can potentially save yourself if time you first open an issue before writing code. I promise to review your ideas quickly to determine if it is appropriate for the community as a whole. 9 | 10 | ## Please Follow Some Basic Standards 11 | 12 | - Please follow the **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** 13 | - Update the `README.md` whenever there are any changes in package behaviour. 14 | - Clearly name your commits, and be sure to squash before submitting. -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) Jim Shannon 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jshannon63/laravel-psr15-middleware", 3 | "description": "Allows the Use of PSR-15 Compliant Middleware in Laravel", 4 | "keywords": ["middleware", "PSR-15", "Laravel"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Jim Shannon", 9 | "email": "jim@hltky.com" 10 | } 11 | ], 12 | "require": { 13 | "php": "^7.3", 14 | "symfony/psr-http-message-bridge": "^2", 15 | "psr/http-server-middleware": "^1.0", 16 | "nyholm/psr7": "^1.3" 17 | }, 18 | "require-dev": { 19 | "illuminate/http": "^5.5|^6|^7", 20 | "illuminate/container": "^5.5|^6|^7", 21 | "illuminate/config": "^5.5|^6|^7", 22 | "phpunit/phpunit": "^9.0" 23 | }, 24 | "autoload": { 25 | "psr-4": { 26 | "Jshannon63\\Psr15Middleware\\": "src/" 27 | } 28 | }, 29 | "autoload-dev": { 30 | "psr-4": { 31 | "Tests\\": "tests/" 32 | } 33 | }, 34 | "extra": { 35 | "laravel": { 36 | "providers": [ 37 | "Jshannon63\\Psr15Middleware\\Psr15MiddlewareServiceProvider" 38 | ] 39 | } 40 | }, 41 | "minimum-stability": "dev", 42 | "prefer-stable": true 43 | } 44 | -------------------------------------------------------------------------------- /src/Handler.php: -------------------------------------------------------------------------------- 1 | response = (new PsrHttpFactory( 23 | $psr17Factory, 24 | $psr17Factory, 25 | $psr17Factory, 26 | $psr17Factory 27 | ))->createResponse($response); 28 | } 29 | 30 | public function handle(ServerRequestInterface $request): ResponseInterface 31 | { 32 | $this->request = $request; 33 | return $this->response; 34 | } 35 | 36 | public function getRequest() 37 | { 38 | return $this->request; 39 | } 40 | 41 | public function setResponse($response) 42 | { 43 | $this->response = $response; 44 | } 45 | 46 | public function getResponse() 47 | { 48 | return $this->response; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Psr15Middleware.php: -------------------------------------------------------------------------------- 1 | middleware = $middleware; 17 | $this->mode = $mode; 18 | } 19 | 20 | /** 21 | * Laravel compatible middleware handle method 22 | * 23 | * @param [type] $request 24 | * @param Closure $next 25 | * @param [type] ...$parameters 26 | * @return void 27 | */ 28 | public function handle($request, Closure $next, ...$parameters) 29 | { 30 | $dispatcher = new Dispatcher(); 31 | 32 | if ($this->mode === 'before') { 33 | // we must create a mock response object since PSR-15 requires it 34 | // but it is not truly available at this point in the request cycle. 35 | // so we will ignore it when returned. 36 | $messages = $dispatcher($request, (new \Symfony\Component\HttpFoundation\Response), $this->middleware, ...$parameters); 37 | return $next($messages['request']); 38 | } 39 | 40 | if ($this->mode === 'after') { 41 | $response = $next($request); 42 | $messages = $dispatcher($request, $response, $this->middleware, ...$parameters); 43 | return $messages['response']; 44 | } 45 | 46 | return $next($request); 47 | } 48 | 49 | /** 50 | * for terminable middlewares 51 | * 52 | * @param [type] $request 53 | * @param [type] $response 54 | * @param [type] ...$parameters 55 | * @return void 56 | */ 57 | public function terminate($request, $response, ...$parameters): void 58 | { 59 | if ($this->mode === 'terminable') { 60 | (new Dispatcher())($request, $response, $this->middleware, ...$parameters); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/exampleMiddleware.php: -------------------------------------------------------------------------------- 1 | message = $parm1.' '.$parm2; 19 | } 20 | 21 | /** 22 | * PSR-15 compatible middleware process method 23 | * 24 | * @param ServerRequestInterface $request 25 | * @param RequestHandlerInterface $handler 26 | * @return ResponseInterface 27 | */ 28 | public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface 29 | { 30 | // process any request manipulations here before the handler. 31 | // remember that only "before" middlewares have access to 32 | // the request object before the application acts on it. 33 | // the handler will ensure the next middleware will see any 34 | // changes to the request object. 35 | 36 | $response = $handler->handle($request); 37 | 38 | // response actions go here after the handler provides 39 | // you with a response object. keep in mind that any 40 | // "before" middlewares will only have access to a mock 41 | // response object and any updates will be lost. 42 | 43 | $response->getBody()->rewind(); 44 | $body = $response->getBody(); 45 | $contents = $body->getContents(); 46 | $contents = str_replace( 47 | '', 48 | "\n\t

".$this->message.'

', 49 | $contents 50 | ); 51 | $body->rewind(); 52 | $body->write($contents); 53 | 54 | // return the reponse object here. 55 | // "terminable" middlewares run after the response has 56 | // been sent back to the browser. they will receive the 57 | // request object passed into this method and will get 58 | // a copy of the response object from the handler. 59 | 60 | return $response->withBody($body); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Psr15MiddlewareServiceProvider.php: -------------------------------------------------------------------------------- 1 | publish(); 15 | 16 | $config = $this->app['config']; 17 | 18 | if ($config->get('psr15middleware')) { 19 | foreach ($config->get('psr15middleware.middleware') ?? [] as $key => $middleware) { 20 | $this->app->singleton('psr15.middleware.'.$key, static function () use ($middleware) { 21 | return new Psr15Middleware($middleware[0], $middleware[2]); 22 | }); 23 | if ($middleware[1] === 'prepend') { 24 | $this->app[Kernel::class]->prependMiddleware('psr15.middleware.'.$key); 25 | } else { 26 | $this->app[Kernel::class]->pushMiddleware('psr15.middleware.'.$key); 27 | } 28 | } 29 | foreach ($config->get('psr15middleware.groups') ?? [] as $groupKey => $group) { 30 | foreach ($config->get('psr15middleware.groups.'.$groupKey) as $key => $middleware) { 31 | $this->app->bind('psr15.group.'.strtolower($groupKey).'.'.$key, static function () use ($middleware): Psr15Middleware { 32 | return new Psr15Middleware($middleware[0], $middleware[2]); 33 | }); 34 | if ($middleware[1] === 'prepend') { 35 | $this->app['router']->prependMiddlewareToGroup($groupKey, 'psr15.group.'.strtolower($groupKey).'.'.$key); 36 | } else { 37 | $this->app['router']->pushMiddlewareToGroup($groupKey, 'psr15.group.'.strtolower($groupKey).'.'.$key); 38 | } 39 | } 40 | } 41 | foreach ($config->get('psr15middleware.aliases') ?? [] as $key => $middleware) { 42 | $this->app->bind('psr15.alias.'.strtolower($key), static function () use ($middleware): Psr15Middleware { 43 | return new Psr15Middleware($middleware[0], $middleware[2]); 44 | }); 45 | $this->app['router']->aliasMiddleware($key, 'psr15.alias.'.strtolower($key)); 46 | } 47 | } 48 | } 49 | 50 | public function register(): void 51 | { 52 | } 53 | 54 | private function publish(): void 55 | { 56 | $this->publishes([ 57 | __DIR__ . '/../config/psr15middleware.php' => config_path('psr15middleware.php'), 58 | ]); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Dispatcher.php: -------------------------------------------------------------------------------- 1 | createRequest($request); 24 | 25 | $requestHandler = new Handler($response); 26 | 27 | if (is_callable($middleware)) { 28 | $psr7response = $middleware()->process($psr7request, $requestHandler); 29 | } elseif (is_object($middleware)) { 30 | $psr7response = $middleware->process($psr7request, $requestHandler); 31 | } else { 32 | $psr7response = (new $middleware(...$parameters))->process($psr7request, $requestHandler); 33 | } 34 | 35 | return [ 36 | 'request' => $this->convertRequest($requestHandler->getRequest(), $request), 37 | 'response' => $this->convertResponse($psr7response, $response) 38 | ]; 39 | } 40 | 41 | private function convertRequest($psr7request, $original) 42 | { 43 | $foundationRequest = (new HttpFoundationFactory())->createRequest($psr7request); 44 | 45 | $original->query = clone $foundationRequest->query; 46 | $original->request = clone $foundationRequest->request; 47 | $original->attributes = clone $foundationRequest->attributes; 48 | $original->cookies = clone $foundationRequest->cookies; 49 | $original->files = clone $foundationRequest->files; 50 | $original->server = clone $foundationRequest->server; 51 | $original->headers = clone $foundationRequest->headers; 52 | 53 | return $original; 54 | } 55 | 56 | private function convertResponse($psr7response, $original) 57 | { 58 | $foundation_response = (new HttpFoundationFactory())->createResponse($psr7response); 59 | 60 | foreach ($foundation_response->headers as $key => $value) { 61 | $original->headers->set($key, $value); 62 | } 63 | 64 | $original->setContent($foundation_response->getContent()); 65 | $original->setProtocolVersion($foundation_response->getProtocolVersion()); 66 | $original->setStatusCode($foundation_response->getStatusCode()); 67 | $original->setCharset($foundation_response->getCharset() ?: ''); 68 | 69 | return $original; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tests/Psr15MiddlewareTest.php: -------------------------------------------------------------------------------- 1 | handle($request); 26 | 27 | $response->getBody()->rewind(); 28 | $body = $response->getBody(); 29 | $contents = $body->getContents(); 30 | $contents .= '

Test-1

'; 31 | $body->rewind(); 32 | $body->write($contents); 33 | 34 | return $response->withBody($body); 35 | } 36 | } 37 | 38 | class exampleMiddleware2 implements MiddlewareInterface 39 | { 40 | public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface 41 | { 42 | $response = $handler->handle($request); 43 | 44 | $response->getBody()->rewind(); 45 | $body = $response->getBody(); 46 | $contents = $body->getContents(); 47 | $contents .= '

Test-2

'; 48 | $body->rewind(); 49 | $body->write($contents); 50 | 51 | return $response->withBody($body); 52 | } 53 | } 54 | 55 | class exampleMiddleware3 implements MiddlewareInterface 56 | { 57 | public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface 58 | { 59 | $response = $handler->handle($request); 60 | 61 | $response->getBody()->rewind(); 62 | $body = $response->getBody(); 63 | $contents = $body->getContents(); 64 | $contents .= '

Test-3

'; 65 | $body->rewind(); 66 | $body->write($contents); 67 | 68 | return $response->withBody($body); 69 | } 70 | } 71 | 72 | class exampleMiddleware4 implements MiddlewareInterface 73 | { 74 | public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface 75 | { 76 | $request->withHeader('X-PHPUNIT-TEST', 'PASSED'); 77 | 78 | $response = $handler->handle($request); 79 | 80 | return $response; 81 | } 82 | } 83 | 84 | class Psr15MiddlewareTest extends TestCase 85 | { 86 | protected $middleware; 87 | protected $container; 88 | protected $config; 89 | 90 | public function setUp(): void 91 | { 92 | parent::setUp(); 93 | $this->middleware = [ 94 | 'psr15middleware.middleware' => [ 95 | [exampleMiddleware1::class, 'append', 'after'], 96 | [function () { 97 | return new exampleMiddleware2(); 98 | }, 'append', 'after'], 99 | [(new exampleMiddleware3()), 'append', 'after'], 100 | [(new exampleMiddleware4()), 'append', 'after'] 101 | ] 102 | ]; 103 | $this->container = new Container; 104 | $this->config = new Repository($this->middleware); 105 | } 106 | 107 | public function test_middleware_stack(): void 108 | { 109 | $request = Request::create('http://localhost:8888/test/1', 'GET', [], [], [], [], null); 110 | $response = new Response('Original Content:', Response::HTTP_OK, ['content-type' => 'text/html']); 111 | 112 | foreach ($this->config->get('psr15middleware.middleware') as $middleware) { 113 | $psr15middleware = new Psr15Middleware($middleware[0], $middleware[2]); 114 | $response = $psr15middleware->handle($request, static function () use ($response) { 115 | return $response; 116 | }); 117 | } 118 | 119 | $this->assertStringContainsString('Original Content:', $response->getContent()); 120 | $this->assertStringContainsString('Test-1', $response->getContent()); 121 | $this->assertStringContainsString('Test-2', $response->getContent()); 122 | $this->assertStringContainsString('Test-3', $response->getContent()); 123 | $this->assertStringContainsString('Original Content:

Test-1

Test-2

Test-3

', $response->getContent()); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Use PSR-15 compliant middleware in Laravel 2 | 3 | #### What it does and why: 4 | PHP-FIG standards related to the HTTP Message Interface (PSR-7) have been in place for some time now. The standard for HTTP Handlers (PSR-15) is approved as of Jan 22, 2018. 5 | 6 | Laravel already provides a pathway for obtaining PSR-7 request objects from route closures or controller methods. Laravel also allows returning PSR-7 response objects from a route or controller. However, having a new PSR related to middleware doesn't necessarily mean that Laravel needs to implement a compliant middleware stack... nor should it. Using a bridge (like this library) is a perfectly acceptable way to adopt PSR-15 capabilities within Laravel without completely changing the underlying framework. 7 | 8 | Middleware is a simple thing and for the most part, middleware should be thin and are easily written. In fact, many are nothing more than single line libraries that could be just as easily created as imported. However, there is some value in re-usable web components that can be shared between applications/frameworks. Many PSR-15 middleware components already exist in the PHP community, some of which can provide some value. Having them available to use in Laravel could be a benefit. 9 | 10 | For what benefit may be gained out of re-usable middleware logic, however small... this library was created. 11 | 12 | The laravel-psr15-middleware library (a.k.a. Psr15Middleware) is a Laravel compatible middleware that creates a bridge between PSR-7/PSR-15 interfaces and Laravel's middleware stack and Foundation HTTP message objects. 13 | 14 | Once installed, you will be able to run compliant PSR-15 middleware in Laravel using this package's integration in the existing Laravel middleware stack. 15 | 16 | #### PSR implementation reasoning. TL;DR 17 | This library fully implements the PSR-7 (psr/http-message) message object interfaces. The interface is realized through Zend Diactoros concrete implementations of both the Request and Response objects. It also fully implements the newly approved PSR-15 (psr/http-server-middleware) middleware and (psr/http-server-handler) request handler interfaces. This library uses the Symfony PSR-7 Bridge to make the conversions in both directions between Foundation and PSR-7 message objects. 18 | 19 | ## Installation 20 | Within your Laravel project folder, install this package using composer. If you are using Laravel 5.5 or later, service provider registration will happen automatically. 21 | ```bash 22 | composer require jshannon63/laravel-psr15-middleware 23 | ``` 24 | Then use artisan to publish the package's configuration assets 25 | ```bash 26 | php artisan vendor:publish 27 | 28 | Which provider or tag's files would you like to publish?: 29 | [0] Publish files from all providers and tags listed below 30 | [1] Provider: Fideloper\Proxy\TrustedProxyServiceProvider 31 | [2] Provider: Illuminate\Mail\MailServiceProvider 32 | [3] Provider: Illuminate\Notifications\NotificationServiceProvider 33 | [4] Provider: Illuminate\Pagination\PaginationServiceProvider 34 | [5] Provider: Jshannon63\Psr15Middleware\Psr15MiddlewareServiceProvider 35 | [6] Tag: laravel-mail 36 | [7] Tag: laravel-notifications 37 | [8] Tag: laravel-pagination 38 | > 39 | 40 | choose the Psr15MiddlewareServiceProvider 41 | ``` 42 | That's it! Now you can configure and run your PSR-15 middleware. The default configuration in `/config/psr15middleware.php` comes with the exampleMiddleware enabled for demonstration purposes. You will need to disable all of the examples and add your own middleware classes as described below. 43 | ## Usage 44 | 45 | #### Add your PSR-15 compliant middlewares to the /config/psr15middleware.php configuration file. 46 | 1. It is NOT necessary to declare PSR-15 middleware in the `app/Http/Middleware/Kernel.php` file as is normally done. Psr15Middleware will automatically register itself and its middlewares by pushing them onto the Laravel middleware stack. 47 | 2. Config entries are arrays and can can contain classnames, callables or objects as shown in the example below. Each entry has two additional parameters which follow the middleware declaration: 48 | * "prepend" or "append" will determine if your midleware will be placed at 49 | the head or tail of the middleware stack. 50 | * "before", "after" and "terminable" specify the type of middleware. Before middlewares run before the application acts on the request. After middlewares run after the request has been acted on by the application, but before the response has been sent to the browser. Terminable middlewares run after the browser has received the response and are generally used for housekeeping task which require access to the request and/or response objects. 51 | 3. Additional sections for aliases ($routeMiddleware) and groups ($middlewareGroups) which closely adhere to the special route middleware groups within the `app\Http\Middleware\Kernel.php` file. 52 | 4. You can add new groups if you like (i.e., custom as shown). 53 | 5. Constructor arguments can be passed for middlewares declared as callables or objects within the configuration. All PSR-15 middleware constructors will be treated as variadic functions and therefore will be able to accept any number of arguments to their constructor. Note: These constructor arguments can also be passed as Laravel middleware route parameters. See the Laravel documentation for more on this feature. 54 | 55 | 56 | ```php 57 | [ 61 | [\Jshannon63\Psr15Middleware\exampleMiddleware::class, 'append', 'before'], 62 | [ 63 | function() { 64 | return new \Jshannon63\Psr15Middleware\exampleMiddleware('Lovin', 'Laravel'); 65 | }, 66 | 'prepend', 67 | 'after' 68 | ], 69 | [ 70 | (new \Jshannon63\Psr15Middleware\exampleMiddleware('PSR-15','Rocks')), 71 | 'append', 72 | 'after' 73 | ] 74 | ], 75 | 'groups' => [ 76 | 'web' => [ 77 | 78 | ], 79 | 'api' => [ 80 | 81 | ], 82 | 'custom' => [ 83 | 84 | ], 85 | ], 86 | 'aliases' => [ 87 | 'psr15' => [ 88 | (new \Jshannon63\Psr15Middleware\exampleMiddleware('Aliased','Middleware')), 89 | 'prepend', 90 | 'after' 91 | ] 92 | ] 93 | ]; 94 | 95 | ``` 96 | ##### Your PSR-15 compatible middleware must have the following signature: 97 | ```php 98 | 99 | // your namespace here 100 | 101 | use Psr\Http\Server\RequestHandlerInterface; 102 | use Psr\Http\Server\MiddlewareInterface; 103 | use Psr\Http\Message\ServerRequestInterface; 104 | use Psr\Http\Message\ResponseInterface; 105 | 106 | class exampleMiddleware implements MiddlewareInterface 107 | { 108 | // Your constructor will be treated as a variadic function 109 | // and parameters may be passed either as a middleware route 110 | // parameter or as defined in the /config/psr15middleware.php 111 | // config file. You can read more about middleware parameters 112 | // in the Laravel documentation. 113 | 114 | public function __construct() 115 | { 116 | // if needed 117 | } 118 | 119 | public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface 120 | { 121 | // process any request manipulations here before the handler. 122 | // remember that only "before" middlewares have access to 123 | // the request object before the application acts on it. 124 | // the handler will ensure the next middleware will see any 125 | // changes to the request object. 126 | 127 | $response = $handler->handle($request); 128 | 129 | // response actions go here after the handler provides 130 | // you with a response object. keep in mind that any 131 | // "before" middlewares will only have access to a mock 132 | // response object and any updates will be lost. 133 | 134 | // "terminable" middlewares are run after the response has 135 | // been sent back to the browser. they will receive the 136 | // request object passed into this method and will get 137 | // a copy of the response object from the handler. 138 | 139 | // return the reponse object here. 140 | 141 | return $response; 142 | } 143 | } 144 | 145 | ``` 146 | 147 | ## Execution Flow 148 | 149 | All PSR-15 middleware is encapsulated and managed entirely by the PSR15Middleware subsystem. On boot, Psr15Middleware will bind a wrapper object for each PSR-15 middleware to make it appear native to Laravel. Then the objects will be placed into the Laravel middleware stack according to your configuration parameters. The middlewares themselves will only be instanitated as needed. Laravel will execute the middelwares according to the system priorites and as modified during registration of PSR-15 middlewares by Psr15Middleware. 150 | 151 | Also, keep in mind, that since Psr15Middlware operates on PSR-7 message objects, PSR-15 middlewares will not have access to Laravel/Symfony specific properties and methods of the Foundation message objects. 152 | 153 | ## Middleware Sources 154 | 155 | For some PSR-15 middleware to use, take a look at [middlewares/psr15middlewares](https://github.com/middlewares/psr15-middlewares). 156 | 157 | ## Contributing 158 | 159 | If you would like to contribute refer to CONTRIBUTING.md 160 | --------------------------------------------------------------------------------