New Features in Laravel 5.5
- Transfer
The new release of Laravel 5.5 will be the release of long-term support (Long Term Support, LTS). This means that he will receive bug fixes for 2 years, and security updates for 3 years. The release of Laravel 5.1 was the same, but its two-year edits are coming to an end this year. Let's see without any fuss what awaits us in the new version.
Create a new project on Laravel 5.5
Since the new release has not yet been officially released, we can still download the dev release using the following command:
laravel new laravel55 --dev
cd laravel55
php artisan key:generate
If you do not like Laravel installer, you can use the composer command:
composer create-project --prefer-dist --stability=dev laravel/laravel:dev-master
cd laravel
php artisan key:generate
When we go to the home page of the new application, we should see a welcome page similar to the one in previous versions of Laravel.
Render Mailables in a browser
I think this feature will be very useful. In previous versions of Laravel, we had to send real letters or use an email client like Mailtrap to test the newsletter, and the task was not the most fun. No more suffering, in Laravel 5.5 you can now render a message template directly in the browser.
Here is a quick way to do this: create a new mailable and a letter template for our project:
php artisan make:mail Welcome --markdown=emails.welcome
I prefer to use the markdown format, since we get the template with some content already. Open the file web.php
and create a test route to check the letter template:
Route::get('/email', function(){
returnnew App\Mail\Welcome();
});
routes / web.php
If we go to route / email, we can see the letter template:
In fact, the following happens. In Laravel 5.5, the 'Mailable' class uses the 'Renderable' contract with the 'render ()' method. Here is the implementation of the render method in 'Illuminate / Mail / Mailable.php':
publicfunctionrender(){
Container::getInstance()->call([$this, 'build']);
return Container::getInstance()->make('mailer')->render(
$this->buildView(), $this->buildViewData()
);
}
Illuminate / Mail / Mailable.php
With this method you can get view. If we tried to return an instance of a class that does not apply the 'Renderable' contract inside our routes, we would get a 'UnexpectedValueException'.
Custom emails
If you use Markdown to format letters, then Laravel will put the default subject. However, someone may need their own styles to promote their brand.
To make custom design for a specific mailable, first create a custom '.css' file with the styles we need:
touch resources/views/vendor/mail/html/themes/custom.css
Then we specify the name of this file as a characteristic of the Mailable class:
classWelcomeextendsMailable{
protected $theme = 'custom';
[...]
}
app / Mail / Welcome.php
Thus, the letter template will be based on the styles that we specified in the file custom.css
. What is especially pleasing is that we can set different styles for different mailables.
Helper Exception Functions
Laravel 5.5 includes two helper exception functions that help us create more expressive code. These are the methods throw_if
and throw_unless
. Both include three arguments, with a third optional.
Let's see how these exceptions can be applied:
$number = 2;
throw_if($number !== 3, new NotThreeException('Number is not three'));
// or
throw_if($number !== 3, NotThreeException::class, 'Number is not three');
If you use the helper function 'throw_if', an exception will be thrown provided that the first argument is regarded as true.
If used throw_unless
, it will essentially be the same, with the only difference being that an exception will be thrown if the first argument is false.
$number = 2;
throw_unless($number === 3, new NotThreeException('Number is not three'));
// or
throw_unless($number === 3, NotThreeException::class, 'Number is not three');
Not a good example, but suitable for demonstration.
Migrate: fresh command
You probably found yourself in a situation where you had to restore the database. In previous versions of Laravel, this could be done using the command php artisan migrate:refresh
. The command migrate:refresh
rolls back all migrations based on what is described in the down method of each migration file, and then starts the migrations again.
But you may have had problems with this command a couple of times, especially when working with foreign key constraints or when one of the 'down ()' methods in any of your migrations was not defined sufficiently. When this happens, in most cases we manually get rid of the table that is having problems - (perhaps using the CLI or some GUI). That's when the team migrate:fresh
rushes to the rescue. This command deletes all tables, and then starts existing migrations again:
Stack Trace JSON Errors
Not the biggest change, but in previous versions of Laravel, we saw HTML markup from an API client like Postman every time an error occurred in our APIs. In Laravel 5.5, in case of an error, we get not HTML markup, but a trace in JSON, which is easier to understand:
Automatic package installation
To use a third-party package in our Laravel projects, we do the following:
- Install the package.
- Register the service provider of the package.
- Register facades, if any.
As you can see, the procedure can be simplified. Now it will be as follows.
With the automatic installation of packages, we simply select the desired package and put it on the fly. I note, however, that this is possible only if the package provider has configured it accordingly.
If we look at the Laravel Debugbar package, for which auto-installation is already configured, we will see that composer.json
there is a section inside the file extra
:
"extra": {
"laravel": {
"providers": [
"Foo\\Bar\\ServiceProvider"
],
"aliases": {
"Bar": "Foo\\Bar\\Facade"
}
}
}
Package providers will need to add the extra section to the file composer.json
, and then specify the service providers and any aliases for the package.
Another plus of auto-installing packages is that if you remove the dependency, then nothing will break. Usually, even after the package has been demolished, its service providers and facades still stick out in the file config/app.php
, and in some cases errors can occur due to them.
With automatic installation, if you remove a package through Composer, then everything related to this package is also deleted.
Changes to vendor: publish command
In previous versions of Laravel, the team vendor:publish
published the resources of all the packages and the framework itself. Some of these resources include migrations, views, and configs.
In Laravel 5.5, you need to clarify in detail what exactly we want to publish with this command. If we run the team php artisan vendor:publish
without any flags, we will be required to choose a provider or tag to make it easier to publish only what we want. See screenshot below:
We can get around this step by specifying a label --all
or --provider
by running the command publish
:
php artisan vendor:publish --all
Variety of front-end presets
In Laravel 5.3 and 5.4, we had some Vue and Bootstrap presets by default, which simplified front-end development. In the new version, React was added to this kit. However, he does not stand there by default.
The new artisan team helps manage front-end presets. We will only have the workpiece that we need for the preset with which we want to work. But not everyone is happy with the default presets, Vue, Bootstrap, and React; someone may need something else. Perhaps another front-end framework. And Laravel already took care of this:
php artisan preset none
This command will delete all existing front-end blanks. If we wanted to use React, the following command will help us with the preparation:
php artisan preset react
Below is this new team in action:
Whoops is back!
Whoops is back in Laravel 5.5! with a new way to display errors. Now, if there is an error during development, we will be able to see this line of code as a screenshot along with the error message. In my opinion, the error message now looks better, and the fact that we now receive a screenshot with an incorrect line of code makes it easier to correct errors.
Example error with Whoops:
Another cool trick is that Whoops now allows you to open specified files directly in your IDE or editor. This function only works if you have local access to PHP files on the machine on which the editor is installed. To configure it, open app / Exceptions / Handler.php and add this snippet:
[...]
useIlluminate\Filesystem\Filesystem;
useIlluminate\Support\Arr;
useWhoops\Handler\PrettyPageHandler;
[...]
classHandlerextendsExceptionHandler{
[...]
protectedfunctionwhoopsHandler(){
return tap(new PrettyPageHandler, function($handler){
$files = new Filesystem;
$handler->setEditor('sublime');
$handler->handleUnconditionally(true);
$handler->setApplicationPaths(
array_flip(Arr::except(
array_flip($files->directories(base_path())), [base_path('vendor')]
))
);
});
}
}
app \ Exceptions \ Handler.php
This snippet cancels the method of the whoopsHandler()
main class using a line $handler->setEditor('sublime')
, thanks to which the link opens in Sublime Text. If you are using another editor, check out the github article for a list of all supported editors and instructions on how to add your own. If you have a Mac, be sure to download the sublime URL protocol for this to work.
Report Method of Custom Exceptions
In previous versions, if we wanted to configure custom exceptions in some special way, we had to place them inside the report method in the Handler.php file. For example, like this:
[...]
publicfunctionreport(Exception $exception){
if ($exception instanceof CustomException) {
// Do something
}
if ($exception instanceof MyOtherException) {
// Do something
}
if ($exception instanceof MyOtherCustomException) {
// Do something
}
returnparent::report($exception);
}
[...]
app / Exceptions / Handler.php
If we have, for example, 50 major exceptions, then this file will turn into something terrible. In Laravel 5.5, to indicate what happens in the case of a custom exception, you can create a report()
method inside the exception:
[...]
classCustomExceptionextends\Exception
{
public function report()
{
// send email
}
}
[...]
app / Exceptions / CustomException.php
Model Factory Generators
Laravel 5.5 introduced a new team to create a model factory. The model factory is very convenient when we need to generate fake data or a new object for tests.
To create a factory for a particular class, run the command:
php artisan make:factory Post
Now if we open the database / factories, we will see the PostFactory class:
[...]
$factory->define(App\Post::class, function(Faker $faker){
return [
//
];
});
database / factories / PostFactory.php
I think this is a more elegant approach, because we share responsibility. In previous versions of Laravel, all factories were located within the same file app/factories/ModelFactory.php
.
Return Validated Data
Now it is possible to get data from the validator and pass it to the method create
. In previous versions of Laravel, we created new objects like this:
{
$this->validate(request(), [
'title' => 'required',
'body' => 'required'
]);
// return Post::create(request()->only(['title', 'body'])); orreturn Post::create(request()->all());
}
In Laravel 5.5, you can now create objects directly from validated data:
publicfunctionstore(){
$post = $this->validate(request(), [
'title' => 'required',
'body' => 'required'
]);
return Post::create($post);
}
You can also call the command validate
directly from request:
publicfunctionstore(){
$post = request()->validate([
'title' => 'required',
'body' => 'required'
]);
return Post::create($post);
}
I note, however, that you need to be careful when you create objects in this way, since any attribute that you leave outside the validation method will not matter. To deal with this problem, we pass all the attributes that we want to create inside the validation method for this object, even if their values do not require any validation:
$post = request()->validate([
'title' => 'required',
'body' => 'required',
'notRequiredField' => '',
]);
return Post::create($post);
Thus, this field is automatically added to the allowed request data, but it is not limited to any validation rules.
Custom Validation Rules
In previous versions of Laravel, they could be set using the method Validator::extend
. But there was no centralization. We added the rule to the file AppServiceProvider
, and then the message to the file inside the resources/lang/en/validation.php
. The Laravel documentation details how this is done in version 5.4.
In Laravel 5.5, we have a new artisan team that defines custom validation. This command creates a new class that implements the contract Rule
. Let's create a new rule to see what's inside:
php artisan make:rule CustomRule
If you look in app/Rules/CustomRule.php
, we will see two methods - a method passes
and a method message
. The method passes
takes 2 parameters, i.e. attribute
and value
, and returns boolean. If you are confused, $attribute
this is the field that needs to be validated, and $value
is the real value that is passed to the attribute.
Suppose, for example, that we do not want to give any specific name to the user. Then our rule will look like this:
{
[...]
publicfunctionpasses($attribute, $value){
return $value !== 'unwantedname';
}
publicfunctionmessage(){
return'You cannot use that as your username';
}
[...]
}
app / Rules / CustomRule.php
Then we use the new rule to validate the attribute username
:
useApp\Rules\CustomRule;
request()->validate([
'username' => [
'required',
new CustomRule()
],
'anotherfield' => 'required|min:5'
]);
app / Rules / CustomRule.php
How custom validation is defined in the new version of Laravel is described in detail in the article by Taylor Otwell .
Added DD and Dump to the collection
Now the dump () and dd () methods are included in the collections. In previous versions of Laravel, when we debugged collections, we assigned a collection variable and then dumped it as the collection changed. In Laravel 5.5, you don’t have to do this anymore, since we can now call a command dd()
or dump()
directly from the collection, which makes debugging much easier.
Suppose we have a collection of posts that have undergone a number of changes, and we need to inspect the collection at every step. Then do the following:
$posts = Post::all();
$posts
->dump()
->sorBy('title')
->dump()
->pluck('title')
->dump();
The output is:
Collection {#284 ▼#items: array:3 [▼0 => Post {#285 }1 => Post {#286 }2 => Post {#287 }
]
}
Collection {#272 ▼#items: array:3 [▼0 => Post {#285 }2 => Post {#287 }1 => Post {#286 }
]
}
Collection {#268 ▼#items: array:3 [▼0 => "Aida Bosco"1 => "Madge Leuschke"2 => "Miss Bulah Armstrong Jr."
]
}
This makes it easier to inspect the contents of the collection at every step. However. Note that between the teams dump()
and dd()
there is a difference. dump()
gives the result at the moment, and then continues to work, while it dd()
immediately stops the process and dumps the results (dd means dump and die, reset and die). If we called dd()
from the collection at every step, then we would only get the result at the very first point when we called dd()
from the collection. Take a look:
366666
$posts = Post::all();
$posts
->dump()
->sorBy('title')
->dd()
->pluck('title')
->dump();
At the output, we get another:
Collection {#284 ▼#items: array:3 [▼0 => Post {#285 }1 => Post {#286 }2 => Post {#287 }
]
}
array:3 [▼
0 => Post {#285 }2 => Post {#287 }1 => Post {#286 }
]
Castes in many-to-many intermediate tables
It is usually possible to declare a casts property of the Model, which determines how the attribute should be stored and read. Suppose we have a Post model, and we want one of the fields to be serialized in JSON when reading and writing. The following code snippet will help us with this:
classPostextendsModel{
[...]
protected $casts = [
'somefield' => 'array',
];
[...]
}
You could already cast custom pivots into a many-to-many relationship in version 5.4, but the data could only be read. If we wanted to perform data write operations, we would first have to manually cast the attribute values and only then save. Now we must do so more as a property casts
in the classroom Eloquent\Model
and Eloquent\Relations\Pivot
will behave the same way, allowing you to use methods attach
, sync
and save
models pivot.
Custom Blade :: if () directives
Long, repeating check code in blade templates can make them ugly. The good news is that it is now possible to extract duplicate validation code from templates, which makes them cleaner and more readable. Checks like these:
@if (auth()->check() && auth()->user()->isSubscribed())
<p>Subscribed</p>
@else
<p>Not Subscribed</p>
@endif
Can be replaced by:
@subscribed
<p>Subscribed</p>
@else
<p>Not Subscribed</p>
@endsubscribed
The logic for creating a custom blade directive is added to the boot
class method AppServiceProvider
:
[...]
useIlluminate\Support\Facades\Blade;
classAppServiceProviderextendsServiceProvider{
[...]
publicfunctionboot(){
Blade::if('subscribed', function(){
return auth()->check() && auth()->user()->isSubscribed();
});
}
[...]
}
app / Providers / AppServiceProvider.php
For some checks, you may need to pass some method to the argument. In this case, we pass the argument to the closure when it comes to the custom blade directive.
@if (auth()->check() && auth()->user()->isFollowing($user->id))
If we use this condition as an example, then we see what needs to be passed to the $user->id
method isFollowing()
. To create a custom blade directive that takes $user->id
as an argument, do the following:
Blade::if('following', function(User $user){
return auth()->check() && auth()->user()->isFollowing($user->id)
});
Then, to use this new directive in our templates:
@following($user)
<p>Following</p>
@else
<p>NotFollowing</p>
@endfollowing
Auto-registration of new artisan teams in Kernel
Usually we create new artisan commands using the command php artisan make:command command-name
. After that, we assign a key inside the class with the command, go to Kernel and manually register the command.
It is no longer necessary to register new teams at Kernel. We now have a app/Console/kernel.php
new method inside the file that tracks the command directory and turns all file paths into namespaced paths:
[...]
protectedfunctioncommands(){
$this->load(__DIR__.'Commands');
require base_path('routes/console.php');
}
[...]
Suppose we called a command that is not yet registered in the kernel. The commands () method will automatically connect it.
New Route Methods
This is not the coolest new feature, but it’s worth mentioning that now we have two additional route methods:
Route::view('/welcome', 'welcome');
Route::redirect('home', 'dashboard');
The first binds the welcome view to the / welcome path, and the second redirects requests /home
to /dashboard
.
Introducing Laravel Horizon
This is the new Laravel package that provides a dashboard and code-driven configuration system for Laravel Redis queues:
Horizon displays real-time queue loads, recent tasks, failed tasks, task restart attempts, throughput and runtime metrics, and the number of processes.
Among the features of Horizon are the following:
- High-level analytics for tasks - such indicators as the number of tasks per minute and tasks for the past hour
- Analytics specific to specific tasks and queues.
- Tags and monitoring - you can add tags to tasks, as well as monitor specific tags.
- Recent Tasks - You can get information about the most recent tasks.
- Queue balancing strategies - Horizon can automatically distribute queue worker processes across all queues depending on their load.
Taylor Otwell in his article discusses in detail how to configure Horizon and all the functions that are included in it.
New Database Migration Trait
This is a trait RefreshDatabase
. Some might wonder why it was needed at all, but the reasons behind it make sense. Initially, we had traits DatabaseMigrations
and DatabaseTransactions
.
Using the trait DatabaseMigrations
in tests helps to ensure that migrations are performed before and after each test, and the trait DatabaseTransactions
allows you to be sure that the database is restored to its original state after each test.
The trait RefreshDatabase
combines these two functions, as the database migrates once at the beginning of the tests, and then wraps each test after that in the transaction. The advantage is that we do not need to re-migrate the database for each test, which means that the tests will pass faster.
Conclusion
As you can see, the new version will have a lot of cool new features. However, there has not yet been an official release, so you have to wait until the instructions for the update are published.
Write your thoughts and suggestions in the comments and do not forget to share the link to the article with other developers on Laravel!