Getting Started With Symfony 4
Symfony 4 is here. There's no better time to start learning. Let's get right into it.
We're going to create our project using the symfony/website-skeleton
.
This is a close approximation to what you might have had should you have installed the Symfony Standard Edition back in Symfony 2 or Symfony 3.
This is different to the symfony/skeleton
which is more minimal, and doesn't include things like Twig, Doctrine, or Monolog.
If you're not creating a full blown website - maybe you're creating a console application, or simple API, you should probably start with that skeleton
.
However, we are creating a web site, so let's use the website-skeleton
as our starting point:
composer create-project symfony/website-skeleton lets-explore-symfony-4
Installing symfony/website-skeleton (v4.0.3)
- Installing symfony/website-skeleton (v4.0.3) Downloading: 100%
Created project in lets-explore-symfony-4
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 88 installs, 0 updates, 0 removals
- Installing ocramius/package-versions (1.2.0) Loading from cache
- Installing symfony/flex (v1.0.61) Downloading: 100%
Prefetching 9 packages
- Connecting (100%)
- Downloading (100%)
- Installing doctrine/lexer (v1.0.1) Loading from cache
- Installing doctrine/inflector (v1.3.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 symfony/polyfill-mbstring (v1.6.0) Loading from cache
- Installing symfony/http-foundation (v4.0.3) Loading from cache
- Installing symfony/yaml (v4.0.3) Loading from cache
- Installing symfony/webpack-encore-pack (v1.0.2) Loading from cache
- Installing psr/link (1.0.0) Loading from cache
- Installing fig/link-util (1.0.0) Loading from cache
- Installing symfony/web-link (v4.0.3) Loading from cache
- Installing symfony/filesystem (v4.0.3) Loading from cache
- Installing symfony/config (v4.0.3) Loading from cache
- Installing symfony/http-kernel (v4.0.3) Loading from cache
- Installing symfony/event-dispatcher (v4.0.3) Loading from cache
- Installing psr/log (1.0.2) Loading from cache
- Installing symfony/debug (v4.0.3) Loading from cache
- Installing psr/container (1.0.0) Loading from cache
- Installing symfony/dependency-injection (v4.0.3) Loading from cache
- Installing egulias/email-validator (2.1.3) Loading from cache
- Installing swiftmailer/swiftmailer (v6.0.2) Loading from cache
- Installing symfony/swiftmailer-bundle (v3.1.6) Loading from cache
- Installing symfony/translation (v4.0.3) Loading from cache
- Installing symfony/validator (v4.0.3) Loading from cache
- Installing symfony/serializer (v4.0.3) Loading from cache
- Installing symfony/inflector (v4.0.3) Loading from cache
- Installing symfony/property-info (v4.0.3) Loading from cache
- Installing symfony/property-access (v4.0.3) Loading from cache
- Installing psr/simple-cache (1.0.0) Loading from cache
- Installing psr/cache (1.0.1) Loading from cache
- Installing symfony/cache (v4.0.3) Loading from cache
- Installing webmozart/assert (1.2.0) Loading from cache
- Installing phpdocumentor/reflection-common (1.0.1) Loading from cache
- Installing phpdocumentor/type-resolver (0.4.0) Loading from cache
- Installing phpdocumentor/reflection-docblock (4.2.0) Loading from cache
- Installing symfony/serializer-pack (v1.0.1) Loading from cache
- Installing symfony/security (v4.0.3) Loading from cache
- Installing symfony/security-bundle (v4.0.3) Loading from cache
- Installing symfony/process (v4.0.3) Loading from cache
- Installing monolog/monolog (1.23.0) Loading from cache
- Installing symfony/monolog-bridge (v4.0.3) Loading from cache
- Installing symfony/monolog-bundle (v3.1.2) Loading from cache
- Installing symfony/routing (v4.0.3) Loading from cache
- Installing symfony/finder (v4.0.3) Loading from cache
- Installing symfony/framework-bundle (v4.0.3) Loading from cache
- Installing symfony/console (v4.0.3) Loading from cache
- Installing zendframework/zend-eventmanager (3.2.0) Loading from cache
- Installing zendframework/zend-code (3.3.0) Loading from cache
- Installing ocramius/proxy-manager (2.2.0) Loading from cache
- Installing doctrine/dbal (v2.6.3) Loading from cache
- Installing doctrine/migrations (v1.6.2) Loading from cache
- Installing symfony/doctrine-bridge (v4.0.3) Loading from cache
- Installing doctrine/doctrine-cache-bundle (1.3.2) Loading from cache
- Installing jdorn/sql-formatter (v1.2.17) Loading from cache
- Installing doctrine/doctrine-bundle (1.8.1) Loading from cache
- Installing doctrine/doctrine-migrations-bundle (v1.3.1) Loading from cache
- Installing doctrine/instantiator (1.1.0) Loading from cache
- Installing doctrine/orm (v2.6.0) Loading from cache
- Installing symfony/orm-pack (v1.0.5) Loading from cache
- Installing symfony/options-resolver (v4.0.3) Loading from cache
- Installing symfony/intl (v4.0.3) Loading from cache
- Installing symfony/polyfill-intl-icu (v1.6.0) Loading from cache
- Installing symfony/form (v4.0.3) Loading from cache
- Installing symfony/expression-language (v4.0.3) Loading from cache
- Installing symfony/polyfill-php72 (v1.6.0) Loading from cache
- Installing symfony/var-dumper (v4.0.3) Loading from cache
- Installing symfony/phpunit-bridge (v4.0.3) Loading from cache
- Installing twig/twig (v2.4.4) Loading from cache
- Installing symfony/twig-bridge (v4.0.3) Loading from cache
- Installing symfony/web-profiler-bundle (v4.0.3) Loading from cache
- Installing symfony/twig-bundle (v4.0.3) Loading from cache
- Installing symfony/stopwatch (v4.0.3) Loading from cache
- Installing symfony/profiler-pack (v1.0.3) Loading from cache
- Installing easycorp/easy-log-handler (v1.0.4) Loading from cache
- Installing symfony/debug-bundle (v4.0.3) Loading from cache
- Installing symfony/debug-pack (v1.0.4) Loading from cache
- Installing symfony/asset (v4.0.3) Loading from cache
- Installing sensio/framework-extra-bundle (v5.1.4) Loading from cache
- Installing symfony/dom-crawler (v4.0.3) Loading from cache
- Installing symfony/browser-kit (v4.0.3) Loading from cache
- Installing symfony/css-selector (v4.0.3) Loading from cache
- Installing symfony/dotenv (v4.0.3) Loading from cache
- Installing symfony/maker-bundle (v1.0.2) Loading from cache
Writing lock file
Generating autoload files
ocramius/package-versions: Generating version class...
ocramius/package-versions: ...done generating version class
Symfony operations: 20 recipes (28dbd00e20d094ab6cb6891380649c4d)
- Configuring symfony/flex (>=1.0): From github.com/symfony/recipes:master
- Configuring symfony/framework-bundle (>=3.3): From github.com/symfony/recipes:master
- Configuring doctrine/annotations (>=1.0): From github.com/symfony/recipes:master
- Configuring symfony/webpack-encore-pack (>=1.0): From github.com/symfony/recipes:master
- Configuring symfony/swiftmailer-bundle (>=2.5): From github.com/symfony/recipes:master
- Configuring symfony/translation (>=3.3): From github.com/symfony/recipes:master
- Configuring symfony/security-bundle (>=3.3): From github.com/symfony/recipes:master
- Configuring symfony/monolog-bundle (>=3.1): From github.com/symfony/recipes:master
- Configuring symfony/routing (>=4.0): From github.com/symfony/recipes:master
- Configuring symfony/console (>=3.3): From github.com/symfony/recipes:master
- Configuring doctrine/doctrine-cache-bundle (>=1.3.2): From auto-generated recipe
- Configuring doctrine/doctrine-bundle (>=1.6): From github.com/symfony/recipes:master
- Configuring doctrine/doctrine-migrations-bundle (>=1.2): From github.com/symfony/recipes:master
- Configuring symfony/phpunit-bridge (>=3.3): From github.com/symfony/recipes:master
- Configuring symfony/web-profiler-bundle (>=3.3): From github.com/symfony/recipes:master
- Configuring symfony/twig-bundle (>=3.3): From github.com/symfony/recipes:master
- Configuring easycorp/easy-log-handler (>=1.0): From github.com/symfony/recipes:master
- Configuring symfony/debug-bundle (>=3.3): From github.com/symfony/recipes:master
- Configuring sensio/framework-extra-bundle (>=4.0): From github.com/symfony/recipes:master
- Configuring symfony/maker-bundle (>=1.0): From github.com/symfony/recipes:master
Executing script cache:clear [OK]
Executing script assets:install --symlink --relative public [OK]
Some files may have been created or updated to configure your new packages.
Please review, edit and commit them: these files are yours.
What's next?
* Run your application:
1. Change to the project directory
2. Execute the php -S 127.0.0.1:8000 -t public command;
3. Browse to the http://localhost:8000/ URL.
Quit the server with CTRL-C.
Run composer require server for a better web server.
* Read the documentation at https://symfony.com/doc
Next: Configuration
* Modify your DATABASE_URL config in .env
* Configure the driver (mysql) and
server_version (5.7) in config/packages/doctrine.yaml
How to test?
* Write test cases in the tests/ folder
* Run php bin/phpunit
Start by changing into your new directory:
cd lets-explore-symfony-4
And let's follow the advice given to install the symfony/web-server-bundle
:
composer require server
./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/web-server-bundle (v4.0.3) Loading from cache
Writing lock file
Generating autoload files
ocramius/package-versions: Generating version class...
ocramius/package-versions: ...done generating version class
Symfony operations: 1 recipe (49f8401ef71615655f92e7820cbc33b9)
- Configuring symfony/web-server-bundle (>=3.3): From github.com/symfony/recipes:master
Executing script cache:clear [OK]
Executing script assets:install --symlink --relative public [OK]
Some files may have been created or updated to configure your new packages.
Please review, edit and commit them: these files are yours.
Now let's fire up the web server and take a look at our new Symfony 4 website:
php bin/console server:start
[OK] Server listening on http://127.0.0.1:8000
Browse, as instructed, to http://127.0.0.1:8000
, and... somewhat unusually there's a 404
error page.
This is good, in some ways.
The fact we see a 404
is good. It means our web server is up and running, and responding to requests.
We can see the web debug toolbar (down at the bottom of the screen) is installed and working.
We can also see that whilst a request was made to the site root (/
), a page wasn't configured to respond on that route.
You might have been expecting a nice "welcome" page. But Symfony 4 is more minimalistic. You would almost certainly have gone right into your code and immediately deleted any "welcome" page that came pre-configured. So why provide it?
Geek Trivia: If you're used to Symfony 2, or Symfony 3, there was a "welcome" page with a fresh install of the Symfony Standard Edition. Whilst this is now gone, the new MakerBundle
does bring this back, kind of. We'll explore this a bit more in the next video.
Our First Page
Even though Symfony doesn't provide us with a Welcome page, let's start by creating something similar.
We're going to create a template first. We use Twig to create templates, and the convention is to use the format whatever_name_you_like.html.twig
.
We will call ours hello_page.html.twig
.
Create this new template under the templates
directory:
touch templates/hello_page.html.twig
touch
is simply a nerdy way of creating a new, empty file from the command line. Feel free to create the file from your IDE, or similar.
Add anything you like into this template. I'm going with the basic:
Hello, CodeReviewVideos!
Now, in order to see this page in our web browser, we need to make Symfony aware it exists.
There's a very standard way of doing this: using a controller.
But, as our page is so simple, we don't technically need a controller. What we're about to do is a bit geeky, so don't worry if you don't understand it. We're going to render our template without a controller.
Open up the file:
config/routes.yaml
And add in:
hello_page:
path: /
controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction
defaults:
template: hello_page.html.twig
Now, head back to your browser and refresh the page.
You should see whatever text you put in to your hello_page.html.twig
template.
Fancy, eh?
Well, whilst it's nice to know you can do this, in 99% of circumstances I, personally, don't render pages in this way.
What we've actually done here is to define our first route.
Remember how the 404
error complained that 'No route found for "GET /"'?

And then we defined a route for /
by setting our hello_page
's path
attribute to /
.
We can double check this by using Symfony's very helpful, very handy debug:router
console command:
php bin/console debug:router
-------------------------- -------- -------- ------ -----------------------------------
Name Method Scheme Host Path
-------------------------- -------- -------- ------ -----------------------------------
_twig_error_test ANY ANY ANY /_error/{code}.{_format}
_wdt ANY ANY ANY /_wdt/{token}
_profiler_home ANY ANY ANY /_profiler/
_profiler_search ANY ANY ANY /_profiler/search
_profiler_search_bar ANY ANY ANY /_profiler/search_bar
_profiler_phpinfo ANY ANY ANY /_profiler/phpinfo
_profiler_search_results ANY ANY ANY /_profiler/{token}/search/results
_profiler_open_file ANY ANY ANY /_profiler/open
_profiler ANY ANY ANY /_profiler/{token}
_profiler_router ANY ANY ANY /_profiler/{token}/router
_profiler_exception ANY ANY ANY /_profiler/{token}/exception
_profiler_exception_css ANY ANY ANY /_profiler/{token}/exception.css
hello_page ANY ANY ANY /
-------------------------- -------- -------- ------ -----------------------------------
All of the entries beginning with the underscore (e.g. _profiler_search_bar
) are included routes that came via setting up our project using the website-skeleton
.
Our custom route: hello_page
is at the bottom, and matches the path
of /
. Just what we defined in config/routes.yaml
.
Change the path
to anything you like:
hello_page:
path: /hello
controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction
defaults:
template: hello_page.html.twig
then re-run the command:
php bin/console debug:router
-------------------------- -------- -------- ------ -----------------------------------
Name Method Scheme Host Path
-------------------------- -------- -------- ------ -----------------------------------
_twig_error_test ANY ANY ANY /_error/{code}.{_format}
_wdt ANY ANY ANY /_wdt/{token}
_profiler_home ANY ANY ANY /_profiler/
_profiler_search ANY ANY ANY /_profiler/search
_profiler_search_bar ANY ANY ANY /_profiler/search_bar
_profiler_phpinfo ANY ANY ANY /_profiler/phpinfo
_profiler_search_results ANY ANY ANY /_profiler/{token}/search/results
_profiler_open_file ANY ANY ANY /_profiler/open
_profiler ANY ANY ANY /_profiler/{token}
_profiler_router ANY ANY ANY /_profiler/{token}/router
_profiler_exception ANY ANY ANY /_profiler/{token}/exception
_profiler_exception_css ANY ANY ANY /_profiler/{token}/exception.css
hello_page ANY ANY ANY /hello
-------------------------- -------- -------- ------ -----------------------------------
And of course, you would now need to browse to http://127.0.0.1:8000/hello
to see the "hello" page.
Ok, that's us with a brand new Symfony 4 website up and running in our local development environment.
In the next video, we will take our first look at our own custom Controller.