$30 off During Our Annual Pro Sale. View Details »

What's new in Laravel 9

What's new in Laravel 9

Some of the new features we get in PHP's favourite framework: Laravel 9

Christian Leo-Pernold

March 10, 2022
Tweet

More Decks by Christian Leo-Pernold

Other Decks in Technology

Transcript

  1. What's new in
    Laravel 9

    View Slide

  2. About me

    !
    Christian Leo-Pernold

    "#$%&'()*⛰,-.

    /
    @mazedlx


    github.com/mazedlx

    1
    mazedlx.net

    2
    gusch.fredl.at
    2/40

    View Slide

  3. Laravel 9
    Released on 2022-02-08
    3/40

    View Slide

  4. Minimum PHP Version
    8.0
    4/40

    View Slide

  5. Controller
    Route
    Groups
    5/40

    View Slide

  6. // Laravel 8
    use App\Http\Controllers\CustomerController;
    Route::get('customers', [CustomerController::class, 'index']);
    Route::get('customers/create', [CustomerController::class, 'create']);
    Route::post('customers', [CustomerController::class, 'store']);
    Route::get('customers/{customer}', [CustomerController::class, 'show']);
    Route::get('customers/{customer}/edit', [CustomerController::class, 'edit']);
    Route::patch('customers/{customer}', [CustomerController::class, 'update']);
    6/40

    View Slide

  7. // Laravel 9
    use App\Http\Controllers\CustomerController;
    Route::controller(CustomerController::class)->group(function() {
    Route::get('customers', 'index');
    Route::get('customers/create', 'create');
    Route::post('customers', 'store');
    Route::get('customers/{customer}', 'show');
    Route::get('customers/{customer}/edit', 'edit');
    Route::patch('customers/{customer}', 'update');
    });
    7/40

    View Slide

  8. Be!er
    php artisan route:list
    8/40

    View Slide

  9. // Laravel 8
    $ php artisan route:list
    +--------+----------+----------------------------------+-----------------------+------------------------------------------------------+---------------------------------------------------------+
    | Domain | Method | URI | Name | Action | Middleware |
    +--------+----------+----------------------------------+-----------------------+------------------------------------------------------+---------------------------------------------------------+
    | | GET|HEAD | / | episodes.index | App\Http\Livewire\Episodes\Index | web |
    | | GET|HEAD | backstage | backstage | App\Http\Livewire\Backstage | web |
    | | | | | | App\Http\Middleware\Authenticate |
    | | | | | | Spatie\ResponseCache\Middlewares\DoNotCacheResponse |
    | | GET|HEAD | episodes/create | episodes.create | App\Http\Livewire\Episodes\Create | web |
    | | | | | | App\Http\Middleware\Authenticate |
    | | | | | | Spatie\ResponseCache\Middlewares\DoNotCacheResponse |
    | | | | | | Illuminate\Auth\Middleware\Authorize:create,App\Episode |
    | | GET|HEAD | episodes/{episode}/edit | episodes.edit | App\Http\Livewire\Episodes\Edit | web |
    +--------+----------+----------------------------------+-----------------------+------------------------------------------------------+---------------------------------------------------------+
    9/40

    View Slide

  10. // Laravel 8
    $ php artisan route:list
    +--------+----------+----------------------------------+-----------------------+------------------------------------------------------
    +---------------------------------------------------------+
    | Domain | Method | URI | Name | Action |
    Middleware |
    +--------+----------+----------------------------------+-----------------------+------------------------------------------------------
    +---------------------------------------------------------+
    | | GET|HEAD | / | episodes.index | App\Http\Livewire\Episodes\Index |
    web |
    | | GET|HEAD | backstage | backstage | App\Http\Livewire\Backstage |
    web |
    | | | | | |
    App\Http\Middleware\Authenticate |
    | | | | | |
    Spatie\ResponseCache\Middlewares\DoNotCacheResponse |
    | | GET|HEAD | episodes/create | episodes.create | App\Http\Livewire\Episodes\Create |
    web |
    | | | | | |
    App\Http\Middleware\Authenticate |
    | | | | | |
    Spatie\ResponseCache\Middlewares\DoNotCacheResponse |
    | | | | | |
    Illuminate\Auth\Middleware\Authorize:create,App\Episode |
    | | GET|HEAD | episodes/{episode}/edit | episodes.edit | App\Http\Livewire\Episodes\Edit |
    web |
    +--------+----------+----------------------------------+-----------------------+------------------------------------------------------
    +---------------------------------------------------------+
    10/40

    View Slide

  11. // Laravel 8
    $ php artisan route:list -c
    +----------+----------------------------------+------------------------------------------------------+
    | Method | URI | Action |
    +----------+----------------------------------+------------------------------------------------------+
    | GET|HEAD | / | App\Http\Livewire\Episodes\Index |
    | GET|HEAD | backstage | App\Http\Livewire\Backstage |
    | GET|HEAD | episodes/create | App\Http\Livewire\Episodes\Create |
    | GET|HEAD | episodes/{episode}/edit | App\Http\Livewire\Episodes\Edit |
    | GET|HEAD | feed | App\Http\Controllers\FeedController |
    | GET|HEAD | livewire/livewire.js | Livewire\Controllers\LivewireJavaScriptAssets@source |
    | GET|HEAD | livewire/livewire.js.map | Livewire\Controllers\LivewireJavaScriptAssets@maps |
    | POST | livewire/message/{name} | Livewire\Controllers\HttpConnectionHandler |
    | GET|HEAD | livewire/preview-file/{filename} | Livewire\Controllers\FilePreviewHandler@handle |
    | POST | livewire/upload-file | Livewire\Controllers\FileUploadHandler@handle |
    | GET|HEAD | login | App\Http\Livewire\Auth\Login |
    | GET|HEAD | preview/{episode} | App\Http\Livewire\Episodes\Index |
    | GET|HEAD | {episode} | App\Http\Livewire\Episodes\Index |
    +----------+----------------------------------+------------------------------------------------------+
    11/40

    View Slide

  12. // Laravel 9
    $ php artisan route:list
    GET|HEAD posts ................................................ posts.index › PostController@index
    POST posts ................................................ posts.store › PostController@store
    GET|HEAD posts/create ....................................... posts.create › PostController@create
    GET|HEAD posts/{post} ........................................... posts.show › PostController@show
    PATCH posts/{post} ....................................... posts.update › PostController@update
    GET|HEAD posts/{post}/edit ...................................... posts.edit › PostController@edit
    POST posts/{post}/pin .......................................... posts.pin › PinPostController
    POST posts/{post}/publish .............................. posts.publish › PublishPostController
    POST posts/{post}/unpin .................................... posts.unpin › UnpinPostController
    12/40

    View Slide

  13. Anonymous
    Migration Classes
    13/40

    View Slide

  14. use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;
    return new class extends Migration
    {
    public function up()
    {
    Schema::create('tablename', function (Blueprint $table) {
    $table->id();
    $table->timestamps();
    });
    }
    public function down()
    {
    Schema::dropIfExists('tablename');
    }
    };
    14/40

    View Slide

  15. New
    Helper
    Functions
    15/40

    View Slide

  16. // str() - alias for Illuminate\Support\Str::of($string)
    str('hello')->append(' world!);
    // to_route() - equivalent to redirect()->route($route)
    return to_route('home');
    16/40

    View Slide

  17. Refreshed
    Ignition
    Error Pages
    17/40

    View Slide

  18. 18/40

    View Slide

  19. 19/40

    View Slide

  20. 20/40

    View Slide

  21. Yes, of course
    there is a
    Dark Mode
    21/40

    View Slide

  22. 22/40

    View Slide

  23. Render
    Blade
    String
    23/40

    View Slide

  24. Route::get('/', function () {
    return Blade::render('{{ $greeting }}, World!', [
    'greeting' => 'Hello',
    ]);
    });
    24/40

    View Slide

  25. Forced
    Scope
    Bindings
    25/40

    View Slide

  26. // Scopes the second Eloquent model
    // that it must be a child of the first Eleoquent model
    Route::get('users/{user}/posts/{post}', function (User $user, Post $post) {
    return $post;
    })->scopeBindings();
    26/40

    View Slide

  27. Test
    Coverage
    27/40

    View Slide

  28. $ php artisan test --coverage
    Console/Kernel ............................................................................ 100.0 %
    Exceptions/Handler ........................................................................ 100.0 %
    Http/Controllers/Controller ............................................................... 100.0 %
    Http/Kernel ............................................................................... 100.0 %
    Http/Middleware/Authenticate ................................................................. 0.0 %
    Http/Middleware/EncryptCookies ............................................................ 100.0 %
    Http/Middleware/PreventRequestsDuringMaintenance .......................................... 100.0 %
    Http/Middleware/RedirectIfAuthenticated ...................................................... 0.0 %
    Http/Middleware/TrimStrings ............................................................... 100.0 %
    Http/Middleware/TrustHosts ................................................................... 0.0 %
    Http/Middleware/TrustProxies .............................................................. 100.0 %
    Http/Middleware/VerifyCsrfToken ........................................................... 100.0 %
    Models/User ............................................................................... 100.0 %
    Providers/AppServiceProvider .............................................................. 100.0 %
    Providers/AuthServiceProvider ............................................................. 100.0 %
    Providers/BroadcastServiceProvider ........................................................... 0.0 %
    Providers/EventServiceProvider ............................................................ 100.0 %
    Providers/RouteServiceProvider 51 ........................................................... 90.9 %
    Total Coverage .............................................................................. 57.7 %
    28/40

    View Slide

  29. $ php artisan test --coverage --min=90
    Console/Kernel ............................................................................ 100.0 %
    Exceptions/Handler ........................................................................ 100.0 %
    Http/Controllers/Controller ............................................................... 100.0 %
    Http/Kernel ............................................................................... 100.0 %
    Http/Middleware/Authenticate ................................................................. 0.0 %
    Http/Middleware/EncryptCookies ............................................................ 100.0 %
    Http/Middleware/PreventRequestsDuringMaintenance .......................................... 100.0 %
    Http/Middleware/RedirectIfAuthenticated ...................................................... 0.0 %
    Http/Middleware/TrimStrings ............................................................... 100.0 %
    Http/Middleware/TrustHosts ................................................................... 0.0 %
    Http/Middleware/TrustProxies .............................................................. 100.0 %
    Http/Middleware/VerifyCsrfToken ........................................................... 100.0 %
    Models/User ............................................................................... 100.0 %
    Providers/AppServiceProvider .............................................................. 100.0 %
    Providers/AuthServiceProvider ............................................................. 100.0 %
    Providers/BroadcastServiceProvider ........................................................... 0.0 %
    Providers/EventServiceProvider ............................................................ 100.0 %
    Providers/RouteServiceProvider 51 ........................................................... 90.9 %
    Total Coverage .............................................................................. 57.7 %
    FAIL Code coverage below expected: 57.7 %. Minimum: 90.0 %.
    29/40

    View Slide

  30. Laravel
    Scout
    Database
    Engine
    30/40

    View Slide

  31. No need for Algolia or MeiliSearch*
    * depending on how many records you have
    31/40

    View Slide

  32. Full Text
    Indexing
    for
    MySQL and PostgreSQL
    32/40

    View Slide

  33. Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->text('body')->fulltext();
    $table->timestamps();
    });
    Post::whereFullText('body', 'search')->get();
    33/40

    View Slide

  34. Enum
    A!ribute Casting
    34/40

    View Slide

  35. enum PostState: string
    {
    case Draft = 'draft';
    case Published = 'published';
    case Archived = 'archived';
    }
    Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->text('body')->fulltext();
    //$table->enum('state', ['draft', 'published', 'archived']);
    $table->string('state')->default('draft');
    $table->timestamps();
    });
    35/40

    View Slide

  36. class Post extends Model
    {
    protected $casts = [
    'state' => PostState::class,
    ];
    }
    36/40

    View Slide

  37. Simplified
    Accessors
    and
    Mutators
    37/40

    View Slide

  38. // Laravel 8
    class User extends Model
    {
    public function getFirstNameAttribute()
    {
    return ucfirst($this->first_name);
    }
    public function setFirstNameAttribute($value)
    {
    $this->attributes['first_name'] = strtolower($value);
    }
    }
    38/40

    View Slide

  39. // Laravel 9
    use Illuminate\Database\Eloquent\Casts\Attribute;
    class User extends Model
    {
    public function firstName(): Attribute
    {
    return new Attribute(
    get: fn ($value) => ucfirst($value),
    set: fn ($value) => strtolower($value),
    );
    }
    }
    39/40

    View Slide

  40. 40/40

    View Slide