Originally published by Holly Lloyd at https://auth0.com
Laravel 6.0 is here!
Taylor Otwell, the creator of Laravel, has been teasing the 6.0 release for a few months now and today it has finally officially dropped. Let's take a look at what's changing and how you can start using it right away.
I plan to show some of the best goodies from Laravel 6.0 in my talk at @LaraconEU. Is there anything else you would like to see me cover on stage? 📣
— Taylor Otwell 🏝 (@taylorotwell) August 26, 2019
Although the jump from 5.8 to 6.0 is a major release, Otwell has mentioned that in terms of new features and changes, this update will feel more like moving from 5.8 to 5.9.
Laravel has had huge updates with every major version release, which is typical in a young framework. All the updates throughout 5.x laid the groundwork for a stable and robust framework. Going forward with 6.0, you won't have to worry as much about huge breaking changes and rewrites with every new major release. Because of this new stability, the Laravel framework package is officially adopting the more traditional semantic versioning.
Instead of manually adding extra boilerplate code around your jobs, you can now extract it into middleware and then just attach it to the job!
This example shows how you could add rate limiting to a job prior to 6.0. You would add it to the job's handle()
method for each job that requires it.
// app/Jobs/JobToBeThrottled.php// Execute the job
public function handle() {
// allow one job to process every 5 seconds
Redis::throttle(‘key’)->block(0)->allow(1)->every(5)->then(function () {
// Handle the job
}, function () {
// Could not obtain lock
return $this->release(5);
});
}
With this new release, we can extract that code out of handle()
and move it into a job-specific middleware. You can create a directory in app/Jobs/Middleware
(or wherever you want, Laravel isn’t opinionated about this) and add a file for the middleware in that folder.
// app/Jobs/Middleware/RateLimited.php
…
namespace App\Jobs\Middleware;
use Illuminate\Support\Facades\Redis;
class RateLimited {
// Process the queued job.
public function handle($job, $next) {
Redis::throttle(‘key’)
->block(0)->allow(1)->every(5)
->then(function () use ($job, $next) {
// Lock obtained
$next($job);
}, function () use ($job) {
// Could not obtain lock
$job->release(5);
});
}
}
Now you can attach this middleware to the job and it will run through the middleware before processing. If you’re familiar with route middleware, this process is very similar.
// app/Jobs/JobToBeThrottled.php
use App\Jobs\Middleware\RateLimited;// get the middleware that the job will use
public function middleware() {
return [new RateLimited];
}public function handle() {
// handle the job
}
This will keep your job files small, easier to read, and focused on their specific task. It will also allow you to easily reuse middleware throughout jobs.
Laravel 6.0 introduces lazy collections, which will allow you to keep memory usage low when dealing with heavy data.
If you’re working with eloquent models, you can choose to load one model into memory at a time instead of everything at once by using the cursor()
method instead of all()
.
// This loads all eloquent models into memory at the same time
// This may be a very large number if you have thousands of posts
$posts = App\Post::all()->filter(function ($post) {
return $post->id > 500;
});
By switching from all()
to cursor()
, only one eloquent model is loaded into memory at a time because cursor()
uses the new LazyCollection
instance.
$posts = App\Post::cursor()->filter(function ($post) {
return $post->id > 500;
});
foreach ($posts as $post) {
echo $post->id;
}
Eloquent has always made it easier to run complex queries. This new release gives you even more help when it comes to running subqueries, or a query within a query, in a single call. This is useful when you need to select information from two tables with a relationship. In Laravel 5.x you were sometimes limited with what you could do in a subquery and would often end up being forced to chain a query using DB::raw()
.
The addSelect
method has been added to subqueries, which should eliminate a lot of that pain! Eloquent subqueries will also now have access to orderBy
.
For this example, imagine you have 2 tables: hotels
and reservations
. You want to know the most recent room type that was booked for a specific hotel. Instead of doing two separate eloquent queries, you can now do this:
use App\Reservation;
use App\Hotel;
return Hotel::addSelect([‘last_booked_room’ => Reservation::select(‘room_type’)
->whereColumn(‘hotel_id’, ‘hotels.id’)
->orderBy(‘created_at’, ‘desc’)
->latest()
->limit(1)
])->get();
If you’re using Laravel’s out-of-the-box authentication with gates for authorization, Laravel 6.0 introduces a new method Gate::inspect
. This makes it easier to provide custom messages to users during authorization requests, such as a specific error message if their request was denied.
For example, say you have the method below that determines if a user is authorized to edit a post. Before 6.0, it was difficult to retrieve this message and display it back to the user.
With the introduction of the Gate::inspect()
method, you can now easily retrieve the full custom response to send back to the user.
If you want to limit the editing of posts to only users who have the role admin, you may have created a gate definition for editing posts.
// App/Providers/AuthServiceProvider.php
…public function boot()
{
$this->registerPolicies();// Define the gate that determines who can edit posts
Gate::define(‘edit’, function ($user) {
return $user->isAdmin
? Response::allow()
: Response::deny(‘You must be an administrator to edit posts.’);
});
}
Normally you would just use the allows
or denies
method to see if that user should be authorized to perform an action. The response depends on the boolean response from the Gate::define
method defined above. The following example will not give you the custom response, just the boolean.
if (Gate::allows(‘edit’)) {
// let the user edit
}if (Gate::denies(‘edit’)) {
// let the user edit
}
If you want to access the more detailed custom denial response, you can now use Gate::inspect
.
// get the full authorization response returned by the gate
$response = Gate::inspect(‘edit’);
if ($response->allowed()) {
// Let the user edit the post
} else {
// Display the denial message
// ‘You must be an administrator to edit posts.’
echo $response->message();
}
“Laravel 6.0 is here! Check out what’s new and what’s changing!”
Another update to be aware of is the extraction of the laravel/ui
package. Front-end scaffolding will still exist, it’s just not included by default. This means in a new Laravel 6.0 application, you won’t see any Vue or Bootstrap scaffolding.
The package now includes presets for React, Vue, and Bootstrap. In a tweet back in May, Otwell mentions that he’s considering adding a Tailwind option as well!
I’ve created https://t.co/IPvq4PdlrV to experiment with extracting Laravel’s front-end scaffolding. Give it a look! Welcome any improvements and will probably explore a @tailwindcss option. 🔥 “artisan ui vue —auth” … “artisan ui react —auth”
— Taylor Otwell 🏝 (@taylorotwell) May 31, 2019
If you’d still like it included, you can bring it back in with composer require laravel/ui
.
With every major release, there has also been new branding that comes along with it, and 6.0 is no exception!
In addition to the new logo above, you can also find a fresh new redesign of the Laravel.com website.
And last but certainly not least, the release of Laravel 6.0 also includes the launch of a much-anticipated product in the Laravel ecosystem - Laravel Vapor.
Before this release, most people used Laravel Forge to provision and deploy their apps. With Forge, you could connect your chosen server (Digital Ocean, AWS, etc.) and Forge would provision it specifically for your Laravel application. This is awesome of course, but you still had to manage updates for yourself.
Laravel Vapor does all of this and more. Instead of managing and updating servers for your Laravel application on your own, Vapor is completely serverless!
This doesn’t mean there are no servers involved, it just means you don’t have to deal with them. Another benefit is that you only pay for what you use. Instead of paying a flat monthly rate, you’re only charged when a request is made to your application. This also means you don’t have to worry about scaling, as it will automatically be done for you.
Here are some more awesome features that Vapor provides:
vapor.yaml
fileThe cost for all of this is $39 per month or $399 per year with unlimited team members and projects. Keep in mind, you still have to pay for your own AWS costs beyond that.
The Laravel documentation estimates it should take about one hour to upgrade from 5.8 to 6.0. Your project may have other dependencies and external packages that can increase that time, so keep that in mind when you decide to upgrade.
In your composer.json
file, change the Laravel framework dependency from 5.8.
to ^6.0
. If you’re on a version earlier than 5.8, it’s recommended to upgrade up to 5.8 before making the switch to 6.0.
// In composer.json
“laravel/framework”: “^6.0”,
Then in your terminal run:
composer update
Another awesome way to manage your upgrades, especially for bigger applications, is to use Laravel Shift. Shift is an automated tool that will do your upgrade for you.
It works like this:
The process is very simple and a great option if simply changing the package version in your composer.json
didn’t work for you. The service isn’t free, but the one-time fee is very low.
You can find the upgrade instructions for 6.0 here.
Laravel 6.0 is the latest Long Term Support release, which means bug fixes will be guaranteed for two years and security fixes for three years. The previous LTS release with these guarantees was Laravel 5.5.
This table from the Laravel website outlines the current support schedule:
With bug fixes for the previous LTS release ending very soon, it may be worth it to upgrade to 6.0 so that you know your project will be supported for a couple more years.
Securing Laravel APIs with Auth0 is very easy and brings a lot of great features to the table. With Auth0, we only have to write a few lines of code to get:
You’ll need an Auth0 account to manage authentication. You can sign up for a free account here. Next, set up an Auth0 API.
Go to APIs in your Auth0 dashboard and click on the “Create API” button. Enter a name for the API. Set the Identifier to a URL(existent or non-existent URL). The Signing Algorithm should be RS256
.
Create API on Auth0 dashboard
We’re now ready to implement Auth0 authentication on our Laravel backend API.
Install the laravel-auth0
package via composer like so:
composer require auth0/login:“~5.0”
Generate the laravel-auth0
package config file like so:
php artisan vendor:publish
After the file is generated, it will be located at config/laravel-auth0.php
. Ensure you replace the placeholder values with the authentic values from the Auth0 Admin Dashboard. Double check your values with laravel-auth0.
Your .env
file should have the AUTH0DOMAIN, AUTH0CLIENT_ID
, AUTH0_CLIENT_SECRET
and AUTH0_CALLBACK_URL
values like so:
AUTH0_DOMAIN=kabiyesi.auth0.com
AUTH0_CLIENT_ID=xxxxxxxxxxxxxxxxxx
AUTH0_CLIENT_SECRET=xxxxxxxxxxxxxxxxx
AUTH0_AUDIENCE=http://mylaravelapi.com
AUTH0_CALLBACK_URL=null
The laravel-auth0
package comes with a provder called LoginServiceProvider
. Add this to the list of application providers
.
// config/app.php
‘providers’ => array(
// …
\Auth0\Login\LoginServiceProvider::class,
);
If you would like to use the Auth0
Facade, add it to the list of aliases
.
// config/app.php
‘aliases’ => array(
// …
‘Auth0’ => \Auth0\Login\Facade\Auth0::class,
);
The user information can now be accessed with Auth0::getUser()
. Finally, you need to bind a class that provides a user (your app model user) each time the user is logged in or an access_token
is decoded. You can use the Auth0UserRepository
provided by this package or you can build your own class.
To use Auth0UserRepository
, add the following lines to your app’s AppServiceProvider
:
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->bind(
\Auth0\Login\Contract\Auth0UserRepository::class,
\Auth0\Login\Repository\Auth0UserRepository::class
);
}
The laravel-auth0
package comes with an authentication driver called auth0
. This driver defines a user structure that wraps the normalized user profile defined by Auth0. It doesn’t actually persist the object but rather simply stores it in the session for future calls.
This is adequate for basic testing or if you don’t have a requirement to persist the user. At any point you can call Auth::check()
to determine if there is a user logged in and Auth::user()
to retreive the wrapper with the user information.
Configure the driver in config/auth.php
to use auth0
.
// app/config/auth.php
// …
‘providers’ => [
‘users’ => [
‘driver’ => ‘auth0’
],
],
Your API routes are defined in routes/api.php
for Laravel 5.3+ apps.
// routes/api.php
<?php
use Illuminate\Http\Request;
/
|--------------------------------------------------------------------------
API Routes |
---|
Here is where you can register API routes for your application. These |
routes are loaded by the RouteServiceProvider within a group which |
is assigned the “api” middleware group. Enjoy building your API! |
*/ |
Route::get(‘/public’, function (Request $request) { |
return response()->json([“message” => “Hello from a public endpoint! You don’t need any token to access this URL…Yaaaay!”]); |
}); |
Route::get(‘/wakanda’, function (Request $request) { |
return response()->json([“message” => “Access token is valid. Welcome to this private endpoint. You need elevated scopes to access Vibranium.”]); |
})->middleware(‘auth:api’); |
Now, you can send a request to your protected endpoint which includes an curl --request GET \ |
--url http://localhost:8000/api/wakanda \ |
--header ‘authorization: Bearer <ACCESS TOKEN>’ |
Once a user hits the Thanks for reading ❤ If you liked this post, share it with all of your programming buddies! Follow me on Facebook |
#laravel #php #web-development