If you work with Laravel PHP framework like me, you have surely done an upgrade to a newer version of Laravel. In this article I want to share an upgrade workflow that I usually do when I upgrade some Laravel app.
The steps that I present here can ensure that you have considered all the customization in your current app, while also taking into account all the modifications that are introduced in the new Laravel version.
Let’s say that we have an app that is currently run on Laravel 5.5.* and that we want to bump it to Laravel 7.*.
Just to note, my dev setup is:
- Windows with WSL (Linux Subsystem)
- Docker (Debian, Apache, PHP)
Steps for upgrade from Laravel 5.5.* to Laravel 7.*
The first thing I do is create the following:
- in the current app repository create a new Git branch from ‘master’ branch. It can be called something like ‘laravel-7-upgrade’. This branch is used to do all code modifications regarding upgrade process, in the current app. When we are ready at the end, we will merge it with the ‘master’ branch. The sample command to do this is:
git checkout master
git checkout -b laravel-7-upgrade
- create a new app which will hold a Laravel 7 base installation. When I say ‘base installation’, I mean installation of Laravel without any custom modifications. We will use this new app to check and sync code between Laravel 5.5.* app and Laravel 7.* app. The result we want is to have our current app and a Laravel 7 app in sync. To create a new Laravel 7 app, create a new Laravel project (of course in a separate directory):
composer create-project --prefer-dist laravel/laravel:7.* laravel-7-base-installation
- create a new app which will hold a Laravel 5.5.* base installation. We will use this app to check the differences between our production Laravel 5.5.* app and a basic Laravel 5.5.* installation. This way we can be sure about all the custom things that we have introduced in the current app.
composer create-project --prefer-dist laravel/laravel:5.5.* laravel-55-base-installation
The next step is to compare the code in the current app to the Laravel 7 base installation, and sync all the changes. While we do this we can also reference the Laravel 5 base installation, so we can be sure about our custom modifications in the current app. Let me show you what I mean.
To do code comparison I use an app called WinMerge. It is an Open Source differencing and merging tool for Windows. It can compare both folders and files, presenting differences in a visual text format that is easy to understand and handle.
Let’s compare our current app with the Laravel 7 installation.
In another WinMerge window, I’ll also do a comparison for current app and a Laravel 5.5 base installation.
Now, let’s take a look in comparison results for Laravel 7 base installation. Note the marked ‘Left only’ result.
The ‘Left only’ means that those two folders exist only in our current app. I will copy those two folders to the Laravel 7 installation, so we can keep track of all the changes we have made when comparing our current installation with Laravel 7 installation. Remember, the final result we want is that the current app and a Laravel 7 app are in sync (that it has same content). To copy selected directories we can use button ‘Copy right’:
This action will place marked directories in the Laravel 7 app. If we refresh the comparison results (press F5 or click refresh button), we will see that they are now marked as ‘Identical’.
Let’s take a look at the next example. We have a ‘Kernel.php’ file with different text.
When we open it, we see the next difference.
The only difference is in one comment. We can safely use the version from Laravel 7, since it is newer. To do this, first we mark the difference and then click on the ‘Copy left’ button.
This will bring the change from Laravel 7 app to the current app. When we save and refresh comparison results, we will again see the Kernel.php file marked as ‘Identical’.
Next case, let’s check out Handler.php file.
Right at the top we see a difference in the ‘use’ statements. The question now is which lines are our custom modifications that we have made in the current app, and which changes are introduced in the Laravel 7 version.
To check our custom modifications, we can compare current app with the Laravel 5.5 base installation. Let’s see a comparison result for the Handler.php file in Laravel 5.5 base installation.
As we can see, our custom modification is that we have used ‘AuthenticationException’ and ‘ValidationException’, so we know that those two lines must stay. Other lines correspond to the Laravel 5.5 base installation, so we can consider changing them.
The sync procedure now is this. I copy right to the Laravel 7 app all custom code. I copy left to the current app all newly introduced code if it doesn’t conflict with current code.
For example, in the new Laravel 7 app, it now has the line ‘use Throwable’ instead of ‘use Exception’. After a brief look at the code, I see that the report() method signature is changed and that it now uses Throwable. The Exception class is never used anymore in this file, so I can be sure to replace ‘use Exception’ with ‘use Throwable’. The result for this difference would be this:
Let’s move down and take a look at other difference in the same file. We have a method report() which now has a different signature.
As we mentioned, it now accepts Throwable parameter instead of Exception. Let’s take a look at the comparison with Laravel 5.5 so we can be sure about our modifications that we have introduced in this file regarding this method.
We can see that the only change is in the body of the method. This means that we have to take the new signature from Laravel 7, and also use our custom code in the method. In this case, despite the new signature, the custom code will still work, since Exception is Throwable. The result for this difference is:
There are still some differences in this file, but to solve them the concept is the same as mentioned in the previous example. Let’s take a look at the next case.
The marked files (new config files) are only available in Laravel 7 app, so we can safely copy them to our current app (copy left).
When it comes to cache files, it actually doesn’t matter which version we choose to keep, since those are generated files.
They will actually be cleared in the end of the procedure, so we can use left or right version just to have them in sync, so they don’t get in our way.
Refreshing Composer and Node packages
Regarding Composer, when it comes to ‘composer.json’ file, in essence you should replace all the packages with the newer version from Laravel 7, and keep all the custom packages in your current app. File ‘composer.lock’ can be deleted, as well as ‘vendor’ directory.
Similar thing is with the file ‘packages.json’ – use newer version packages, and keep custom packages. Directory ‘node_modules’ can be deleted.
After the configuration of composer.json and packages.json file, we can enter the following commands to refresh all the newly included and kept packages. Commands are entered for current app:
File ‘composer.lock’ can now be copied right to the Laravel 7 app, just to have it in sync. Folders ‘vendor’ and ‘node_modules’ can be copied also, or the above-mentioned commands can be run in the Laravel 7 folder.
To clear all the auto generated files in Laravel, we can now enter the following command in the current app:
php artisan optimize:clear
We can also sync this with the Laravel 7, just to have it in sync.
At the end of the procedure of comparing current app with Laravel 7 app, we should have all the folders and files in sync, like this.
Check Laravel upgrade guides
Laravel documentation is good at covering all the changes a new version brings. When upgrading, we should read all the upgrade guides from the version we are upgrading from to the version we are upgrading to.
For example, in our case, we have regularly used ‘str_’ helper functions which were available in Laravel 5.5 https://laravel.com/docs/5.5/helpers#available-methods, and which are now replaced with ‘Illuminate\Support\Str’ class https://laravel.com/docs/7.x/helpers#available-methods. This means we must search for all occurrences of ‘str_’ functions in our code and replace them with corresponding methods available in ‘Str’ class.
If you didn’t already run your Laravel 5.5.* application on higher PHP version, upgrading from Laravel 5.5.* to Laravel 7.* also means upgrading from PHP 7.0 to PHP 7.2 or higher. If this is the case, this means that we should also check upgrade guides for PHP:
Save production state and git commit 🙂
When you have made sure that your app works, you can make your commit for the upgrade. When upgrading, I like to have as few commits as possible, preferably only one 🙂 (as if everything works from single commit :P).
git commit -m "Upgrade to Laravel 7"
git push -u origin laravel-7-upgrade
If you remember, we are on a new branch used for upgrade only. We still have our production state available on the ‘master’ branch. Let’s just keep current production state in a new branch, so we have it available for quick checkout.
git checkout master
git checkout -b pre-laravel-7-upgrade
git checkout master
At this point, since everything works, we can merge the upgrade branch with master and push it to repository.
git merge laravel-7-upgrade