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 /"'?

Symfony 4 no route found

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.

Code For This Course

Get the code for this course.

Episodes