Getting Started with Symfony 3


In this first video we are going to get started by taking a look at how the finished app should function. The idea here is that we can access any valid GitHub user's profile data, and our Symfony 3 web application will pull their profile and repository data in, and display it on the page.

There's quite a lot to cover, so rather than doing too much intro, I'd rather jump right into Symfony and get started.

Installation

I am going to assume you have a working copy of Symfony 3 installed and ready to go. If you do not, please follow the instructions on Symfony.com for Installing and Configuring Symfony.

If you are still struggling to get a Symfony web site / development environment installed and ready to go, I have covered this in a previous tutorial video. Note that this video was for Symfony 2, but aside from installing a different version, Symfony 3 is extremely similar. Just remember to swap out any app/console commands out for bin/console.

I would also strongly recommend you use a proper IDE designed for PHP when working with a modern web framework like Symfony. My IDE of choice is PHPStorm, and there's a 30 day demo available if you haven't yet given it a try. There's tons of useful shortcuts that make PHPStorm amazing for PHP development.

There is also a useful Symfony cookbook article on Configuring a Webserver.

If after all this, you are still struggling with installation, do let me know by leaving a comment below and I will record a video covering the installation process.

Environment

For my examples, I will use http://symfony-3.dev/ as my web site. Your website can, and likely will, differ.

In Symfony, right out of the box we have the concept of multiple environments. This gives tons of flexibility in larger projects, but for now, we are only going to use the dev environment, which we access by browsing to http://symfony-3.dev/app_dev.php/. Symfony developers tend to use dev and app_dev interchangably to describe this same environment.

It is worth pointing out here that http://symfony-3.dev/app_dev.php/ and http://symfony-3.dev/ are both considered the root of your Symfony website. For the curious, this is achieved by passing specific configuration to your webserver (Apache, NGINX, etc).

By using the app_dev environment we get full access to the Web Debug Toolbar which you may have seen before if you've ever seen a Symfony project. This toolbar contains lots of helpful information about the current environment, and we will use it more later in this series.

If you open up http://symfony-3.dev/app_dev.php/ on a brand new Symfony 3 install, you should see a welcome page with some details displayed about your system. However, you might see a 403 forbidden page. If you do see the 403 page, be sure to open up your web/app_dev.php and add in your local IP address details (line 15):

