Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Routing Laravel

Routing Laravel

Let's find how Route:: works and where we can reuse it for our own technical challenges.

Talk was given at Laracon Online 2021, march 17th.

Bobby Bouwmann

March 17, 2021
Tweet

More Decks by Bobby Bouwmann

Other Decks in Programming

Transcript

  1. Routing Laravel
    Photo by Franco Antonio Giovanella on Unsplash

    View Slide

  2. View Slide

  3. Laravel Fashionista
    • Laravel Evangelist @ Enrise

    • Top Contributor @ Laracasts

    • Writer of Laravel Secrets

    • Partner @ PingPing.io
    @bobbybouwmann

    View Slide

  4. Enrise
    We are the new standard in organising
    No management, no board,
    but professionals who take control

    View Slide

  5. Better order that pizza now!
    • Laravel basic routing

    • Routing cycle

    • Route model binding explained

    • Another use case for the router

    • Best practices
    Today’s menu
    Photo by Natasha Filippovskaya from Pexels

    View Slide

  6. p

    use Illuminate\Support\Facades\Route
    ;

    /
    *

    |-------------------------------------------------------------------------
    -

    | Web Route
    s

    |-------------------------------------------------------------------------
    -

    |

    | Here is where you can register web routes for your application. Thes
    e

    | routes are loaded by the RouteServiceProvider within a group whic
    h

    | contains the "web" middleware group. Now create something great
    !

    |

    *
    /

    Route::get('/', function ()
    {

    return view('welcome')
    ;

    });

    View Slide

  7. // Basic Controller


    Route::get('/users/{user}', [UsersController::class, ‘show']
    )

    ->name('users.show')
    ;

    // Invokable Controlle
    r

    Route::get('/users/{user}', EditUser::class
    )

    ->name(‘users.edit')
    ;

    // Callbac
    k

    Route::get('/', function ()
    {

    return view('welcome')
    ;

    });

    View Slide

  8. Route::get('posts', [PostsController::class, ‘index'])->name('posts.index')
    ;

    Route::get('posts/create', [PostsController::class, ‘create'])->name('posts.create')
    ;

    Route::post('posts', [PostsController::class, ‘store'])->name('posts.store')
    ;

    Route::get('posts/{post}', [PostsController::class, ‘show'])->name('posts.show')
    ;

    Route::get('posts/{post}/edit', [PostsController::class, ‘edit'])->name('posts.edit')
    ;

    Route::put('posts/{post}', [PostsController::class, ‘update’])->name('posts.update')
    ;

    Route::patch('posts/{post}', [PostsController::class, ‘update'])->name('posts.update')
    ;

    Route::delete('posts/{post}', [PostsController::class, ‘destroy'])->name('posts.destroy');

    View Slide

  9. $ php artisan route:list


    +-----------+--------------------+----------------+-----------------------------------------------+------------+


    | Method | URI | Name | Action | Middleware |


    +-----------+--------------------+----------------+-----------------------------------------------+------------+


    | GET|HEAD | posts | posts.index | App\Http\Controllers\PostsController@index | web |


    | POST | posts | posts.store | App\Http\Controllers\PostsController@store | web |


    | GET|HEAD | posts/create | posts.create | App\Http\Controllers\PostsController@create | web |


    | GET|HEAD | posts/{post} | posts.show | App\Http\Controllers\PostsController@show | web |


    | PUT|PATCH | posts/{post} | posts.update | App\Http\Controllers\PostsController@update | web |


    | DELETE | posts/{post} | posts.destroy | App\Http\Controllers\PostsController@destroy | web |


    | GET|HEAD | posts/{post}/edit | posts.edit | App\Http\Controllers\PostsController@edit | web |


    +-----------+--------------------+----------------+-----------------------------------------------+------------+
    $ php artisan route:list --compact


    +-----------+--------------------+-----------------------------------------------+


    | Method | URI | Action |


    +-----------+--------------------+-----------------------------------------------+


    | GET|HEAD | posts | App\Http\Controllers\PostsController@index |


    | POST | posts | App\Http\Controllers\PostsController@store |


    | GET|HEAD | posts/create | App\Http\Controllers\PostsController@create |


    | GET|HEAD | posts/{post} | App\Http\Controllers\PostsController@show |


    | PUT|PATCH | posts/{post} | App\Http\Controllers\PostsController@update |


    | DELETE | posts/{post} | App\Http\Controllers\PostsController@destroy |


    | GET|HEAD | posts/{post}/edit | App\Http\Controllers\PostsController@edit |


    +-----------+--------------------+-----------------------------------------------+

    View Slide

  10. Route::resource('posts', PostsController::class);
    $ php artisan route:list --compact


    +-----------+--------------------+-----------------------------------------------+


    | Method | URI | Action |


    +-----------+--------------------+-----------------------------------------------+


    | GET|HEAD | / | Closure |


    | GET|HEAD | posts | App\Http\Controllers\PostsController@index |


    | POST | posts | App\Http\Controllers\PostsController@store |


    | GET|HEAD | posts/create | App\Http\Controllers\PostsController@create |


    | GET|HEAD | posts/{post} | App\Http\Controllers\PostsController@show |


    | PUT|PATCH | posts/{post} | App\Http\Controllers\PostsController@update |


    | DELETE | posts/{post} | App\Http\Controllers\PostsController@destroy |


    | GET|HEAD | posts/{post}/edit | App\Http\Controllers\PostsController@edit |


    +-----------+--------------------+-----------------------------------------------+

    View Slide

  11. Route::resource('posts', PostsController::class)
    ;

    Route::resource('posts', PostsController::class)->except(['index'])
    ;

    Route::resource('posts', PostsController::class)->only(['index', 'create', 'show'])
    ;

    Route::get('posts/{post}/publish', [PostsController::class, ‘publish']
    )

    ->name(‘posts.publish')
    ;

    View Slide

  12. Route::resource('posts', PostsController::class)->middleware(‘auth')->names('blog');
    Route::resource('posts', PostsController::class)->name('index', 'blog');
    $ php artisan route:list


    +-----------+--------------------+----------------+-----------------------------------------------+------------+


    | Method | URI | Name | Action | Middleware |


    +-----------+--------------------+----------------+-----------------------------------------------+------------+


    | GET|HEAD | posts | blog.index | App\Http\Controllers\PostsController@index | web, auth |


    | POST | posts | blog.store | App\Http\Controllers\PostsController@store | web, auth |


    | GET|HEAD | posts/create | blog.create | App\Http\Controllers\PostsController@create | web, auth |


    | GET|HEAD | posts/{post} | blog.show | App\Http\Controllers\PostsController@show | web, auth |


    | PUT|PATCH | posts/{post} | blog.update | App\Http\Controllers\PostsController@update | web, auth |
    +-----------+--------------------+----------------+-----------------------------------------------+------------+
    $ php artisan route:list


    +-----------+--------------------+----------------+-----------------------------------------------+------------+


    | Method | URI | Name | Action | Middleware |


    +-----------+--------------------+----------------+-----------------------------------------------+------------+


    | GET|HEAD | posts | blog | App\Http\Controllers\PostsController@index | web |


    | POST | posts | posts.store | App\Http\Controllers\PostsController@store | web |


    | GET|HEAD | posts/create | posts.create | App\Http\Controllers\PostsController@create | web |


    | GET|HEAD | posts/{post} | posts.show | App\Http\Controllers\PostsController@show | web |


    | PUT|PATCH | posts/{post} | posts.update | App\Http\Controllers\PostsController@update | web |
    +-----------+--------------------+----------------+-----------------------------------------------+------------+

    View Slide

  13. Route::name('posts.index'
    )

    ->prefix('posts'
    )

    ->middleware('auth'
    )

    ->domain('portal.example.com'
    )

    ->get('list', [PostsController::class, 'index'])
    ;

    Route::name('posts.update'
    )

    ->prefix('posts'
    )

    ->middleware('auth'
    )

    ->domain('portal.example.com'
    )

    ->patch('{post}', [PostsController::class, 'update']);
    $ php artisan route:list


    +--------------------+----------+-------------+--------------+---------------------------------------------+------------+


    | Domain | Method | URI | Name | Action | Middleware |


    +--------------------+----------+-------------+--------------+---------------------------------------------+------------+


    | portal.example.com | GET|HEAD | posts/list | posts.index | App\Http\Controllers\PostsController@index | web |


    | | | | | | auth |


    | portal.example.com | PATCH | posts/{post}| posts.update | App\Http\Controllers\PostsController@update | web |


    | | | | | | auth |


    +--------------------+----------+-------------+--------------+---------------------------------------------+------------+

    View Slide

  14. Route::name('posts.'
    )

    ->prefix('posts'
    )

    ->middleware('auth'
    )

    ->domain('{vendor}.example.com'
    )

    ->group(function ()
    {

    Route::get('list', [PostsController::class, 'index'])->name('list')
    ;

    Route::get('public', [PostsController::class, 'public'])->name('public')
    ;

    })
    ;

    $ php artisan route:list


    +----------------------+----------+--------------------+-----------------+------------------------------------------------+------------+


    | Domain | Method | URI | Name | Action | Middleware |


    +----------------------+----------+--------------------+-----------------+------------------------------------------------+------------+


    | {vendor}.example.com | GET|HEAD | posts/list | posts.list | App\Http\Controllers\PostsController@index | web |


    | | | | | | auth |


    | {vendor}.example.com | GET|HEAD | posts/published | posts.published | App\Http\Controllers\PostsController@published | web |


    | | | | | | auth |


    +----------------------+----------+--------------------+-----------------+------------------------------------------------+------------+

    View Slide

  15. Route::middleware('auth')->group(function ()
    {

    Route::get('blog/{post}', [PostsController::class, 'show'])->name('posts.show')
    ;

    Route::middleware('throttle:10|60,1')->group(function ()
    {

    Route::get('blog', [PostsController::class, 'index'])->name('posts.index')
    ;

    })
    ;

    Route::middleware('verified')->group(function ()
    {

    Route::get('posts/create', [PostsController::class, 'create'])->name('posts.index')
    ;

    Route::post('posts/store', [PostsController::class, 'store'])->name('posts.store')
    ;

    })
    ;

    });
    $ php artisan route:list --columns=method,name,action,middleware


    +----------+-------------+---------------------------------------------+------------------+


    | Method | Name | Action | Middleware |


    +----------+-------------+---------------------------------------------+------------------+


    | GET|HEAD | posts.index | App\Http\Controllers\PostsController@index | web |


    | | | | auth |


    | | | | throttle:10|60,1 |


    | GET|HEAD | posts.show | App\Http\Controllers\PostsController@show | web |


    | | | | auth |


    | GET|HEAD | posts.index | App\Http\Controllers\PostsController@create | web |


    | | | | auth |


    | | | | verified |


    | POST | posts.store | App\Http\Controllers\PostsController@store | web |


    | | | | auth |


    | | | | verified |


    +----------+-------------+---------------------------------------------+------------------+

    View Slide

  16. p

    namespace App\Providers
    ;

    use Illuminate\Cache\RateLimiting\Limit
    ;

    use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider
    ;

    use Illuminate\Http\Request
    ;

    use Illuminate\Support\Facades\RateLimiter
    ;

    use Illuminate\Support\Facades\Route
    ;

    class RouteServiceProvider extends ServiceProvide
    r

    {

    /*
    *

    * The path to the "home" route for your application
    .

    *

    * This is used by Laravel authentication to redirect users after login
    .

    *

    * @var strin
    g

    *
    /

    public const HOME = '/home'
    ;

    /*
    *

    * The controller namespace for the application
    .

    *

    * When present, controller route declarations will automatically be prefixed with this namespace
    .

    *

    * @var string|nul
    l

    *
    /

    // protected $namespace = 'App\\Http\\Controllers'
    ;

    View Slide

  17. ;

    use Illuminate\Support\Facades\Route
    ;

    class RouteServiceProvider extends ServiceProvide
    r

    {

    /*
    *

    * The path to the "home" route for your application
    .

    *

    * This is used by Laravel authentication to redirect users after login
    .

    *

    * @var strin
    g

    *
    /

    public const HOME = '/home'
    ;

    /*
    *

    * The controller namespace for the application
    .

    *

    * When present, controller route declarations will automatically be prefixed with this namespace
    .

    *

    * @var string|nul
    l

    *
    /

    // protected $namespace = 'App\\Http\\Controllers'
    ;

    /*
    *

    * Define your route model bindings, pattern filters, etc
    .

    *

    * @return voi
    d

    *
    /

    public function boot(
    )

    {

    $this->configureRateLimiting()
    ;

    protected $namespace = 'App\\Http\\Controllers';
    Route::get('/users/{user}', 'UsersController@show');

    View Slide

  18. /*
    *

    * Define your route model bindings, pattern filters, etc
    .

    *

    * @return voi
    d

    *
    /

    public function boot(
    )

    {

    $this->configureRateLimiting()
    ;

    $this->routes(function ()
    {

    Route::prefix('api'
    )

    ->middleware('api'
    )

    ->namespace($this->namespace
    )

    ->group(base_path('routes/api.php'))
    ;

    Route::middleware('web'
    )

    ->namespace($this->namespace
    )

    ->group(base_path('routes/web.php'))
    ;

    })
    ;

    }

    /*
    *

    * Configure the rate limiters for the application
    .

    *

    * @return voi
    d

    *
    /

    protected function configureRateLimiting(
    )

    {

    RateLimiter::for('api', function (Request $request)
    {

    return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip())
    ;

    ;

    View Slide

  19. Route::match(['get', 'post'], 'login', function (Request $request)
    {

    /
    /

    })->name('login')
    ;

    Route::any('register', function (Request $request)
    {

    /
    /

    })->name('register');
    $ php artisan route:list --columns=method,name,action,middleware


    +----------------------------------------+----------------+----------------+------------+


    | Method | Name | Action | Middleware |


    +----------------------------------------+----------------+----------------+------------+


    | GET|POST|HEAD | login | Closure | web |


    | GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS | register | Closure | web |


    +----------------------------------------+----------------+----------------+------------+

    View Slide

  20. Route::get('dashboard', DashboardController::class)->name('dashboard')
    ;

    // Redirect to a different URL, HTTP status code 30
    2

    Route::redirect('/app', '/dashboard')
    ;

    // Permanent redirect to a different URL, , HTTP status code 30
    1

    Route::permanentRedirect('contact', '/#contact');
    $ php artisan route:list --columns=method,uri,name,action


    +----------------------------------------+------------+------------+------------------------------------------+


    | Method | URI | Name | Action |


    +----------------------------------------+------------+------------+------------------------------------------+


    | GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS | app | | Illuminate\Routing\RedirectController |


    | GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS | contact | | Illuminate\Routing\RedirectController |


    | GET|HEAD | dashboard | dashboard | App\Http\Controllers\DashboardController |


    +----------------------------------------+------------+------------+------------------------------------------+

    View Slide

  21. Route::view('/home', 'welcome')->name('welcome')
    ;

    // With additional dat
    a

    Route::view('/home', 'welcome', ['title' => 'Welcome'])->name('welcome');
    $ php artisan route:list --columns=method,uri,name,action


    +----------------------------------------+------------+------------+------------------------------------------+


    | Method | URI | Name | Action |


    +----------------------------------------+------------+------------+------------------------------------------+


    | GET|HEAD | home | welcome | Illuminate\Routing\ViewController |


    +----------------------------------------+------------+------------+------------------------------------------+

    View Slide

  22. Route::fallback(function ()
    {

    return redirect()->route('welcome')
    ;

    })
    ;

    Route::fallback('App\Http\Controllers\AirportsController@index');
    $ php artisan route:list --columns=method,uri,name,action


    +----------------+-----------------------+--------+-------------------------------------------------+


    | Method | URI | Name | Action |


    +----------------+-----------------------+--------+-------------------------------------------------+


    | GET|HEAD | {fallbackPlaceholder} | | App\Http\Controllers\AirportsController@index |


    +----------------+-----------------------+--------+-------------------------------------------------+

    View Slide

  23. Route::get('customers/{customer}', ShowCustomerController::class
    )

    ->name(‘customers.show’)
    ;

    View Slide

  24. Route::get('customers/{customer}', ShowCustomerController::class
    )

    ->name(‘customers.show’)
    ;

    // https://example.com/customers/
    1

    $url = route('customers.show', 1)
    ;

    View Slide

  25. // Befor
    e

    Route::get('customers/{customer}', ShowCustomerController::class
    )

    ->name(‘customers.show’)
    ;

    // Afte
    r

    Route::get(‘customers/{customer}/details’, ShowCustomerController::class
    )

    ->name(‘customers.show’);
    // Before: https://example.com/customers/
    1

    $url = route('customers.show', 1)
    ;

    // After: https://example.com/customers/1/detail
    s

    $url = route('customers.show', 1)
    ;

    View Slide

  26. Route::get('customers/{customer}', ShowCustomerController::class
    )

    ->name(‘customers.show’)
    ;

    // https://example.com/customers/
    1

    $url = route('customers.show', 1)
    ;

    // https://example.com/customers/
    1

    $url = route('customers.show', Customer::find(1))
    ;

    View Slide

  27. Route::get('customers/{customer}', ShowCustomerController::class
    )

    ->name(‘customers.show’)
    ;

    // https://example.com/customers/
    1

    $url = route('customers.show', 1)
    ;

    // https://example.com/customers/
    1

    $url = route('customers.show', $customer)
    ;

    // https://example.com/customers/1?withInvoice=
    1

    $url = route('customers.show', ['customer' => $customer, 'withInvoice' => true])
    ;

    View Slide

  28. Route::get('customers/{customer}', ShowCustomerController::class
    )

    ->name(‘customers.show’)
    ;

    // https://example.com/customers/
    1

    $url = route('customers.show', 1)
    ;

    // https://example.com/customers/
    1

    $url = route('customers.show', $customer)
    ;

    // https://example.com/customers/1?withInvoice=
    1

    $url = route('customers.show', ['customer' => $customer, 'withInvoice' => true])
    ;

    // https://example.com/customers/1?signatur
    e

    $url = route('customers.show', [$customer, 'signature'])
    ;

    View Slide

  29. Route::get('customers/{customer}', ShowCustomerController::class
    )

    ->name(‘customers.show’)
    ;

    // https://example.com/customers/
    1

    $url = route('customers.show', 1)
    ;

    // https://example.com/customers/
    1

    $url = route('customers.show', $customer)
    ;

    // https://example.com/customers/1?withInvoice=
    1

    $url = route('customers.show', ['customer' => $customer, 'withInvoice' => true])
    ;

    // https://example.com/customers/1?signatur
    e

    $url = route('customers.show', [$customer, 'signature'])
    ;

    View Slide

  30. public function update(CustomerRequest $request, Customer $customer
    )

    {

    $customer->update($request->only(['company']))
    ;

    return redirect()->route('customers.show', $customer)
    ;

    }

    View Slide

  31. public function handle(Request $request, Closure $next
    )

    {

    if (! Auth::check() && $request->route()->named('customers.show'))
    {

    return redirect()->route('dashboard')
    ;

    }

    return $next($request)
    ;

    }

    View Slide

  32. Route::get('/users/{user}', [UsersController::class, ‘show'])->name('users.show')
    ;

    // Illuminate\Routing\Rout
    e

    $current = Route::current()
    ;

    // users.nam
    e

    $name = Route::currentRouteName()
    ;

    // App\Http\Controllers\UsersController@sho
    w

    $action = Route::currentRouteAction()
    ;

    View Slide

  33. Did you order your pizza already?
    Routing cycle
    Photo by Anete Lusina from Pexels

    View Slide

  34. // public/index.ph
    p

    /
    *

    |-------------------------------------------------------------------------
    -

    | Run The Applicatio
    n

    |-------------------------------------------------------------------------
    -

    |

    | Once we have the application, we can handle the incoming request usin
    g

    | the application's HTTP kernel. Then, we will send the response bac
    k

    | to this client's browser, allowing them to enjoy our application
    .

    |

    *
    /

    $app = require_once __DIR__.'/../bootstrap/app.php'
    ;

    $kernel = $app->make(Kernel::class)
    ;

    $response = tap($kernel->handle
    (

    $request = Request::capture(
    )

    ))->send()
    ;

    $kernel->terminate($request, $response)
    ;

    View Slide

  35. // app/Http/Kernel.ph
    p

    namespace App\Http
    ;

    use Illuminate\Foundation\Http\Kernel as HttpKernel
    ;

    class Kernel extends HttpKerne
    l

    {

    /*
    *

    * The application's global HTTP middleware stack
    .

    * These middleware are run during every request to your application
    .

    *
    /

    protected $middleware = [
    ]
    ;

    /*
    *

    * The application's route middleware groups
    .

    *
    /

    protected $middlewareGroups = [
    ]
    ;

    /*
    *

    * The application's route middleware
    .

    * These middleware may be assigned to groups or used individually
    .

    *
    /

    protected $routeMiddleware = [
    ]
    ;

    }

    View Slide

  36. // app/Http/Kernel.ph
    p

    namespace App\Http
    ;

    use Illuminate\Foundation\Http\Kernel as HttpKernel
    ;

    class Kernel extends HttpKerne
    l

    {

    /*
    *

    * The application's global HTTP middleware stack
    .

    *

    * These middleware are run during every request to your application
    .

    *

    * @var arra
    y

    *
    /

    protected $middleware =
    [

    // \App\Http\Middleware\TrustHosts::class
    ,

    \App\Http\Middleware\TrustProxies::class
    ,

    \Fruitcake\Cors\HandleCors::class
    ,

    \App\Http\Middleware\PreventRequestsDuringMaintenance::class
    ,

    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class
    ,

    \App\Http\Middleware\TrimStrings::class
    ,

    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class
    ,

    ]
    ;

    }

    View Slide

  37. // app/Http/Kernel.ph
    p

    namespace App\Http
    ;

    use Illuminate\Foundation\Http\Kernel as HttpKernel
    ;

    class Kernel extends HttpKerne
    l

    {

    /*
    *

    * The application's route middleware groups
    .

    *
    /

    protected $middlewareGroups =
    [

    'web' =>
    [

    \App\Http\Middleware\EncryptCookies::class
    ,

    \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class
    ,

    \Illuminate\Session\Middleware\StartSession::class
    ,

    // \Illuminate\Session\Middleware\AuthenticateSession::class
    ,

    \Illuminate\View\Middleware\ShareErrorsFromSession::class
    ,

    \App\Http\Middleware\VerifyCsrfToken::class
    ,

    \Illuminate\Routing\Middleware\SubstituteBindings::class
    ,

    ]
    ,

    'api' =>
    [

    'throttle:api'
    ,

    \Illuminate\Routing\Middleware\SubstituteBindings::class
    ,

    ]
    ,

    ]
    ;

    }

    View Slide

  38. // app/Http/Kernel.ph
    p

    namespace App\Http
    ;

    use Illuminate\Foundation\Http\Kernel as HttpKernel
    ;

    class Kernel extends HttpKerne
    l

    {

    /*
    *

    * The application's route middleware
    .

    *

    * These middleware may be assigned to groups or used individually
    .

    *

    * @var arra
    y

    *
    /

    protected $routeMiddleware =
    [

    'auth' => \App\Http\Middleware\Authenticate::class
    ,

    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class
    ,

    'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class
    ,

    'can' => \Illuminate\Auth\Middleware\Authorize::class
    ,

    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class
    ,

    'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class
    ,

    'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class
    ,

    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class
    ,

    'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class
    ,

    ]
    ;

    }

    View Slide

  39. // app/Http/Kernel.ph
    p

    namespace App\Http
    ;

    use Illuminate\Foundation\Http\Kernel as HttpKernel
    ;

    class Kernel extends HttpKerne
    l

    {

    /*
    *

    * The application's global HTTP middleware stack
    .

    * These middleware are run during every request to your application
    .

    *
    /

    protected $middleware = [
    ]
    ;

    /*
    *

    * The application's route middleware groups
    .

    *
    /

    protected $middlewareGroups = [
    ]
    ;

    /*
    *

    * The application's route middleware
    .

    * These middleware may be assigned to groups or used individually
    .

    *
    /

    protected $routeMiddleware = [
    ]
    ;

    }

    View Slide

  40. // vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.ph
    p

    namespace Illuminate\Foundation\Http
    ;

    class Kernel implements KernelContrac
    t

    {

    public function handle($request
    )

    {

    try
    {

    $request->enableHttpMethodParameterOverride()
    ;

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

    } catch (Throwable $e)
    {

    $this->reportException($e)
    ;

    $response = $this->renderException($request, $e)
    ;

    }

    $this->app['events']->dispatch
    (

    new RequestHandled($request, $response
    )

    )
    ;

    return $response
    ;

    }

    }

    View Slide

  41. // vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.ph
    p

    namespace Illuminate\Foundation\Http
    ;

    class Kernel implements KernelContrac
    t

    {

    /*
    *

    * Send the given request through the middleware / router
    .

    *

    * @param \Illuminate\Http\Request $reques
    t

    * @return \Illuminate\Http\Respons
    e

    *
    /

    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())
    ;

    }

    }

    View Slide

  42. // vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.ph
    p

    namespace Illuminate\Foundation\Http
    ;

    class Kernel implements KernelContrac
    t

    {

    /*
    *

    * Send the given request through the middleware / router
    .

    *

    * @param \Illuminate\Http\Request $reques
    t

    * @return \Illuminate\Http\Respons
    e

    *
    /

    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())
    ;

    }

    }

    View Slide

  43. // app/Providers/RouteServiceProvider.ph
    p

    namespace App\Providers
    ;

    use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider
    ;

    class RouteServiceProvider extends ServiceProvide
    r

    {

    /*
    *

    * Define your route model bindings, pattern filters, etc
    .

    *

    * @return voi
    d

    *
    /

    public function boot(
    )

    {

    $this->configureRateLimiting()
    ;

    $this->routes(function ()
    {

    Route::prefix('api'
    )

    ->middleware('api'
    )

    ->namespace($this->namespace
    )

    ->group(base_path('routes/api.php'))
    ;

    Route::middleware('web'
    )

    ->namespace($this->namespace
    )

    ->group(base_path('routes/web.php'))
    ;

    })
    ;

    }

    }

    View Slide

  44. // vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.ph
    p

    namespace Illuminate\Foundation\Support\Providers
    ;

    class RouteServiceProvider extends ServiceProvide
    r

    {

    /*
    *

    * Register the callback that will be used to load the application's routes
    .

    *

    * @param \Closure $routesCallbac
    k

    * @return $thi
    s

    *
    /

    protected function routes(Closure $routesCallback
    )

    {

    $this->loadRoutesUsing = $routesCallback
    ;

    return $this
    ;

    }

    }

    View Slide

  45. // vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.ph
    p

    namespace Illuminate\Foundation\Support\Providers
    ;

    class RouteServiceProvider extends ServiceProvide
    r

    {

    /*
    *

    * Register any application services
    .

    *

    * @return voi
    d

    *
    /

    public function register(
    )

    {

    $this->booted(function ()
    {

    $this->setRootControllerNamespace()
    ;

    if ($this->routesAreCached())
    {

    $this->loadCachedRoutes()
    ;

    } else
    {

    $this->loadRoutes()
    ;

    $this->app->booted(function ()
    {

    $this->app['router']->getRoutes()->refreshNameLookups()
    ;

    $this->app['router']->getRoutes()->refreshActionLookups()
    ;

    })
    ;

    }

    })
    ;

    }

    }

    View Slide

  46. // vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.ph
    p

    namespace Illuminate\Foundation\Support\Providers
    ;

    class RouteServiceProvider extends ServiceProvide
    r

    {

    /*
    *

    * Load the application routes
    .

    *

    * @return voi
    d

    *
    /

    protected function loadRoutes(
    )

    {

    if (! is_null($this->loadRoutesUsing))
    {

    $this->app->call($this->loadRoutesUsing)
    ;

    } elseif (method_exists($this, 'map'))
    {

    $this->app->call([$this, 'map'])
    ;

    }

    }

    }

    View Slide

  47. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContract
    {

    /*
    *

    * Register a new GET route with the router
    .

    *
    * @return \Illuminate\Routing\Rout
    e

    *
    /

    public function get($uri, $action = null
    )

    {

    return $this->addRoute(['GET', 'HEAD'], $uri, $action)
    ;

    }

    /*
    *

    * Register a new POST route with the router
    .

    *
    * @return \Illuminate\Routing\Rout
    e

    *
    /

    public function post($uri, $action = null
    )

    {

    return $this->addRoute('POST', $uri, $action)
    ;

    }

    }

    View Slide

  48. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContract
    {

    /*
    *

    * Add a route to the underlying route collection
    .

    *

    * @param array|string $method
    s

    * @param string $ur
    i

    * @param array|string|callable|null $actio
    n

    * @return \Illuminate\Routing\Rout
    e

    *
    /

    public function addRoute($methods, $uri, $action
    )

    {

    return $this->routes->add($this->createRoute($methods, $uri, $action))
    ;

    }

    }

    View Slide

  49. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContract
    {

    protected function createRoute($methods, $uri, $action
    )

    {

    // If the route is routing to a controller we will parse the route action int
    o

    // an acceptable array format before registering i
    t

    if ($this->actionReferencesController($action))
    {

    $action = $this->convertToControllerAction($action)
    ;

    }

    $route = $this->newRoute
    (

    $methods, $this->prefix($uri), $actio
    n

    )
    ;

    // If we have groups that need to be merged, we will merge them now after thi
    s

    // route has already been created and is ready to go
    .

    if ($this->hasGroupStack())
    {

    $this->mergeGroupAttributesIntoRoute($route)
    ;

    }

    $this->addWhereClausesToRoute($route)
    ;

    return $route
    ;

    }

    }

    View Slide

  50. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContract
    {

    /*
    *

    * Add a route to the underlying route collection
    .

    *

    * @param array|string $method
    s

    * @param string $ur
    i

    * @param array|string|callable|null $actio
    n

    * @return \Illuminate\Routing\Rout
    e

    *
    /

    public function addRoute($methods, $uri, $action
    )

    {

    return $this->routes->add($this->createRoute($methods, $uri, $action))
    ;

    }

    }

    View Slide

  51. // vendor/laravel/framework/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.ph
    p

    namespace Illuminate\Foundation\Support\Providers
    ;

    class RouteServiceProvider extends ServiceProvide
    r

    {

    /*
    *

    * Register any application services
    .

    *

    * @return voi
    d

    *
    /

    public function register(
    )

    {

    $this->booted(function ()
    {

    $this->setRootControllerNamespace()
    ;

    if ($this->routesAreCached())
    {

    $this->loadCachedRoutes()
    ;

    } else
    {

    $this->loadRoutes()
    ;

    $this->app->booted(function ()
    {

    $this->app['router']->getRoutes()->refreshNameLookups()
    ;

    $this->app['router']->getRoutes()->refreshActionLookups()
    ;

    })
    ;

    }

    })
    ;

    }

    }

    View Slide

  52. // vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.ph
    p

    namespace Illuminate\Foundation\Http
    ;

    class Kernel implements KernelContrac
    t

    {

    /*
    *

    * Send the given request through the middleware / router
    .

    *

    * @param \Illuminate\Http\Request $reques
    t

    * @return \Illuminate\Http\Respons
    e

    *
    /

    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())
    ;

    }

    }

    View Slide

  53. // vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.ph
    p

    namespace Illuminate\Foundation\Http
    ;

    class Kernel implements KernelContrac
    t

    {

    /*
    *

    * The router instance
    .

    *

    * @var \Illuminate\Routing\Route
    r

    *
    /

    protected $router
    ;

    /*
    *

    * Get the route dispatcher callback
    .

    *

    * @return \Closur
    e

    *
    /

    protected function dispatchToRouter(
    )

    {

    return function ($request)
    {

    $this->app->instance('request', $request)
    ;

    return $this->router->dispatch($request)
    ;

    }
    ;

    }

    }

    View Slide

  54. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    /*
    *

    * Dispatch the request to the application
    .

    *

    * @param \Illuminate\Http\Request $reques
    t

    * @return \Symfony\Component\HttpFoundation\Respons
    e

    *
    /

    public function dispatch(Request $request
    )

    {

    $this->currentRequest = $request
    ;

    return $this->dispatchToRoute($request)
    ;

    }

    /*
    *

    * Dispatch the request to a route and return the response
    .

    *
    /

    public function dispatchToRoute(Request $request
    )

    {

    return $this->runRoute($request, $this->findRoute($request))
    ;

    }

    }

    View Slide

  55. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    /*
    *

    * The route collection instance
    .

    *

    * @var \Illuminate\Routing\RouteCollectionInterfac
    e

    *
    /

    protected $routes
    ;

    /*
    *

    * Find the route matching a given request
    .

    *

    * @param \Illuminate\Http\Request $reques
    t

    * @return \Illuminate\Routing\Rout
    e

    *
    /

    protected function findRoute($request
    )

    {

    $this->current = $route = $this->routes->match($request)
    ;

    $this->container->instance(Route::class, $route)
    ;

    return $route
    ;

    }

    }

    View Slide

  56. // vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.ph
    p

    namespace Illuminate\Routing
    ;

    class RouteCollection extends AbstractRouteCollectio
    n

    {

    /*
    *

    * Find the first route matching a given request
    .

    *

    * @param \Illuminate\Http\Request $reques
    t

    * @return \Illuminate\Routing\Rout
    e

    *

    * @throws \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpExceptio
    n

    * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpExceptio
    n

    *
    /

    public function match(Request $request
    )

    {

    $routes = $this->get($request->getMethod())
    ;

    // First, we will see if we can find a matching route for this current reques
    t

    // method. If we can, great, we can just return it so that it can be calle
    d

    // by the consumer. Otherwise we will check for routes with another verb
    .

    $route = $this->matchAgainstRoutes($routes, $request)
    ;

    return $this->handleMatchedRoute($request, $route)
    ;

    }

    }

    View Slide

  57. // vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.ph
    p

    namespace Illuminate\Routing
    ;

    class RouteCollection extends AbstractRouteCollectio
    n

    {

    /*
    *

    * Determine if a route in the array matches the request
    .

    *

    * @return \Illuminate\Routing\Route|nul
    l

    *
    /

    protected function matchAgainstRoutes(array $routes, $request, $includingMethod = true
    )

    {

    [$fallbacks, $routes] = collect($routes)->partition(function ($route)
    {

    return $route->isFallback
    ;

    })
    ;

    return $routes->merge($fallbacks)->first(function (Route $route) use ($request, $includin
    {

    return $route->matches($request, $includingMethod)
    ;

    })
    ;

    }

    }

    View Slide

  58. // vendor/laravel/framework/src/Illuminate/Routing/Route.ph
    p

    namespace Illuminate\Routing
    ;

    class Route
    {

    /*
    *

    * Determine if the route matches a given request
    .

    *

    * @return boo
    l

    *
    /

    public function matches(Request $request, $includingMethod = true
    )

    {

    $this->compileRoute()
    ;

    foreach (self::getValidators() as $validator)
    {

    if (! $includingMethod && $validator instanceof MethodValidator)
    {

    continue
    ;

    }

    if (! $validator->matches($this, $request))
    {

    return false
    ;

    }

    }

    return true
    ;

    }

    }

    View Slide

  59. // vendor/laravel/framework/src/Illuminate/Routing/Route.ph
    p

    namespace Illuminate\Routing
    ;

    class Route
    {

    /*
    *

    * Compile the route into a Symfony CompiledRoute instance
    .

    *
    /

    protected function compileRoute(
    )

    {

    if (! $this->compiled)
    {

    $this->compiled = $this->toSymfonyRoute()->compile()
    ;

    }

    return $this->compiled
    ;

    }

    public function toSymfonyRoute(
    )

    {

    return new SymfonyRoute
    (

    preg_replace('/\{(\w+?)\?\}/', '{$1}', $this->uri()), $this->getOptionalParameterNames()
    ,

    $this->wheres, ['utf8' => true, 'action' => $this->action]
    ,

    $this->getDomain() ?: '', [], $this->method
    s

    )
    ;

    }

    }

    View Slide

  60. // vendor/laravel/framework/src/Illuminate/Routing/Route.ph
    p

    namespace Illuminate\Routing
    ;

    class Route
    {

    /*
    *

    * Determine if the route matches a given request
    .

    *

    * @return boo
    l

    *
    /

    public function matches(Request $request, $includingMethod = true
    )

    {

    $this->compileRoute()
    ;

    foreach (self::getValidators() as $validator)
    {

    if (! $includingMethod && $validator instanceof MethodValidator)
    {

    continue
    ;

    }

    if (! $validator->matches($this, $request))
    {

    return false
    ;

    }

    }

    return true
    ;

    }

    }

    View Slide

  61. // vendor/laravel/framework/src/Illuminate/Routing/Route.ph
    p

    namespace Illuminate\Routing
    ;

    class Route
    {

    /*
    *

    * Get the route validators for the instance
    .

    *

    * @return arra
    y

    *
    /

    public static function getValidators(
    )

    {

    if (isset(static::$validators))
    {

    return static::$validators
    ;

    }

    // To match the route, we will use a chain of responsibility pattern with th
    e

    // validator implementations. We will spin through each one making sure i
    t

    // passes and then we will know if the route as a whole matches request
    .

    return static::$validators =
    [

    new UriValidator, new MethodValidator
    ,

    new SchemeValidator, new HostValidator
    ,

    ]
    ;

    }

    }

    View Slide

  62. // vendor/laravel/framework/src/Illuminate/Routing/Matching/UriValidator.ph
    p

    namespace Illuminate\Routing\Matching
    ;

    use Illuminate\Http\Request
    ;

    use Illuminate\Routing\Route
    ;

    class UriValidator implements ValidatorInterfac
    e

    {

    /*
    *

    * Validate a given rule against a route and request
    .

    *

    * @param \Illuminate\Routing\Route $rout
    e

    * @param \Illuminate\Http\Request $reques
    t

    * @return boo
    l

    *
    /

    public function matches(Route $route, Request $request
    )

    {

    $path = rtrim($request->getPathInfo(), '/') ?: '/'
    ;

    return preg_match($route->getCompiled()->getRegex(), rawurldecode($path))
    ;

    }

    }

    View Slide

  63. // vendor/laravel/framework/src/Illuminate/Routing/Matching/UriValidator.ph
    ;



    $regex = '{^/users/(?P[^/]++)$}sDu';

    View Slide

  64. // vendor/laravel/framework/src/Illuminate/Routing/Route.ph
    p

    namespace Illuminate\Routing
    ;

    class Route
    {

    /*
    *

    * Determine if the route matches a given request
    .

    *

    * @return boo
    l

    *
    /

    public function matches(Request $request, $includingMethod = true
    )

    {

    $this->compileRoute()
    ;

    foreach (self::getValidators() as $validator)
    {

    if (! $includingMethod && $validator instanceof MethodValidator)
    {

    continue
    ;

    }

    if (! $validator->matches($this, $request))
    {

    return false
    ;

    }

    }

    return true
    ;

    }

    }

    View Slide

  65. // vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.ph
    p

    namespace Illuminate\Routing
    ;

    class RouteCollection extends AbstractRouteCollectio
    n

    {

    /*
    *

    * Find the first route matching a given request
    .

    *

    * @param \Illuminate\Http\Request $reques
    t

    * @return \Illuminate\Routing\Rout
    e

    *

    * @throws \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpExceptio
    n

    * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpExceptio
    n

    *
    /

    public function match(Request $request
    )

    {

    $routes = $this->get($request->getMethod())
    ;

    // First, we will see if we can find a matching route for this current reques
    t

    // method. If we can, great, we can just return it so that it can be calle
    d

    // by the consumer. Otherwise we will check for routes with another verb
    .

    $route = $this->matchAgainstRoutes($routes, $request)
    ;

    return $this->handleMatchedRoute($request, $route)
    ;

    }

    }

    View Slide

  66. // vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.ph
    p

    namespace Illuminate\Routing
    ;

    abstract class AbstractRouteCollection
    {

    protected function handleMatchedRoute(Request $request, $route
    )

    {

    if (! is_null($route))
    {

    return $route->bind($request)
    ;

    }

    // If no route was found we will now check if a matching route is specified b
    y

    // another HTTP verb. If it is we will need to throw a MethodNotAllowed an
    d

    // inform the user agent of which HTTP verb it should use for this route
    .

    $others = $this->checkForAlternateVerbs($request)
    ;

    if (count($others) > 0)
    {

    return $this->getRouteForMethods($request, $others)
    ;

    }

    throw new NotFoundHttpException
    ;

    }

    }

    View Slide

  67. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    /*
    *

    * The route collection instance
    .

    *

    * @var \Illuminate\Routing\RouteCollectionInterfac
    e

    *
    /

    protected $routes
    ;

    /*
    *

    * Find the route matching a given request
    .

    *

    * @param \Illuminate\Http\Request $reques
    t

    * @return \Illuminate\Routing\Rout
    e

    *
    /

    protected function findRoute($request
    )

    {

    $this->current = $route = $this->routes->match($request)
    ;

    $this->container->instance(Route::class, $route)
    ;

    return $route
    ;

    }

    }

    View Slide

  68. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    /*
    *

    * Dispatch the request to the application
    .

    *

    * @param \Illuminate\Http\Request $reques
    t

    * @return \Symfony\Component\HttpFoundation\Respons
    e

    *
    /

    public function dispatch(Request $request
    )

    {

    $this->currentRequest = $request
    ;

    return $this->dispatchToRoute($request)
    ;

    }

    /*
    *

    * Dispatch the request to a route and return the response
    .

    *
    /

    public function dispatchToRoute(Request $request
    )

    {

    return $this->runRoute($request, $this->findRoute($request))
    ;

    }

    }

    View Slide

  69. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    /*
    *

    * Return the response for the given route
    .

    *

    * @param \Illuminate\Http\Request $reques
    t

    * @param \Illuminate\Routing\Route $rout
    e

    * @return \Symfony\Component\HttpFoundation\Respons
    e

    *
    /

    protected function runRoute(Request $request, Route $route
    )

    {

    $request->setRouteResolver(function () use ($route)
    {

    return $route
    ;

    })
    ;

    $this->events->dispatch(new RouteMatched($route, $request))
    ;

    return $this->prepareResponse($request
    ,

    $this->runRouteWithinStack($route, $request
    )

    )
    ;

    }

    }

    View Slide

  70. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    /*
    *

    * Run the given route within a Stack "onion" instance
    .

    *
    /

    protected function runRouteWithinStack(Route $route, Request $request
    )

    {

    $shouldSkipMiddleware = $this->container->bound('middleware.disable') &
    &

    $this->container->make('middleware.disable') === true
    ;

    $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route)
    ;

    return (new Pipeline($this->container)
    )

    ->send($request
    )

    ->through($middleware
    )

    ->then(function ($request) use ($route)
    {

    return $this->prepareResponse
    (

    $request, $route->run(
    )

    )
    ;

    })
    ;

    }

    View Slide

  71. // vendor/laravel/framework/src/Illuminate/Routing/Route.ph
    p

    namespace Illuminate\Routing
    ;

    class Rout
    e

    {

    /*
    *

    * Run the route action and return the response
    .

    *

    * @return mixe
    d

    *
    /

    public function run(
    )

    {

    $this->container = $this->container ?: new Container
    ;

    try
    {

    if ($this->isControllerAction())
    {

    return $this->runController()
    ;

    }

    return $this->runCallable()
    ;

    } catch (HttpResponseException $e)
    {

    return $e->getResponse()
    ;

    }

    }

    }

    View Slide

  72. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    /*
    *

    * Run the given route within a Stack "onion" instance
    .

    *
    /

    protected function runRouteWithinStack(Route $route, Request $request
    )

    {

    $shouldSkipMiddleware = $this->container->bound('middleware.disable') &
    &

    $this->container->make('middleware.disable') === true
    ;

    $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route)
    ;

    return (new Pipeline($this->container)
    )

    ->send($request
    )

    ->through($middleware
    )

    ->then(function ($request) use ($route)
    {

    return $this->prepareResponse
    (

    $request, $route->run(
    )

    )
    ;

    })
    ;

    }

    View Slide

  73. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    /*
    *

    * Create a response instance from the given value
    .

    *

    * @param \Symfony\Component\HttpFoundation\Request $reques
    t

    * @param mixed $respons
    e

    * @return \Symfony\Component\HttpFoundation\Respons
    e

    *
    /

    public function prepareResponse($request, $response
    )

    {

    return static::toResponse($request, $response)
    ;

    }

    /*
    *

    * Static version of prepareResponse
    .

    *

    * @param \Symfony\Component\HttpFoundation\Request $reques
    t

    * @param mixed $respons
    e

    * @return \Symfony\Component\HttpFoundation\Respons
    e

    *
    /

    public static function toResponse($request, $response
    )

    {

    if ($response instanceof Responsable)
    {

    $response = $response->toResponse($request)
    ;

    }

    View Slide

  74. *
    /

    public static function toResponse($request, $response
    )

    {

    if ($response instanceof Responsable)
    {

    $response = $response->toResponse($request)
    ;

    }

    if ($response instanceof PsrResponseInterface)
    {

    $response = (new HttpFoundationFactory)->createResponse($response)
    ;

    } elseif ($response instanceof Model && $response->wasRecentlyCreated)
    {

    $response = new JsonResponse($response, 201)
    ;

    } elseif ($response instanceof Stringable)
    {

    $response = new Response($response->__toString(), 200, ['Content-Type' => 'text/html'])
    ;

    } elseif (! $response instanceof SymfonyResponse &
    &

    ($response instanceof Arrayable |
    |

    $response instanceof Jsonable |
    |

    $response instanceof ArrayObject |
    |

    $response instanceof JsonSerializable |
    |

    is_array($response)))
    {

    $response = new JsonResponse($response)
    ;

    } elseif (! $response instanceof SymfonyResponse)
    {

    $response = new Response($response, 200, ['Content-Type' => 'text/html'])
    ;

    }

    if ($response->getStatusCode() === Response::HTTP_NOT_MODIFIED)
    {

    $response->setNotModified()
    ;

    }

    return $response->prepare($request)
    ;

    }

    View Slide

  75. // vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.ph
    p

    namespace Illuminate\Foundation\Http
    ;

    class Kernel implements KernelContrac
    t

    {

    public function handle($request
    )

    {

    try
    {

    $request->enableHttpMethodParameterOverride()
    ;

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

    } catch (Throwable $e)
    {

    $this->reportException($e)
    ;

    $response = $this->renderException($request, $e)
    ;

    }

    $this->app['events']->dispatch
    (

    new RequestHandled($request, $response
    )

    )
    ;

    return $response
    ;

    }

    }

    View Slide

  76. Is your pizza being prepared?
    Route model binding
    Photo by Athena from Pexels

    View Slide

  77. Route::get('/airports/{airport}', [AirportsController::class, ‘show’]
    )

    ->name('airports.show')
    ;

    View Slide

  78. Route::get('/airports/{airport}', [AirportsController::class, ‘show']
    )

    ->name(‘airports.show')
    ;

    use App\Models\Airport
    ;

    class AirportsController extends Controlle
    r

    {

    public function show(Airport $airport
    )

    {

    return $airport
    ;

    }

    }
    Route::get('/airports/{airport}', function (Airport $airport)
    {

    return $airport
    ;

    })->name('airports.show')
    ;

    View Slide

  79. // https://example.com/airports/
    1

    Route::get('/airports/{airport}', function (Airport $airport)
    {

    // \App\Models\Airpor
    t

    return $airport
    ;

    })->name('airports.show');
    // https://example.com/airports/
    1

    Route::get('/airports/{airport}', function ($airport)
    {

    // 1
    return $airport
    ;

    })->name('airports.show');

    View Slide

  80. Route::get('users/{username}', function ($name)
    {

    return $name
    ;

    })->where('username', '[A-Za-z]+')->name('users.show')
    ;

    Route::get('{twitter}', function ($twitter)
    {

    return $twitter
    ;

    })->where('twitter', '^@(\w){1,15}$')->name('twitter')
    ;

    $ php artisan route:list


    +--------+----------+------------------+------------+---------+------------+


    | Domain | Method | URI | Name | Action | Middleware |


    +--------+----------+------------------+------------+---------+------------+


    | | GET|HEAD | users/{username} | users.show | Closure | web |


    | | GET|HEAD | {twitter} | twitter | Closure | web |


    +--------+----------+------------------+------------+---------+------------+

    View Slide

  81. Route::get('users/{id}', [UsersController::class, 'show']
    )

    ->whereNumber('id'
    )

    ->name('users.show')
    ;

    Route::get('users/{username}', [UsersController::class, 'show']
    )

    ->whereAlpha('username'
    )

    ->name('users.show')
    ;

    Route::get('users/{username}', [UsersController::class, 'show']
    )

    ->whereAlphaNumeric('username'
    )

    ->name('users.show')
    ;

    Route::get('users/{id}', [UsersController::class, 'show']
    )

    ->whereUuid('id'
    )

    ->name('users.show');

    View Slide

  82. use App\Models\Airport
    ;

    class AirportsController extends Controlle
    r

    {

    public function show(?Airport $airport = null
    )

    {

    if ($airport === null)
    {

    return Airport::first()
    ;

    }

    return $airport
    ;

    }

    }
    Route::get(‘/airports/{airport?}', [AirportsController::class, ‘show’]
    )

    ->name('airports.show');

    View Slide

  83. Route::get('/airports/{airport}', [AirportsController::class, 'show']
    )

    ->name('airports.show'
    )

    ->missing(function (Request $request) {
    return redirect()->route('airports.index')
    ;

    });

    View Slide

  84. // https://example.com/airports/AM
    S

    Route::get('/airports/{airport:code}', [AirportsController::class, ‘show']
    )

    ->name('airports.show');

    View Slide

  85. namespace App\Models
    ;

    final class Airport extends Mode
    l

    {

    use HasFactory
    ;

    /*
    *

    * Get the route key for the model
    .

    *

    * @return strin
    g

    *
    /

    public function getRouteKeyName(): strin
    g

    {

    return 'code'
    ;

    }

    }
    // https://example.com/airports/AM
    S

    Route::get('/airports/{airport}', [AirportsController::class, ‘show’]
    )

    ->name('airports.show');

    View Slide

  86. // app/Providers/RouteServiceProvider.ph
    p

    namespace App\Providers
    ;

    class RouteServiceProvider extends ServiceProvide
    r

    {

    /*
    *

    * Define your route model bindings, pattern filters, etc
    .

    *

    * @return voi
    d

    *
    /

    public function boot(
    )

    {

    Route::model('airport', Airport::class)
    ;

    Route::model('code', Airport::class)
    ;

    }

    }
    // https://example.com/airports/AM
    S

    Route::get('/airports/{airport}', [AirportsController::class, ‘show’]
    )

    ->name(‘airports.show')
    ;

    Route::get('/airports/{code}', [AirportsController::class, ‘show’]
    )

    ->name(‘airports.show’);

    View Slide

  87. // app/Providers/RouteServiceProvider.ph
    p

    namespace App\Providers
    ;

    class RouteServiceProvider extends ServiceProvide
    r

    {

    /*
    *

    * Define your route model bindings, pattern filters, etc
    .

    *

    * @return voi
    d

    *
    /

    public function boot(
    )

    {

    Route::bind(‘airport', function ($value)
    {

    return Airport::where('code', $value
    )

    ->orWhere('id', $value
    )

    ->orWhere('uuid', $value
    )

    ->firstOrFail()
    ;

    })
    ;

    }

    }

    View Slide

  88. namespace App\Models
    ;

    final class Airport extends Mode
    l

    {

    public function resolveRouteBinding($value, $field = null): sel
    f

    {

    return $this->where('code', $value
    )

    ->orWhere('id', $value
    )

    ->orWhere('uuid', $value
    )

    ->firstOrFail()
    ;

    }

    }

    View Slide

  89. // app/Http/Kernel.ph
    p

    namespace App\Http;
    class Kernel extends HttpKerne
    l

    {

    /*
    *

    * The application's route middleware groups
    .

    *

    * @var arra
    y

    *
    /

    protected $middlewareGroups =
    [

    'web' =>
    [

    \App\Http\Middleware\EncryptCookies::class
    ,

    \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class
    ,

    \Illuminate\Session\Middleware\StartSession::class
    ,

    // \Illuminate\Session\Middleware\AuthenticateSession::class
    ,

    \Illuminate\View\Middleware\ShareErrorsFromSession::class
    ,

    \App\Http\Middleware\VerifyCsrfToken::class
    ,

    \Illuminate\Routing\Middleware\SubstituteBindings::class
    ,

    ]
    ,

    'api' =>
    [

    'throttle:api'
    ,

    \Illuminate\Routing\Middleware\SubstituteBindings::class
    ,

    ]
    ,

    ]
    ;

    }

    View Slide

  90. // vendor/laravel/framework/src/Illuminate/Routing/Middeware/SubstituteBindings.ph
    p

    namespace Illuminate\Routing\Middleware;


    class SubstituteBindings


    {


    /**


    * Handle an incoming request.


    */


    public function handle($request, Closure $next)


    {


    try {


    $this->router->substituteBindings($route = $request->route());


    $this->router->substituteImplicitBindings($route);


    } catch (ModelNotFoundException $exception) {


    if ($route->getMissing()) {


    return $route->getMissing()($request);


    }


    throw $exception;


    }


    return $next($request);


    }


    }

    View Slide

  91. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    public function substituteBindings($route
    )

    {

    foreach ($route->parameters() as $key => $value)
    {

    if (isset($this->binders[$key]))
    {

    $route->setParameter($key, $this->performBinding($key, $value, $route))
    ;

    }

    }

    return $route
    ;

    }

    /**


    * Call the binding callback for the given key.


    */


    protected function performBinding($key, $value, $route)


    {


    return call_user_func($this->binders[$key], $value, $route);


    }


    }

    View Slide

  92. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    public function substituteBindings($route
    )

    {

    foreach ($route->parameters() as $key => $value)
    {

    if (isset($this->binders[$key]))
    {

    $route->setParameter($key, $this->performBinding($key, $value, $route))
    ;

    }

    }

    return $route
    ;

    }

    /**


    * Call the binding callback for the given key.


    */


    protected function performBinding($key, $value, $route)


    {


    return call_user_func($this->binders[$key], $value, $route);


    }


    }

    View Slide

  93. // app/Providers/RouteServiceProvider.ph
    p

    namespace App\Providers
    ;

    class RouteServiceProvider extends ServiceProvide
    r

    {

    /*
    *

    * Define your route model bindings, pattern filters, etc
    .

    *
    /

    public function boot(
    )

    {

    Route::model('code', Airport::class)
    ;

    Route::bind('airport', function ($value)
    {

    return Airport::where('code', $value
    )

    ->orWhere('id', $value
    )

    ->orWhere('uuid', $value
    )

    ->firstOrFail()
    ;

    })
    ;

    }

    }

    View Slide

  94. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    /*
    *

    * Add a new route parameter binder
    .

    *
    /

    public function bind($key, $binder
    )

    {

    $this->binders[str_replace('-', '_', $key)] = RouteBinding::forCallback
    (

    $this->container, $binde
    r

    )
    ;

    }

    /*
    *

    * Register a model binder for a wildcard
    .

    *
    /

    public function model($key, $class, Closure $callback = null
    )

    {

    $this->bind($key, RouteBinding::forModel($this->container, $class, $callback))
    ;

    }

    }

    View Slide

  95. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    d

    Route::bind('airport', App\Services\AirportBinder::class)
    ;

    // Calls the method of the clas
    s

    Route::bind('airport', ‘App\Services\AirportBinder@parse')
    ;

    // Use the callback
    Route::bind('airport', function ($value)
    {

    return Airport::where('code', $value
    )

    ->orWhere('id', $value
    )

    ->firstOrFail()
    ;

    });

    View Slide

  96. // vendor/laravel/framework/src/Illuniate/Routing/RouteBinding.ph
    p

    namespace Illuminate\Routing
    ;

    class RouteBindin
    g

    {

    public static function forCallback($container, $binder
    )

    {

    if (is_string($binder))
    {

    return static::createClassBinding($container, $binder)
    ;

    }

    return $binder
    ;

    }

    protected static function createClassBinding($container, $binding
    )

    {

    return function ($value, $route) use ($container, $binding)
    {

    // If the binding has an @ sign, we will assume it's being used to delimi
    t

    // the class name from the bind method name. This allows for binding
    s

    // to run multiple bind methods in a single class for convenience
    .

    [$class, $method] = Str::parseCallback($binding, 'bind')
    ;

    $callable = [$container->make($class), $method]
    ;

    return $callable($value, $route)
    ;

    }
    ;

    }

    }

    View Slide

  97. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    /*
    *

    * Add a new route parameter binder
    .

    *
    /

    public function bind($key, $binder
    )

    {

    $this->binders[str_replace('-', '_', $key)] = RouteBinding::forCallback
    (

    $this->container, $binde
    r

    )
    ;

    }

    /*
    *

    * Register a model binder for a wildcard
    .

    *
    /

    public function model($key, $class, Closure $callback = null
    )

    {

    $this->bind($key, RouteBinding::forModel($this->container, $class, $callback))
    ;

    }

    }

    View Slide

  98. // vendor/laravel/framework/src/Illuniate/Routing/RouteBinding.ph
    p

    namespace Illuminate\Routing
    ;

    class RouteBindin
    g

    {

    public static function forModel($container, $class, $callback = null
    )

    {

    return function ($value) use ($container, $class, $callback)
    {

    if (is_null($value))
    {

    return
    ;

    }

    // Try to find the model and return it
    .

    $instance = $container->make($class)
    ;

    if ($model = $instance->resolveRouteBinding($value))
    {

    return $model
    ;

    }

    // Callback to determine what should happen if model was not found
    .

    if ($callback instanceof Closure)
    {

    return $callback($value)
    ;

    }

    throw (new ModelNotFoundException)->setModel($class)
    ;

    }
    ;

    }

    }

    View Slide

  99. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    /*
    *

    * Add a new route parameter binder
    .

    *
    /

    public function bind($key, $binder
    )

    {

    $this->binders[str_replace('-', '_', $key)] = RouteBinding::forCallback
    (

    $this->container, $binde
    r

    )
    ;

    }

    /*
    *

    * Register a model binder for a wildcard
    .

    *
    /

    public function model($key, $class, Closure $callback = null
    )

    {

    $this->bind($key, RouteBinding::forModel($this->container, $class, $callback))
    ;

    }

    }

    View Slide

  100. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    public function substituteBindings($route
    )

    {

    foreach ($route->parameters() as $key => $value)
    {

    if (isset($this->binders[$key]))
    {

    $route->setParameter($key, $this->performBinding($key, $value, $route))
    ;

    }

    }

    return $route
    ;

    }

    /**


    * Call the binding callback for the given key.


    */


    protected function performBinding($key, $value, $route)


    {


    return call_user_func($this->binders[$key], $value, $route);


    }


    }

    View Slide

  101. // vendor/laravel/framework/src/Illuminate/Routing/Router.ph
    p

    namespace Illuminate\Routing
    ;

    class Router implements BindingRegistrar, RegistrarContrac
    t

    {

    /*
    *

    * Substitute the implicit Eloquent model bindings for the route
    .

    *
    /

    public function substituteImplicitBindings($route
    )

    {

    ImplicitRouteBinding::resolveForRoute($this->container, $route)
    ;

    }

    }

    View Slide

  102. // vendor/laravel/framework/src/Illuminate/Routing/ImplicitRouteBinding.ph
    p

    namespace Illuminate\Routing
    ;

    class ImplicitRouteBindin
    g

    {

    public static function resolveForRoute($container, $route
    )

    {

    $parameters = $route->parameters()
    ;

    foreach ($route->signatureParameters(UrlRoutable::class) as $parameter)
    {

    if (! $parameterName = static::getParameterName($parameter->getName(), $parameters))
    {

    continue
    ;

    }

    $parameterValue = $parameters[$parameterName]
    ;

    if ($parameterValue instanceof UrlRoutable)
    {

    continue
    ;

    }

    $instance = $container->make(Reflector::getParameterClassName($parameter))
    ;

    $parent = $route->parentOfParameter($parameterName)
    ;

    if ($parent instanceof UrlRoutable && in_array($parameterName, array_keys($route-
    >bindingFields())))
    {

    if (! $model = $parent->resolveChildRouteBinding
    (

    $parameterName, $parameterValue, $route->bindingFieldFor($parameterName
    )

    {

    View Slide

  103. // vendor/laravel/framework/src/Illuminate/Routing/Route.ph
    p

    namespace Illuminate\Routing
    ;

    class Rout
    e

    {

    /**


    * Get the parameters that are listed in the route / controller signature.


    *


    * @param string|null $subClass


    * @return array


    */


    public function signatureParameters($subClass = null)


    {


    return RouteSignatureParameters::fromAction($this->action, $subClass);


    }


    }

    View Slide

  104. // vendor/laravel/framework/src/Illuminate/Routing/RouteSignatureParameters.php


    namespace Illuminate\Routing;


    class RouteSignatureParameters


    {


    public static function fromAction(array $action, $subClass = null)


    {


    $callback = RouteAction::containsSerializedClosure($action)


    ? unserialize($action['uses'])->getClosure()


    : $action['uses'];


    $parameters = is_string($callback)


    ? static::fromClassMethodString($callback)


    : (new ReflectionFunction($callback))->getParameters();


    return is_null($subClass)


    ? $parameters


    : array_filter($parameters, function ($p) use ($subClass) {


    return Reflector::isParameterSubclassOf($p, $subClass);


    });


    }


    protected static function fromClassMethodString($uses)


    {


    [$class, $method] = Str::parseCallback($uses);


    if (! method_exists($class, $method) && Reflector::isCallable($class, $method)) {


    return [];


    }


    return (new ReflectionMethod($class, $method))->getParameters();


    }


    }

    View Slide

  105. // vendor/laravel/framework/src/Illuminate/Routing/RouteSignatureParameters.php


    namespace Illuminate\Routing;


    class RouteSignatureParameters


    {


    public static function fromAction(array $action, $subClass = null)


    {


    $callback = RouteAction::containsSerializedClosure($action)


    ? unserialize($action['uses'])->getClosure()


    : $action['uses'];


    $parameters = is_string($callback)


    ? static::fromClassMethodString($callback)


    : (new ReflectionFunction($callback))->getParameters();


    return is_null($subClass)


    ? $parameters


    : array_filter($parameters, function ($p) use ($subClass) {


    return Reflector::isParameterSubclassOf($p, $subClass);


    });


    }


    protected static function fromClassMethodString($uses)


    {


    [$class, $method] = Str::parseCallback($uses);


    if (! method_exists($class, $method) && Reflector::isCallable($class, $method)) {


    return [];


    }


    return (new ReflectionMethod($class, $method))->getParameters();


    }


    }

    View Slide

  106. {

    $parameters = $route->parameters()
    ;

    foreach ($route->signatureParameters(UrlRoutable::class) as $parameter)
    {

    if (! $parameterName = static::getParameterName($parameter->getName(), $parameters))
    {

    continue
    ;

    }

    $parameterValue = $parameters[$parameterName]
    ;

    if ($parameterValue instanceof UrlRoutable)
    {

    continue
    ;

    }

    $instance = $container->make(Reflector::getParameterClassName($parameter))
    ;

    $parent = $route->parentOfParameter($parameterName)
    ;

    if ($parent instanceof UrlRoutable && in_array($parameterName, array_keys($route->bindingFields())))
    {

    if (! $model = $parent->resolveChildRouteBinding
    (

    $parameterName, $parameterValue, $route->bindingFieldFor($parameterName
    )

    ))
    {

    throw (new ModelNotFoundException)->setModel(get_class($instance), [$parameterValue])
    ;

    }

    } elseif (! $model = $instance->resolveRouteBinding($parameterValue, $route-
    >bindingFieldFor($parameterName)))
    {

    throw (new ModelNotFoundException)->setModel(get_class($instance), [$parameterValue])
    ;

    }

    $route->setParameter($parameterName, $model)
    ;

    }

    }

    View Slide

  107. // vendor/laravel/framework/src/Illuminate/Routing/Middeware/SubstituteBindings.ph
    p

    namespace Illuminate\Routing\Middleware
    ;

    class SubstituteBinding
    s

    {

    public function handle($request, Closure $next
    )

    {

    try
    {

    $this->router->substituteBindings($route = $request->route())
    ;

    $this->router->substituteImplicitBindings($route)
    ;

    } catch (ModelNotFoundException $exception)
    {

    if ($route->getMissing())
    {

    return $route->getMissing()($request)
    ;

    }

    throw $exception
    ;

    }

    return $next($request)
    ;

    }

    }

    View Slide

  108. // vendor/laravel/framework/src/Illuminate/Routing/Route.ph
    p

    namespace Illuminate\Routing
    ;

    class Rout
    e

    {

    /*
    *

    * Run the route action and return the response
    .

    *

    * @return mixe
    d

    *
    /

    public function run(
    )

    {

    $this->container = $this->container ?: new Container
    ;

    try
    {

    if ($this->isControllerAction())
    {

    return $this->runController()
    ;

    }

    return $this->runCallable()
    ;

    } catch (HttpResponseException $e)
    {

    return $e->getResponse()
    ;

    }

    }

    }

    View Slide

  109. // vendor/laravel/framework/src/Illuminate/Routing/Route.ph
    p

    namespace Illuminate\Routing
    ;

    class Rout
    e

    {

    protected function runController()


    {


    return $this->controllerDispatcher()->dispatch(


    $this, $this->getController(), $this->getControllerMethod()


    );


    }


    public function getController()


    {


    if (! $this->controller) {


    $class = $this->parseControllerCallback()[0];


    $this->controller = $this->container->make(ltrim($class, '\\'));


    }


    return $this->controller;


    }


    protected function getControllerMethod()


    {


    return $this->parseControllerCallback()[1];


    }


    protected function parseControllerCallback()


    {


    return Str::parseCallback($this->action['uses']);


    }


    }

    View Slide

  110. // vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php


    namespace Illuminate\Routing;


    use Illuminate\Container\Container;


    use Illuminate\Routing\Contracts\ControllerDispatcher as ControllerDispatcherContract;


    class ControllerDispatcher implements ControllerDispatcherContract


    {


    use RouteDependencyResolverTrait;


    /**


    * Dispatch a request to a given controller and method.


    */


    public function dispatch(Route $route, $controller, $method)


    {


    $parameters = $this->resolveClassMethodDependencies(


    $route->parametersWithoutNulls(), $controller, $method


    );


    if (method_exists($controller, 'callAction')) {


    return $controller->callAction($method, $parameters);


    }


    return $controller->{$method}(...array_values($parameters));


    }


    }

    View Slide

  111. Is your pizza on its way?
    Router use case
    Photo by Lucian Alexe on Unsplash

    View Slide

  112. {

    "order": "/order/vendor/dominos/pizza/hawaii"
    ,

    "message":
    {

    "price": "10.80"
    ,

    "delivery_time": "2021-03-17 19:10:00"
    ,

    "options":
    [

    "no-pineapple
    "

    ]

    }

    }

    View Slide

  113. class OrdersController extends Controlle
    r

    {

    public function store(Request $request
    )

    {

    $pattern = '/order/vendor/{vendor}/pizza/{pizza}'
    ;

    $message = json_decode($request->input('message'), true)
    ;

    $parameters = $this->getRouteParametersForPattern($message['order'], $pattern)
    ;

    $vendor = Vendor::where('key', $parameters['vendor'])->firstOrFail()
    ;

    $pizza = Pizza::where('key', $parameters['pizza'])->firstOrFail();
    }

    }
    "order": "/order/vendor/dominos/pizza/hawaii",

    View Slide

  114. "order": "/order/vendor/dominos/pizza/hawaii",
    $pattern = '/order/vendor/{vendor}/pizza/{pizza}';
    private function getRouteParametersForPattern(string $url, string $pattern): arra
    y

    {

    $compiledRoute = RouteCompiler::compile(new Route($pattern))
    ;

    $matches = []
    ;

    preg_match_all($compiledRoute->getRegex(), $url, $matches)
    ;

    $parameters = []
    ;

    foreach ($compiledRoute->getVariables() as $variable)
    {

    $parameters[$variable] = $matches[$variable][0]
    ;

    }

    return $parameters
    ;

    }

    View Slide

  115. private function getRouteParametersForPattern(string $url, string $pattern): arra
    y

    {

    $compiledRoute = RouteCompiler::compile(new Route($pattern))
    ;

    $matches = []
    ;

    preg_match_all($compiledRoute->getRegex(), $url, $matches)
    ;

    $parameters = []
    ;

    foreach ($compiledRoute->getVariables() as $variable)
    {

    $parameters[$variable] = $matches[$variable][0]
    ;

    }

    return $parameters
    ;

    }

    "order": "/order/vendor/dominos/pizza/hawaii",
    $pattern = '/order/vendor/{vendor}/pizza/{pizza}';
    $regex = "{^/order/vendor/(?P[^/]++)/pizza/(?P[^/]++)$}sD"
    ;

    $matches =
    [

    'vendor' =>
    [

    'dominos'
    ,

    ]
    ,

    'pizza' =>
    [

    'margherita'
    ,

    ]
    ,

    ];

    View Slide

  116. class OrdersController extends Controlle
    r

    {

    public function store(Request $request
    )

    {

    $pattern = '/order/vendor/{vendor}/pizza/{pizza}'
    ;

    $message = json_decode($request->input('message'), true)
    ;

    $parameters = $this->getRouteParametersForPattern($message['order'], $pattern)
    ;

    $vendor = Vendor::where('key', $parameters['vendor'])->firstOrFail()
    ;

    $pizza = Pizza::where('key', $parameters['pizza'])->firstOrFail();
    }

    }
    "order": "/order/vendor/dominos/pizza/hawaii",

    View Slide

  117. {

    "topic": "/windpark/2/turbine/5/sensor/shadow_flicker"
    ,

    "message":
    {

    "datetime":"2021-17-03T15:47:14+00:00"
    ,

    "status": tru
    e

    }

    }

    View Slide

  118. final class Shadow extends Messag
    e

    {

    public string $type = MessageTypes::TYPE_SHADOW_FLICKER
    ;

    protected string $routePattern = '/windpark/{windparkId}/turbine/{turbineId}/sensor/shadow_flicker'
    ;

    public function validate(): Messag
    e

    {

    if (! is_bool($this->message->status))
    {

    throw new Exception('Value could not be validated')
    ;

    }

    return $this
    ;

    }

    public function isSameStatus($status): boo
    l

    {

    return (bool) $status === $this->message->status
    ;

    }

    }

    View Slide

  119. Did your pizza already arrive?
    Best practices
    Photo by Vita Marija Murenaite on Unsplash

    View Slide

  120. // Don't do thi
    s

    Route::name('teams.')->group(function ()
    {

    Route::group(['prefix' => 'team'], function ()
    {

    Route::get('/', [TeamsController::class, 'index'])->middleware('auth')->name('index')
    ;

    Route::get('/create', [TeamsController::class, 'create'])->middleware('auth')->name('create')
    ;

    Route::post('/', [TeamsController::class, 'store'])->middleware('auth')->name('store')
    ;

    Route::get('/{team}', [TeamsController::class, 'show'])->middleware('auth')->name('show')
    ;

    Route::get('/{team}/edit', [TeamsController::class, 'edit'])->middleware('auth')->name('edit')
    ;

    Route::put('/{team}', [TeamsController::class, 'update'])->middleware('auth')->name('update')
    ;

    Route::delete('/{team}', [TeamsController::class, 'destroy'])->middleware('auth')->name('destroy')
    ;

    })
    ;

    });
    // Instead do thi
    s

    Route::get('teams', [TeamsController::class, 'index'])->name('teams.index')
    ;

    Route::middleware('auth')->group(function ()
    {

    Route::get('teams/create', [TeamsController::class, 'create'])->name('teams.create')
    ;

    Route::post('teams', [TeamsController::class, 'store'])->name('teams.store')
    ;

    Route::get('teams/{team}', [TeamsController::class, 'show'])->name('teams.show')
    ;

    Route::get('teams/{team}/edit', [TeamsController::class, 'edit'])->name('teams.edit')
    ;

    Route::put('teams/{team}', [TeamsController::class, 'update'])->name('teams.update')
    ;

    Route::delete('teams/{team}', [TeamsController::class, 'destroy'])->name('teams.destroy')
    ;

    });

    View Slide

  121. // app/Providers/RouteServiceProvider.php


    namespace App\Providers;


    class RouteServiceProvider extends ServiceProvider


    {


    /**


    * Define your route model bindings, pattern filters, etc.


    */


    public function boot()


    {


    $this->routes(function () {


    Route::prefix('api')


    ->middleware('api')


    ->namespace($this->namespace)


    ->group(base_path('routes/api.php'));


    Route::middleware('web')


    ->namespace($this->namespace)


    ->group(base_path('routes/web.php'));


    Route::middleware(['web', 'can:admin'])


    ->namespace($this->namespace)


    ->group(base_path('routes/admin.php'));


    });


    }


    }

    View Slide

  122. // app/Providers/RouteServiceProvider.php


    namespace App\Providers;


    class RouteServiceProvider extends ServiceProvider


    {


    /**


    * Define your route model bindings, pattern filters, etc.


    */


    public function boot()


    {


    $this->routes(function () {


    if (config('app.api') === true) {


    Route::prefix('api')


    ->middleware('api')


    ->namespace($this->namespace)


    ->group(base_path('routes/api.php'));


    } else {


    Route::middleware('web')


    ->namespace($this->namespace)


    ->group(base_path('routes/web.php'));


    }


    });


    }


    }

    View Slide

  123. // app/Providers/RouteServiceProvider.php


    namespace App\Providers;


    class RouteServiceProvider extends ServiceProvider


    {


    /**


    * Define your route model bindings, pattern filters, etc.


    */


    public function boot()


    {


    Route::model('country', Country::class);


    Route::bind('airport', function ($value, $route) {


    return Airport::where('country_id', $route->parameter('country'))


    ->where('code', $value)


    ->firstOrFail();


    });


    }


    }

    View Slide

  124. // Doesn’t work as expected


    Route::get('/users/{user}', [UsersController::class, 'show'])->name('users.show');


    Route::get('/users/create', [UsersController::class, 'create'])->name('users.create');
    // Works as expected


    Route::get('/users/create', [UsersController::class, 'create'])->name('users.create');

    Route::get('/users/{user}', [UsersController::class, 'show'])->name('users.show');

    View Slide

  125. class SomeMiddlewar
    e

    {

    public function handle($request, Closure $next
    )

    {

    // App\Model\Use
    r

    $request->route(‘user')
    ;

    return $next($request)
    ;

    }

    }

    View Slide

  126. $ php artisan route:cache

    Route cache cleared!

    Routes cached successfully!

    View Slide

  127. Ok, one more pizza
    Photo by Katerina Holmes from Pexels
    Final pizza! Promised!

    View Slide

  128. View Slide

  129. Enjoy your pizza!
    Thank you 🍕

    View Slide