PHP Developer for 20 Years
Cisco Systems, Inc., Walt Disney Corporation,
Johnson & Johnson, and many others
routes.php
$ composer global require "laravel/installer"
$ laravel new middleware-demo
$ composer create-project --prefer-dist laravel/laravel middleware-demo-2
app/Http/routes.php
<?php
Route::get('hello-world', {something goes here});
app/Http/routes.php
<?php
Route::get('hello-world', function()
{
return '<h1>Hello, world</h1>';
});
$ php artisan make:controller MyController
app/Http/routes.php
<?php
Route::get('hello-world', 'MyController@hello');
app/Http/Controllers/MyController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
class MyController extends Controller
{
public function hello()
{
return '<h1>Hello, world</h1>';
}
}
app/Http/Controllers/MyController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
class MyController extends Controller
{
public function hello()
{
return view('hello');
}
}
resources/views/hello.blade.php
<h2>Hello, world!</h2>
"Middleware is a terribly nebulous term."
Connects two applications
and passes data between them
Connects two
layers of the application
and passes data between them
Connects two
layers of the application
and passes data between them
public/index.php
<?php
// ...
/** @var Illuminate\Foundation\Http\Kernel $kernel */
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
/** @var Illuminate\Http\Response $response */
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
Kernel.php
<?php
namespace Illuminate\Foundation\Http;
// ...
public function handle($request)
{
try {
$request->enableHttpMethodParameterOverride();
$response = $this->sendRequestThroughRouter($request);
} catch // a couple of catches & other stuff here...
return $response;
}
Kernel.php
<?php
namespace Illuminate\Foundation\Http;
protected function sendRequestThroughRouter($request)
{
$this->app->instance('request', $request);
Facade::clearResolvedInstance('request');
$this->bootstrap();
return (new Pipeline($this->app))
->send($request)
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
->then($this->dispatchToRouter());
}
Pipeline.php
<?php
namespace Illuminate\Pipeline;
public function send($passable)
{
// this is the request
$this->passable = $passable;
return $this;
}
public function through($pipes)
{
// these are the middleware
$this->pipes = is_array($pipes) ? $pipes : func_get_args();
return $this;
}
Pipeline.php
<?php
namespace Illuminate\Pipeline;
public function then(Closure $destination)
{
$firstSlice = $this->getInitialSlice($destination);
$pipes = array_reverse($this->pipes);
return call_user_func(
array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable
);
}
Affects Every Single Request
Registered in
app/Http/Kernel.php
in the $middleware array
app/Http/Kernel.php
<?php
// ...
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
];
A single middleware
that can be assigned to Routes
Registered in
app/Http/Kernel.php
in the
$routeMiddleware array.
app/Http/Kernel.php
<?php
// ...
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
A group of middleware
that can be assigned to Routes
Registered in
app/Http/Kernel.php
in the
$middlewareGroups array.
For example, Laravel ships
with the 'web' and 'api' groups
app/Http/Kernel.php
<?php
// ...
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
<?php // app/Http/Kernel.php
protected $middleware = [
\App\Http\Middleware\MyGlobalMiddleware::class,
];
protected $middlewareGroups = [
'my-group' => [
\App\Http\Middleware\MySecondMiddleware::class,
\App\Http\Middleware\MyThirdMiddleware::class,
],
];
protected $routeMiddleware = [
'my-fourth-middleware' => '\App\Http\Middleware\MyFourthMiddleware::class,
];
<?php
// app/Http/routes.php
Route::get('my-route', [
'middleware' => ['my-group', 'my-fourth-middleware'],
'uses' => 'MyControllerd@hello'
]);
On your route, you simply specify
the name of the middleware
Route::get('hello-world', ['middleware' => 'my-middleware', function()
{
return '<h1>Hello, world</h1>';
}]);
Or an array of middlewares
Route::get('hello-world', [
'middleware' => ['my-first-middleware', 'my-second-middleware'],
function()
{
return '<h1>Hello, world</h1>';
}
]);
Or the name of a middleware group
Route::get('hello-world', ['middleware' => 'my-group', function()
{
return '<h1>Hello, world</h1>';
}]);
public function handle($request, Closure $next)
{
// modify the $request here...
return $next($request);
}
public function handle($request, Closure $next)
{
$response = $next($request);
// modify the $response here...
return $response;
}
$next($request)
happens
Route::get('hello-world', function()
{
return '<h1>Hello, world</h1>';
});
$ php artisan make:middleware MyMiddleware
This creates a new Middleware file here:app/Http/Middleware/MyMiddleware.php
Remember, There Are
2 Ways To Do This
Let's use Route Middleware
app/Http/Kernel.php
<?php
// ...
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
// our new middleware here
'my-middleware' => \App\Http\Middleware\MyMiddleware::class,
];
Route::get('hello-world', ['middleware' => 'my-middleware', function()
{
return '<h1>Hello, world</h1>';
}]);
app/Http/Middleware/MyMiddleware.php
<?php
namespace App\Http\Middleware;
use Closure;
class MyMiddleware
{
public function handle($request, Closure $next)
{
$response = $next($request);
// modify the $response here...
return $next($request);
}
}
app/Http/Middleware/MyMiddleware.php
<?php
namespace App\Http\Middleware;
use Closure;
class MyMiddleware
{
public function handle($request, Closure $next)
{
$response = $next($request);
$content = $response->getOriginalContent();
$response->setContent(str_replace('world', 'everyone', $content));
return $response;
}
}
please wait while we try to insert your message ..... message
inserted.
please wait while we try to insert your message ..
*** 60 second pause *** ...
deadlock, transaction aborted.
Please hit Reload in five or ten minutes.
ns_write "please wait while we try to insert your message ..."
ns_sleep 60
ns_write "... deadlock, transaction aborted. Please hit Reload
in five or ten minutes."
Route::get('forum/create', ['uses' => 'MyController@forumCreate']);
Route::post('forum', [
'uses' => 'MyController@forumStore'
]);
app/Http/Controllers/MyController.php
<?php
// ...
public function forumCreate()
{
// shows the forum post form
return view('forum.create');
}
public function forumStore(ForumPostRequest $request)
{
// inserts a post into the forum
Forum\Post::create( ... );
}
$ php artisan make:middleware JerkCheck
This creates a new Middleware file here:
app/Http/Middleware/JerkCheck.php
app/Http/Kernel.php
<?php
// ...
protected $routeMiddleware = [
// ...
'my-middleware' => \App\Http\Middleware\MyMiddleware::class,
// our new jerk check middleware here
'jerk-check' => \App\Http\Middleware\JerkCheck::class,
];
Route::get('forum/create', ['uses' => 'MyController@forumCreate']);
Route::post('forum', [
'middleware' => 'jerk-check',
'uses' => 'MyController@forumStore'
]);
app/Http/Middleware/JerkCheck.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
class JerkCheck
{
public function handle($request, Closure $next)
{
// code goes here
}
}
app/Http/Middleware/JerkCheck.php
public function handle($request, Closure $next)
{
// get the user
$user = Auth::user();
// see if they're a jerk
if ($user->isAJerk()) {
// they're a jerk. serve them a pretend broken page
$view = view('forum.jerk');
return new Response($view->render());
}
// not a jerk; keep going
return $next($request);
}
resources/views/forum/jerk.blade.php
<h1>Trying to insert your message...</h1>
<img id="loading" src="/img/loading.gif">
<h2 id="sorry" style="display: none;">Sorry, it failed... :( We tried.</h2>
<script type="text/javascript">
setTimeout(function(){
var loading = document.getElementById('loading');
var sorry = document.getElementById('sorry');
loading.style.display = 'none';
sorry.style.display = 'block';
}, 3000);
</script>
Route::get('hello-world', ['middleware' => 'my-middleware', function()
{
return '<h1>Hello, world</h1>';
}]);
app/Http/Middleware/MyMiddleware.php
<?php
namespace App\Http\Middleware;
use Closure;
class MyMiddleware
{
public function handle($request, Closure $next)
{
$response = $next($request);
$content = $response->getOriginalContent();
$response->setContent(str_replace('world', 'everyone', $content));
return $response;
}
}
tests/ExampleTest.php
<?php
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
public function testHello()
{
// this will pass, because the middleware changes "world" to "everyone"
$this->visit('hello-world')
->see('Hello, everyone');
}
}
tests/ExampleTest.php
<?php
// ... other use statements
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase {
use WithoutMiddleware;
public function testHello()
{
// this will fail, because with the middleware disabled,
// "world" is not changed to "everyone"
$this->visit('hello-world')
->see('Hello, everyone');
}
}