Laravel 9, what's new?!
Tags: php, laravel
Published: 2022-02-21 13:07:00

Laravel and its other first-party packages follow Semantic Versioning. Major framework releases are released every year (~February), while minor and patch releases may be released as often as every week. Minor and patch releases should never contain breaking changes.

When referencing the Laravel framework or its components from your application or package, you should always use a version constraint such as ^9.0, since major releases of Laravel do include breaking changes. However, we strive to always ensure you may update to a new major release in one day or less.

---

## From 8.x to 9.x important changes:
-   php is beginning transition to require function return type.
-   Belongs to many methods (`firstOr...`,  `UpdateOr...`) now comparing against the related model not pivot.
-   They moved from  `swiftMailer`  to  `symfonyMailer`.
-   lang directory have located to project root directory.
-   Use  `current_password`  validation rule instead of  `password`

---

## New features in 9.x:

- Route controller group.
- Anonymous migration class.
- New helper functions.
- Refreshed ignition error page.
- Render blade string.
- Forced scope bindings.
- Laravel scout DB engine.
- Full text indexing.
- Enum attribute casting.
- Simplified accessors and mutators.

> we will discuss every point below:

### Route controller group
If a group of routes all utilize the same [controller](https://laravel.com/docs/9.x/controllers), you may use the `controller` method to define the common controller for all of the routes within the group. Then, when defining the routes, you only need to provide the controller method that they invoke:

    use App\Http\Controllers\OrderController;
    
    Route::controller(OrderController::class)->group(function  () {
    Route::get('/orders/{id}', 'show');
    Route::post('/orders', 'store');
        });

> They don't stop here but also made new console format when listing
> project routes `php artisan route:list`

![enter image description here](https://user-images.githubusercontent.com/5457236/148321982-38c8b869-f188-4f42-a3cc-a03451d5216c.png)

---

### Anonymous migration class
Migration file now not class with name but anonymous one.

    <?php
    ...
    return  new  class  extends  Migration
    {
	    /**
	    * Run the migrations.
	    *
	    * @return  void
	    */
	    public  function  up()
	    {
	    ...
	    });
    }
    
	    /**
	    * Reverse the migrations.
	    *
	    * @return  void
	    */
	    public  function  down()
	    {
	    ...
	    }
    };
---
### New helper functions
 -  `str('__') /** equals to */ Str::of('__');`
and it's good specially in blade as we don't need to use name space qualifier of Str class.
 - `to_route('__'); /** equals to */ redirect()->route('__');`

---

### Refreshed ignition error page
![enter image description here](https://freek.dev/uploads/media/ignition-2022/ignition.png)

---

### Render blade string
Sometimes you may need to transform a raw Blade template string into valid HTML.

    use Illuminate\Support\Facades\Blade;
    
    return  Blade::render('Hello, @if(true) {$name} @endif', ['name'  =>  'Julian Bashir']);

---
### Forced scope bindings
To bind models only belong to another model.

    Route::get('/users/{user}/posts/{post:id}', function(User $user, Post $post){
    ...
    })
we use `post:id` to see if user has this post , if not returns 404 but this can be dis-informative so explicitly:

    Route::get('/users/{user}/posts/{post}', function(User $user, Post $post){
        ...
        })->scopeBindings();
---
### Laravel scout DB engine
Scout package performs full text search, It used to using services but now for small projects we can use our DB engine.

---
### Full text indexing
 - In migration class:
`$table->text('body')->fullText();`
 - When searching:
 `Post::whereFullText('body', '__')->get();`

---

### Enum attribute casting
Eloquent also allows you to cast your attribute values to PHP ["backed" enums](https://www.php.net/manual/en/language.enumerations.backed.php).

    use App\Enums\ServerStatus;
    
    /**
    * The attributes that should be cast.
    *
    * @var  array
    */
    protected  $casts  = [
    'status'  =>  ServerStatus::class,
    ];
also Laravel allows you to type-hint an Enum on your route definition and Laravel will only invoke the route if that route segment corresponds to a valid Enum value. Otherwise, a 404 HTTP response will be returned automatically.

    <?php
   
    namespace App\Enums;
    
    enum  Category:  string 
    {
	    case  Fruits  =  'fruits';    
	    case  People  =  'people';    
    }

---

    use App\Enums\Category;
    use Illuminate\Support\Facades\Route;
    
    Route::get('/categories/{category}', function  (Category  $category) {
	    return  $category->value;    
    });

---
### Simplified accessors and mutators


    <?php
    
    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Casts\Attribute;
    use Illuminate\Database\Eloquent\Model;
    
    class  User  extends  Model    
    {    
	    /**    
	    * Interact with the user's first name.    
	    *    
	    * @param  string $value    
	    * @return  \Illuminate\Database\Eloquent\Casts\Attribute    
	    */    
	    protected  function  firstName():  Attribute
	    {    
		    return  new  Attribute(    
		    get: fn  ($value) => ucfirst($value),    
		    set: fn  ($value) => strtolower($value),    
			 );    
	    }    
    }