Top 10 Additions to Laravel in 2021
Tags: php, laravel
Published: 2022-01-18 00:02:45

Laravel 9 would be release this January of 2021, Here a top of my favorite additions to the framework during 2021. 

A lot of this features are already available, thankfully the release process now is softer and we can enjoy a lot of this features with minor releases.


## 10 Allow "can" Middleware Chaining in the Route Definition

There is a new `can` method to use instead of a middleware string param:

```php
// instead of this
Route::put('/post/{post}', function (Post $post) {
    // The current user may update the post...
})->middleware('can:update,post');
 
// Using the new can() method
Route::put('/post/{post}', function (Post $post) {
    // The current user may update the post...
})->can('update', 'post');
```







## 9 Conditional Validation Rules

It will validate (pass) a rule when a condition returns `true`:

```php
request()->validate([
    'name' => 'required|string|min:6',
    'password' => [
        'required',
        'string',
        Rule::when(true, ['min:5', 'confirmed'])
    ],
]);
```







## 8 Ignore Trashed Models in Unique Validation Rule

It adds a convenient helper to ignore trashed records:

```php
// Before
[
    'email'=> [
        Rule::unique('users')->whereNull('deleted_at'),
    ],
];
 
// After
[
    'email'=> [
        Rule::unique('users')->ignoreTrashed(),
    ],
];
```







## 7 Support "With Trashed" On Routes

Previously a trashed model was not able to be resolve with route model binding, now by adding this method it is posible:

```php
Route::post('/user/{user}', function (ImplicitBindingModel $user) {
    return $user;
})->middleware(['web'])->withTrashed();
```







## 6 Password Validation Rule Object

Is a very common requirement to validate passwords with multiple rules like has at least one Uppercase, Lowercase, has a symbol, has a number, now it is very easy to implement with Password Rule Object:

```php
<?php
 
$request->validate([
    'password' => [
        'required',
        'confirmed',
        Password::min(8)
            ->mixedCase()
            ->letters()
            ->numbers()
            ->symbols()
            ->uncompromised(),
    ],
]);
```







## 5 Disabling Lazy Loading

With this change the app would throw an exception if there is a model that is not returning eager loading relationships.

It requires to register this change in `AppServiceProvider.php`:

```php
// app/Providers/AppServiceProvider.php
 
public function boot()
{
    Model::preventLazyLoading(! app()->isProduction());
}
```

Now you must use eager loading like this: `$user->with('posts');` or `$user->load('posts')`







## 4 Logging With Context

```php
// Middleware example
 
/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    $requestId = (string) Str::uuid();
 
    Log::withContext([
        'request-id' => $requestId
    ]);
 
    return $next($request)->header('Request-Id', $requestId);
}
```







## 3 Prunable Models

Nuno Maduro adds an amazing feature to the framework, an ability to remove obsolete records by making Laravel models "prunable":

```php
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Prunable; // or MassPrunable
 
class Post extends Model
{
    use Prunable; // or MassPrunable
 
    /**
     * Determines the prunable query.
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function prunable()
    {
        return $this->where('created_at', '<=', now()->subMonth());
    }
}
```

You can choose between `prunable` or `massPrunable` the main difference between both is that `prunable` method would delete a model and fired eloquent model events and `massPrunable` only delete every model that match the condition quietly.







## 2 Enforce Implicit Route Model Scoping

There are cases where you have a nested routes relationship and it would be nice to validate that the second model is child from the first one, now it is available by using `scopeBindings()` method.

```php
Route::get('/posts/{post}/comments/{comment}', function (Post $post, Comment $comment) {
    return $comment;
})->scopeBindings();
```







## 1 Mysql & Postgres FullTextSearch

You can search a term in different columns with this method:

```php
// it search the word Laravel in title and body columns
$post = DB::table('posts')
    ->whereFullText(['title', 'body'], 'Laravel')
    ->get();
```







## Bonus Merge Validated Input

Sometimes we need to "automatically" merge to a request fields some value by default or as a result of a service class, etc... now it is really easy to add:

```php
$validator = Validator::make(
    ['name' => 'Taylor'],
    ['name' => 'required']
);
 
$validator->safe()->merge(['role' => 'Admin']);
 
User::create($validator->safe()->all());
// user would be stored as Taylor and with admin role
```






There are a lot of features that deserves a place here, but for the sake of keep this post short I am going to mention very briefly some of them that you can find useful


- Configurable "Remember me" cookie from config file `config/app.php`

- New AssertIfModelExists Assertion (sugar syntax for `assertDatabaseHas()`)

- Make Model Artisan command new flags (`--test`, `--pest`, `--requests`, etc)

- New Dump TestResponse Methods (`dd()`, `dump()`, `dumpHeaders()`, etc)

- New Status Code Checks (`$response->forbidden()`, `$response->notFound()`, etc ...)

- Validate Multiple Date Formats

- Attribute Cast / Accessor Improvements

- New Design for `routes:list` command


Hopefully it adds more visibility to the new features that we have available in the framework Laravel.

Thanks for reading!