Laravel 9.18 Released
Published on by Paul Redmond
The Laravel team released 9.18 jam-packed with amazing features and quality-of-life improvements. Let's look at the high-level details of the standout features now available in Laravel 9!
Laravel 9.18.0 is out today. Naturally, it has some *fire* features that I think you'll dig. Let's jump in.
— Taylor Otwell 🪐 (@taylorotwell) June 21, 2022
First, @timacdonald87 introduced a new method that invokes a closure if cumulative time you spend querying the database during a request exceeds a threshold ⌛ pic.twitter.com/TBPA4P6Rx3
Improve file attachments for mail and notifications
Tim MacDonald contributed attachable objects, which you can use to implement attachments with models:
namespace App\Models; use Illuminate\Contracts\Mail\Attachable;use Illuminate\Database\Eloquent\Model;use Illuminate\Mail\Attachment; class Photo extends Model implements Attachable{ /** * Get the attachable representation of the model. * * @return \Illuminate\Mail\Attachment */ public function toMailAttachment() { return Attachment::fromPath('/path/to/file'); }}
When building an email message, you can pass an instance of the model via the attach()
method:
public function build(){ return $this->view('photos.resized') ->attach($this->photo);}
See the new attachable objects documentation for complete details on this beneficial feature!
Invokable validation classes
Tim MacDonald contributed invokable validation classes:
This PR aims to introduce a new class based validation implementation that mixes the brevity + simplicity of Closure based rules with the shareable, extendable, and chainable nature of class based rules by introducing an Invokable validation rule.
Here's an example implementation from Pull Request #42689:
class InvokableQuantity implements InvokableRule{ public function __invoke($attribute, $value, $fail) { if (! is_array($value)) { return $fail('validation.quantity.must_be_an_object')->translate(); } if (! array_key_exists('magnitude', $value)) { $fail('validation.quantity.missing_magnitude')->translate(); } if (! array_key_exists('units', $value)) { $fail('validation.quantity.missing_units')->translate(); } }}
Predis 2.0
Dries Vints contributed support for Predis 2.0. Predis 2.0.0 is a maintenance release, so nothing should break.
Define nested "with" relations via a nested array
Tim MacDonald contributed a way to define nested eager loading relationships via a nested array:
// Using dot notation$books = Book::with('author.contacts')->get(); // Nested array$books = Book::with([ 'author' => [ 'contacts', 'publisher', ],])->get();
Add host methods to the Illuminate Request object
Pull Request #42797 provides three convenience methods on the Illuminate Request instance to access underlying Symphony methods:
$request->host(); // getHost()$request->httpHost(); // getHttpHost()$request->schemeAndHttpHost(); // getSchemeAndHttpHost()
Invokable validation rules can push messages to nested attributes
Tim MacDonald contributed the ability for invokable validation rules to push errors to nested and other attributes:
class UserRule implements InvokableRule{ public function __invoke($attribute, $value, $fail) { if (! is_array($attribute) || array_is_list($attribute)) { return $fail('Must be an object.'); // apply to $attribute } if (! array_key_exists('name', $attribute)) { return $fail("{$attribute}.name", 'Is required.'); // apply to nested attribute } /* ... */ }}
Given the above implementation, here's a usage example:
Validator::make( [ 'user_1' => ['xxxx'], 'user_2' => ['age' => 23], ], [ 'user_1' => [new UserRule()], 'user_2' => [new UserRule()], ]); // errors...[ 'user_1' => ['Must be an object.'], 'user_2.name' => ['Is required.'],]
Introduce fake() helper
Tim MacDonald contributed a global fake()
helper function that allows you to easily access a singleton faker instance. Using this helper is helpful when prototyping, testing, and generating factory and seed data:
@for($i = 0; $i < 10; $i++) <dl> <dt>Name</dt> <dd>{{ fake()->name() }}</dd> <dt>Phone</dt> <dd>{{ fake()->phoneNumber() }}</dd> </dl>@endfor
Here's an example of locale-specific faker usage:
fake()->name() // config('app.faker_locale') ?? 'en_US'fake('en_AU')->name() // en_AU
Cumulative query duration limit callback
Tim MacDonald contributed a callback handler after a cumulative query limit duration:
DB::handleExceedingCumulativeQueryDuration(Interval::seconds(5), function (Connection $connection) { Log::warning("Database queries exceeded 5 seconds on {$connection->getName()}");});
To learn more about this feature, check out the official documentation for cumulative query time. Also, check out Pull Request #42744 for implementation details and discussion around this feature.
Release Notes
You can see the complete list of new features and updates below and the diff between 9.17.0 and 9.18.0 on GitHub. The following release notes are directly from the changelog:
v9.18.0
Added
- Improve file attachment for mail and notifications (#42563)
- Introduce Invokable validation classes (#42689)
- Predis v2.0 (#42577)
- Added
Illuminate/View/Compilers/Concerns/CompilesConditionals::compileReadonly()
(#42717) - Apply where's from union query builder in cursor pagination (#42651)
- Added ability to define "with" relations as a nested array (#42690)
- Added ability to set backoff in broadcast events (#42737)
- Added host(), httpHost(), schemeAndHttpHost() to Request (#42797)
- Allow invokable rules to push messages to nested (or other) attributes (#42801)
- Adds compilePushIf and compileEndpushIf functions to View compiler (#42762)
- Added: Allow removing token during tests (#42841)
- Added predefined_constants to reservedNames array in
Illuminate/Console/GeneratorCommand
(#42832) - Handle collection creation around a single enum (#42839)
- Allow for nullable morphs in whereNotMorphedT (#42878)
- Introduce a fake() helper to resolve faker singletons, per locale (#42844)
- Allow handling cumulative query duration limit per DB connection (#42744)
- Add invokable option to make rule command (#42742)
Fixed
- Fix deprecation error in the route:list command (#42704)
- Fixed Request offsetExists without routeResolver (#42754)
- Fixed: Loose comparison causes the value not to be saved (#42793)
- Fixed: Fix database session driver keeps resetting CSRF token (#42782)
- Fixed: Arr::map - Fix map-by-reference w/ built-ins (#42815)
- Fixed league/flysystem suggest (#42872)
Changed
- Start session in TestResponse to allow marshalling of error bag from JSON (#42710)
- Rename methods in
Illuminate/Broadcasting/BroadcastManager
(753e9fd) - Avoid throwing on invalid mime-type in
Illuminate/Filesystem/FilesystemAdapter::mimeType()
(#42761) - Do not resolve already set headers in
Illuminate/Filesystem/FilesystemAdapter
(#42760) - Standardise invokable rule translation functionality (#42873)
- Clear cast cache when setting attributes using arrow (#42852)