The latest version of Laravel, version 5.8, has recently been released. This version has many exciting new features and it is a continuous improvement of previous versions of Laravel. These features include:
- Automatic policy resolution
- Carbon 2.0 support
- Has-one-through Eloquent relationships
- Token guard token hashing
- Cache TTL
- Scheduler timezone configuration
Artisan::call
improvements- Artisan serve improvements
- Mock testing helper methods
- Higher order
orWhere
Eloquent method
And many more. In this article, I will discuss some of these new features in greater depth.
1. Automatic policy resolution
Policies are one of two primary ways Laravel handles user authorization. They are classes that organize authorization logic around a particular model or resource. In the previous version of Laravel, policies needed to be registered in the AuthServiceProvider
as follows:
<?php
namespace AppProviders;
use AppPost;
use AppPoliciesTransactionPolicy;
use IlluminateSupportFacadesGate;
use IlluminateFoundationSupportProvidersAuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
Transaction::class => TransactionPolicy::class,
];
/**
* Register any application authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
//
}
}
In this case, the policy we are registering is a policy called TransactionPolicy
, which we are entering into the $policies
array.
However, starting in Laravel 5.8 you do not need to manually register a model’s authorization policy. Laravel can auto-discover policies as long as the model and policy follow standard Laravel naming conventions and the policy directory is in its default location.
If you have models or policies in locations different from the default Laravel structure, you can register a custom callback using the Gate::guessPolicyNamesUsing
method. Typically, this method should be called from the boot method of your application’s AuthServiceProvider
like this:
use IlluminateSupportFacadesGate;
Gate::guessPolicyNamesUsing(function ($modelClass) {
// return policy class name...
});
2. Carbon 2.0 support
Carbon is a package that extends PHP’s own DateTime class and makes working with dates and time very easy. Laravel 5.8 provides support for the 2.0
release of Carbon. Among the new features of Carbon 2.0
is the CarbonImmutable
class and a new Date
facade. Let’s see how this works.
Enter the following in the routesweb.php
file of a Laravel 5.8 installation:
use CarbonCarbon;
Route::get('carbon', function () {
$date = Carbon::now();
dump($date);
$date->addDays(3);
dump($date);
});
Here we are creating a route carbon
which would save the current date in a $date
variable and then display it. It then adds three (3) days to the current date and also displays it. If you visit the /carbon
route we have just created, you would see something like:
What is happening here is that we are changing our object. This may be what you desire, but in many cases, this is not what we want, as dates are usually protected
properties. We should actually be able to create a new date and not modify an existing date. For example say we are storing a date of birth in one of the columns of our database, this is not information that is going to change, however, we may create a copy for it and do some modifications to that copy. This is where the CarbonImmutable
class comes in. To use this feature, go to your AppServiceProvider
and enter the following:
// ...other includes
use IlluminateSupportDateFactory;
use CarbonCarbonImmutable;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
DateFactory::use(CarbonImmutable::class);
}
}
Then update the routesweb.php
file to use the new Date
facade and create a copy of the date which we can change:
use IlluminateSupportFacadesDate;
Route::get('carbon', function () {
$date = Date::now();
dump($date);
$newDate = $date->copy()->addDays(7);
dump($newDate);
});
Refresh your browser and you should see this:
3. HasOneThrough eloquent relationship
Laravel 5.8 introduces a new eloquent relationship: HasOneThrough
. Though this is new in Laravel, it exists in other frameworks like Rails. Say we have three models: a Supplier
model an Account
model and an AccountHistory
model. A supplier has an account and an account has one account history.
Previously to get a supplier’s account history, you will have to find the supplier then write something like: $supplier->account->accountHistory
. Now you may use a hasOneThrough
relationship to skip this step, accessing a supplier’s account history straight away like this: $history = $supplier->accountHistory
through the account model:
public function accountHistory()
{
return $this->hasOneThrough(AccountHistory::class, Account::class);
}
4. Token guard token hashing
A little known fact about Laravel API authentication is that you don’t always have to use Laravel Passport. There is a simpler token guard which provides basic API authentication and in Laravel 5.8 it now supports storing tokens as SHA-256 hashes. This provides greater security over storing plain-text tokens.
5. Cache TTL
In previous versions of Laravel, caching was set in minutes. This has changed in version 5.8, to seconds for more precise and granular setting for expiration time when storing items and provide compliance with the PSR-16 caching library standard. So in any reference to cache in your application remember to update to seconds:
// Laravel 5.7 - Store item for 5 minutes...
Cache::put('foo', 'bar', 10);
// Laravel 5.8 - Store item for 5 seconds...
Cache::put('foo', 'bar', 10);
6. Scheduler timezone configuration
In Laravel you can define your timezone for a scheduled task using the timezone
method like this:
$schedule->command('run')
->daily()
->at('15:00')
->timezone('America/Chicago');
In previous releases, you have to repeat this for every scheduled task and this can quickly become cumbersome if you have many of them. In Laravel 5.8 you can just define a method called scheduledTimezone
in your app/Console/kernel.php
file and return your default timezone. This will be attached to every scheduler you have:
/**
* Get the timezone that should be used by default for scheduled events.
*
* @return DateTimeZone|string|null
*/
protected function scheduleTimezone()
{
return 'America/Chicago';
}
7. Artisan call improvements
Laravel allows you to make Artisan commands from your code using the Artisan::call
method. In previous versions of Laravel, if you need to pass some options to the command you typically do this:
use IlluminateSupportFacadesArtisan;
Artisan::call('migrate:install', ['database' => 'foo']);
Now in 5.8, instead of passing the options as an array, you can pass it in one single string like this:
Artisan::call('migrate:install --database=foo');
8. Artisan serve improvements
A way to quickly serve your Laravel application is by running the command php artisan serve
. In previous versions of Laravel this command will run your application in a default port of 8000
and if you attempt to serve another application with the same command, this would fail. Now in version 5.8 the serve
command will scan for available ports up to port 8009
so you can serve multiple applications at once.
9. Mock testing helper methods
This is another improvement to make your test code cleaner and readable. Say we want to mock a transaction service and have it return some dummy transaction data. In previous versions of Laravel we would write something like this:
public function testBasicTest()
{
$service = Mockery::mock(TransactionService::class, function ($mock) {
$mock->shouldReceive('find')->once()->with()->andReturn(['id' => 1, 'name' => 'foo']);
});
$this->instance(TransactionService::class, $service)
}
In Laravel 5.8 this can be shortened to:
public function testBasicTest()
{
$this->mock(TransactionService::class, function($mock){
$mock->shouldReceive('find')->once()->with(1)->andReturn(['id' => 1, 'name' => 'foo'])
});
}
This takes care of calling Mockery
and binding it into the container. Notice we don’t have to call $this->instance
10. Higher order orWhere eloquent method
Previously if we wanted to combine scoped query with or
, we typically would define a closure like this:
// scopeActive and scopeEmailVerified methods defined on the User model...
$users = AppUser::emailVerified()->orWhere(function (Builder $query) {
$query->active();
})->get();
Laravel 5.8 introduces a “higher order” orWhere
method, so you don’t need to write the above closure anymore. Instead, you can write this:
$users = AppUser::emailVerified()->orWhere->active()->get();
Conclusion
This new version of Laravel comes loaded with many exciting features and we have gone through some of the most notable improvements in the framework. For details on how to upgrade your existing Laravel application to version 5.8, see the upgrade guide. What are your thoughts on Laravel 5.8? Let me know in the comments section!