[Part 2/2] Migrating to Symfony 4.0 with Flex
We're over half way through our migration from Symfony 3 to Symfony 4 with Flex.
We're following along with the official Upgrade to Symfony Flex guidance. This video directly follows on from the previous video, so if you haven't already watched that one, then please start there first.
Use the force, Luke Move the src
, Luke
The official Symfony Flex upgrade guidance:
Move the original source code from
src/{App,...}Bundle/
tosrc/
and update the namespaces of every PHP file to beApp\...
(advanced IDEs can do this automatically).
This one sounds quite involved. And it is, depending on your project's size.
Fortunately our project is relatively tiny.
Due to the way we're working, I can open both the old project and the new project inside two separate instances of PhpStorm.
I'm able to copy / paste the folder contents easily in this way. Here's a command line representation of what I am doing:
cp -R \
/home/chris/Development/crv-symfony-4-updates/githut/src/AppBundle/Controller \
/tmp/githut-flex/src
I've split this onto multiple lines for readability.
This is copying the src/AppBundle/Controller
directory contents from the old project to the new.
Likewise, for the src/AppBundle/Service
directory:
cp -R \
/home/chris/Development/crv-symfony-4-updates/githut/src/AppBundle/Service \
/tmp/githut-flex/src
That's basically it for the copy / paste.
What we now need to do is de-bundle.
In other words, replace references of AppBundle\...
with App\...
.
We can do this using a find / replace in PhpStorm. Watch the video for an example.
Important: Also update your service definitions. We haven't done that here, but will do so below.
Our code changes are now complete.
Of course real world projects are more involved than this. I know I'm making this look easier than it will very likely be for you.
Move the templates
The official guidance:
Move the original templates from
app/Resources/views/
totemplates/
andapp/Resources/translations
totranslations/
. There may be a few other files you need to move into a new location.
We don't have any translations.
We do have templates though.
We don't seem to have a templates/
directory, so let's create one:
mkdir templates
And copy everything over:
cp -R \
/home/chris/Development/crv-symfony-4-updates/githut/app/Resources/views/* \
/tmp/githut-flex/templates
Seems easy enough, right?
We'll come back to templates - or more specifically, Twig - shortly.
Make any other change needed by your application
The last piece of official guidance:
Make any other change needed by your application. For example, if your original
web/app_*.php
front controllers were customized, add those changes to the newpublic/index.php
controller.
Sweet, we don't have any worries here.
Final Checks
We've complete all the official steps to migrate to Symfony 4 with Flex.
Let's give our new code a cache:clear
as a quick way to validate everything is behaving:
php bin/console cache:clear
In DefinitionErrorExceptionPass.php line 37:
Cannot autowire service "App\Service\GitHubApi": argument "$httpClient" of method "__construct()" references interface "App\Service\HttpClientIn
terface" but no such service exists. You should maybe alias this interface to one of these existing services: "App\Service\BuzzHttpClient", "App
\Service\GuzzleHttpClient".
Stone the crows.
Ok, so towards the end of the previous video we did copy over all the service
config. However, at the time I mentioned that PhpStorm will likely flag up a fault here.
We need to change the definitions from AppBundle
to App
:
# config/services.yaml
services:
# other stuff removed for brevity
App\Service\HttpClientInterface: '@App\Service\GuzzleHttpClient'
GuzzleHttp\Client: "@eight_points_guzzle.client.8p_guzzle_client"
With this change our quick cache:clear
verification should pass:
php bin/console cache:clear
// Clearing the cache for the dev environment with debug true
[OK] Cache for the "dev" environment (debug=true) was successfully cleared.
Good stuff.
Firing Up Symfony 4
Ok, let's get this show on the road.
All our code is migrated. Before we merge these changes back in, let's fire up our new app and test it out:
php bin/console server:start
[OK] Server listening on http://127.0.0.1:8001
We added the web server bundle back in. This is important. If you missed adding this in then this command will not work.
Ok, so browsing to the site:
http://127.0.0.1:8001/
We see a ... "Welcome" page.
Where the heck is GitHut?
You Need To Add That
The biggest change by far moving from Symfony 2 or Symfony 3 up to Symfony 4 is that very little is included by default.
This can be ... frustrating.
The reason we can't browse to our pages as before is because Symfony currently has no idea about our routes.
Whereas in Symfony 3 annotation routing was the defacto standard, in Symfony 4 we must composer require annotations
to make this work.
php bin/console debug:router
------ -------- -------- ------ ------
Name Method Scheme Host Path
------ -------- -------- ------ ------
And after adding the dep:
$ composer require annotations
Using version ^5.1 for sensio/framework-extra-bundle
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 7 installs, 0 updates, 0 removals
- Installing doctrine/lexer (v1.0.1) Loading from cache
- Installing doctrine/inflector (v1.2.0) Loading from cache
- Installing doctrine/collections (v1.5.0) Loading from cache
- Installing doctrine/cache (v1.7.1) Loading from cache
- Installing doctrine/annotations (v1.6.0) Loading from cache
- Installing doctrine/common (v2.8.1) Loading from cache
- Installing sensio/framework-extra-bundle (v5.1.3) Loading from cache
Writing lock file
Generating autoload files
Symfony operations: 2 recipes (94e3dbafd6174569355f91da114039f9)
- Configuring doctrine/annotations (>=1.0): From github.com/symfony/recipes:master
- Configuring sensio/framework-extra-bundle (>=4.0): From github.com/symfony/recipes:master
Executing script cache:clear [OK]
Executing script assets:install --symlink --relative public [OK]
$ php bin/console debug:router
--------- -------- -------- ------ ------------------------
Name Method Scheme Host Path
--------- -------- -------- ------ ------------------------
another ANY ANY ANY /another/{thing}/{and}
githut ANY ANY ANY /{username}
profile ANY ANY ANY /profile/{username}
repos ANY ANY ANY /repos/{username}
--------- -------- -------- ------ ------------------------
Hoorah, our routes are back.
Now we can browse to our site, right?
Whoops, looks like something went wrong
Refreshing the page should work.
But it doesn't.
(1/1) LogicException
You can not use the "render" method if the Templating Component or the Twig Bundle are not available.
Oh yeah, Twig isn't included anymore.
We must add it.
composer require symfony/twig-bundle
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 3 installs, 0 updates, 0 removals
- Installing twig/twig (v2.4.4) Loading from cache
- Installing symfony/twig-bridge (v4.0.2) Downloading: 100%
- Installing symfony/twig-bundle (v4.0.2) Downloading: 100%
Writing lock file
Generating autoload files
Symfony operations: 1 recipe (d75b639d694c496445f2e3d2d4301cd0)
- Configuring symfony/twig-bundle (>=3.3): From github.com/symfony/recipes:master
Executing script cache:clear [OK]
Executing script assets:install --symlink --relative public [OK]
The reasoning behind this is because not every project needs Twig.
If you're making a JSON API then you don't need to render HTML.
Less dependencies = smaller projects = fewer bugs.
But still, the User Experience here is challenging for beginners, in my opinion.
Ok, onwards.
We have Twig, now let's refresh:
Twig_Error_Syntax
Unknown "asset" function.
Again, we hit on another 'thing' we don't have any longer.
The fix is simple, if a little laborious:
composer require symfony/asset
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
- Installing symfony/asset (v4.0.2) Downloading: 100%
Writing lock file
Generating autoload files
Executing script cache:clear [OK]
Executing script assets:install --symlink --relative public [OK]
For what it's worth, it might be worth your time investigating Symfony Encore at this point.
Our Own Problems
We kinda glossed over the earlier template changes because I deliberately wanted to hit upon all these issues.
Now though, we must do a little further template tweaking because:
An exception has been thrown during the rendering of a template ("The "AppBundle" (from the _controller value "AppBundle:GitHut:profile") does not exist or is not enabled in your kernel!").
We still have some left over references to AppBundle
in our templates.
These need changing quite significantly:
<!-- templates/githut/index.html.twig -->
{% extends 'base.html.twig' %}
{% block body %}
<div class="col-sm-3">
{{ render (controller('App\\Controller\\GitHutController::profileAction', { 'username': username })) }}
</div>
<div class="col-sm-9">
{{ render (controller('App\\Controller\\GitHutController::reposAction', { 'username': username })) }}
</div>
{% endblock body %}
And a further change:
Unable to find template ":githut:repo.html.twig" (looked into: /tmp/githut-flex/templates, /tmp/githut-flex/templates) in githut/repos.html.twig at line 17.
This needs the include
syntax updating:
# templates/githut/repos.html.twig
- <li class="list-group-item">{% include ':githut:repo.html.twig' %}</li>
+ <li class="list-group-item">{% include 'githut/repo.html.twig' %}</li>
Fixing the CSS
Our page now loads.
But it has a CSS issue.
Namely our custom CSS - mystyle.css
is 404
.
To fix this we need to copy the old contents from web/css/mystyle.css
to public/css/mystyle.css
.
It's as easy as that.
And finally, the Rock has come back to... no wait, that's not it. Finally, our web page loads and looks right. And it's on Symfony 4.
I truly hope at this point you can smell what the Rock is cookin'.
All that remains here is to move the new code into the old code repo.
Stop It And Tidy Up
Stop the running web server:
php bin/console server:stop
[OK] Stopped the web server.
Then I'm going to create a new branch in my old repo:
cd /home/chris/Development/crv-symfony-4-updates/githut
git checkout -b flex
Ready to go crazy?
rm -rf ./*
ls -la
total 20
drwxrwxr-x 4 chris chris 4096 Dec 16 11:38 .
drwxrwxr-x 3 chris chris 4096 Dec 9 20:41 ..
drwxrwxr-x 8 chris chris 4096 Dec 16 11:38 .git
-rw-rw-r-- 1 chris chris 288 Dec 16 09:13 .gitignore
drwxrwxr-x 3 chris chris 4096 Dec 16 11:34 .idea
All I have left now is the git root, any hidden files (.
/ dot files), and the .idea
hidden directory (PhpStorm thingy).
Now I'm going to copy all the flex project stuff into my new / old directory (depending on your point of view).
Before doing this, be sure to delete the .git
folder from your Flex project directory. This is very likely going to cause you major headaches if you accidentally copy this directory over the top of your real git directory.
# remove the flex git repo first
rm -rf /tmp/githut-flex/.git
cp -R \
/tmp/githut-flex/* \
/home/chris/Development/crv-symfony-4-updates/githut
# and again for hidden files
# there may be a better way to do this
cp -R \
/tmp/githut-flex/.* \
/home/chris/Development/crv-symfony-4-updates/githut
PhpStorm will need to re-index everything to be happy.
But at this point you are done. The migration is complete. It's time to reward ourselves with a biscuit and a cup of tea, and then as is always the case with software development, get started on the next major crisis :)