|| !(in_array(@$_SERVER['REMOTE_ADDR'], ['127.0.0.1', 'fe80::1', '::1', 'your.ip.details.here'])

Controller

Symfony is the really about the journey from Request through to Response.

Users of our system send in a request:

GET http://symfony-3.dev/app_dev.php/some/page

And Symfony handles the details behind the scenes to figure out firstly, is this even a valid request? If not, throw an error - 404, 403, etc.

If the request is valid then Symfony will figure out which Controller has the PHP code / logic to handle this particular URL / route inside our site.

Then, the specific action / PHP function will be run, which will do whatever it needs to return a Response - this typically being some sort of HTML data.

So long as we keep to the expected conventions for naming things inside our Symfony project, largely this is very straightforward.

Symfony comes with some predefined directory structure which is admittedly, initially quite scary and confusing.

For now, all we need to know about is that the app/config directory contains all our application configuration files.

We are interested in the routing.yml file, which contains the information Symfony needs to figure out which routes / URLs will be available inside our project, and which Controller files contain the PHP code / logic to deal with requests for those URLs.

An example illustrates this much easier, in my opinion.

As our application is going to be called GitHut, it makes sense to create a new Controller called GitHutController.

Controllers can have any name, so long as they follow some conventions.

The conventions here are that the file name matches the class name. In our case the file is called GitHutController.php, and the class name matches - GitHutController.

Notice also that the namespace path matches up with the directory structure exactly. This isn't Symfony specific, but is worth pointing out.

<?php

// src/AppBundle/Controller/GitHutController.php

namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;

class GitHutController extends Controller
{
    /**
     * @Route("/", name="githut")
     */
    public function githutAction(Request $request)
    {
        return $this->render('githut/index.html.twig');
    }
}

There's quite a lot going on here, so let's step through it line by line.

namespace AppBundle\Controller; - Symfony uses PHP's namespaces to ensure code we write doesn't conflict with code other people write. Think of namespaces as directories in your operating system and how we can have two files with the same name in different directories, but not in the same directory.

The use statement lines tell Symfony which other classes we need to make this class work properly. This, again, uses the namespace functionality from PHP. This is not Symfony specific. The hard part is knowing which classes to use. PHPStorm will make this easier for you by auto-suggesting, but if unsure, check the appropriate documentation.

class GitHutController extends Controller - declares our GitHutController class, and also extends Symfony's provided Controller class (from the use statement). This gives us immediate access to all of Symfony's Controller methods - such as render().

@Route("/", name="githut") is a Symfony routing annotation. To use routing annotations we need to have the relevant use statement - the first use statement in our case. Then, annotations allow us to define the URI that this PHP function will be used for, and also to name our route. This is helpful as we can later refer to this route by name, so if the URI changes, we don't need to find / replace all instances of that URI in our project.

public function githutAction(Request $request) - follows Symfony's Controller convention to declare our action function that will be run when this route / URL is hit. The name can be anything, so long as it ends in Action. We are getting the Request $request variable set for us via dependency injection, which isn't something we need worry about at this stage.

return $this->render('githut/index.html.twig'); - calls the render method on the Controller class we are extending from, passing in the template name - which we haven't yet defined. Remember, when we extend from another class, we get all that class's functionality which is why we don't see the code in our GitHutController, but if you ctrl+click the word Controller in extends Controller, you should be taken to that file (in PHPStorm at least).

We'll cover the template in a moment, but it's worth noting that none of this would work if our Routing was not properly configured.

Fortunately, Symfony provides a useful default routing setup which allows us to create any number of Controller classes inside AppBundle:

# app/config/routing.yml

app:
    resource: "@AppBundle/Controller/"
    type:     annotation

Essentially this is a catch-all bit of configuration that tells Symfony to look inside src/AppBundle/Controller directory, and for any found Controllers (remember, by naming convention {Anything}Controller.php) to look inside, and discover configured routes by their defined annotations.

Routing is a fancy word for the URLs we want to be available inside our project.

Templates

Twig is the template engine used by Symfony.

If you've ever used a template engine before, you should find Twig as good as - if not better - than what you are used too. It really is a joy to use.

Twig is a separate project that you can use outside of Symfony. Fortunately for us, it comes pre-configured for use in our Symfony projects.

Current Symfony Best Practice dictates that our templates live in the app/Resources/views directory. This might feel a little odd - our templates live outside our code / src directory. The two main reasons being that it makes life easier for designers, and also simplifies the naming convention used to reference templates.

This means earlier that when we told Symfony to:

return $this->render('githut/index.html.twig');

That our githut/index.html.twig template should live inside:

app/Resources/views/githut/index.html.twig

We now need to define the templates. For this I will create a base.html.twig template which will contain all the common layout elements, meta tags, stylesheets, and so on.

Then, other pages inside our project can extend (and overwrite as needed) from the base template and immediately get access to these styles and layout, without having to constantly redeclare the same boilerplate over and over.

<!-- app/Resources/views/base.html.twig -->

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>{% block title %}{{ username }}'s GitHut!{% endblock %}</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
        <link rel="stylesheet" href="{{ asset('css/styles.css') }}">
        {% block stylesheets %}{% endblock %}
        <link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
    </head>
    <body>

        <nav class="navbar navbar-default navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <a class="navbar-brand" href="#">My Githut</a>
                </div>
            </div>
        </nav>

        <div class="container">

            <div class="row">
                <div class="col-sm-12">
                    {% block body %}{% endblock %}
                </div>
            </div>

        </div><!-- /.container -->

        {% block javascripts %}{% endblock %}
    </body>
</html>

And the template for our githut/index.html.twig:

{% extends 'base.html.twig' %}

{% block body %}
  <p>This will appear inside the container > row > col-sm-12 div</p>
{% endblock %}

And that is enough at this stage to start the rest of our development.

In the next video we will flesh out the sidebar containing our profile picture, location data, and other bits and pieces from our GitHub profile.

Code For This Course

Get the code for this course.

Episodes