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
What's new?
Semantic versioning
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.
Job middleware
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.
Lazy collections
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 subquery enhancements
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();
Improved custom authorization responses
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(); }
Auth0 also provides a simple and quick way to add authorization to your Laravel API.
“Laravel 6.0 is here! Check out what's new and what's changing!”
Tweet This
Laravel UI composer package
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
.New branding
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.
Laravel Vapor
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:
- On-demand scaling - Can execute jobs immediately as they come in
- Powered by AWS
- Ready for bursts of traffic
- Zero downtime during deployment
- Extremely fast
- Multiple environments with free vanity URL for testing (https://snowy-hurricane-12349834324432.vapor.build)
- Maintenance mode
- Searchable logs
- Create and scale your databases from Vapor
- Backup and restore databases
- Metrics and monitoring with notifications
- Purchase domains and manage DNS from Vapor dashboard
- Automatically added SSL certificates
- Jobs, workers, PHP updates, and more are handled behind the scenes
- Deployment easily configured with a simple
filevapor.yaml
The 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.
Upgrading to 6.0
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.
How to upgrade to Laravel 6.0
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
Laravel Shift
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:
- Grant Shift access to your Laravel repository
- Choose what version of Laravel you're on and what you want to upgrade to
- Shift creates a new branch and modifies what needs to be changed in your code
- Shift creates a pull request so that you can test and decide if it should be merged
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.
Do I need to Upgrade?
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.
Aside: Securing Laravel APIs with Auth0
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:
- A solid identity management solution, including single sign-on
- User management
- Support for social identity providers (like Facebook, GitHub, Twitter, etc.)
- Enterprise identity providers (Active Directory, LDAP, SAML, etc.)
- Our own database of users
Sign Up for Auth0
You'll need an Auth0 account to manage authentication. You can sign up for a free account here. Next, set up an Auth0 API.
Set Up an 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.
Dependencies and Setup
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 AUTH0_DOMAIN
, AUTH0_CLIENT_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
Activate Provider and Facade
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 ); }
Configure Authentication Driver
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' ], ],
Secure API Routes
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
access_token
.curl --request GET \ --url http://localhost:8000/api/wakanda \ --header 'authorization: Bearer <ACCESS TOKEN>'
Once a user hits the
api/wakanda
endpoint, a valid JWT access_token
will be required before the resource can be released. With this in place, private routes can be secured.More Resources
That's it! We have an authenticated Laravel API with protected routes. To learn more, check out the following resources:
- Why You Should Always Use Access Tokens to Secure an API
- Laravel backend Quickstart
- Navigating RS256 and JWKS
- Access Token
- Verify Access Tokens
- Call APIs from Client-side Web Apps
- How to implement the Implicit Grant
- Auth0.js Documentation
- OpenID Standard Claims
Recap
Laravel has brought a lot of enthusiasm and excitement to the PHP world and it's been great to see the framework and accompanying products continue to improve.
With the introduction of semantic versioning, you can upgrade between major releases without worrying about huge breaking changes. This switch signifies more than just versioning, it shows that after all the improvements that came in 5.x, the framework is now at a stable point going forward!
In addition to semantic versioning, 6.0 is bringing speed improvements to accessing collections, additions to eloquent subquery selections, the introduction of job middleware, and more.
The full documentation is out now, so take a look if you'd like more information about the new release!
And if you're interested in adding authentication to your Laravel 6.0 application, Auth0 provides an incredibly simple SDK that can be integrated in minutes.
About the author
Holly Guevara
Former Developer Content Manager