This is the third part of the series Symfony2 Tutorial for Beginners which will describe the process of creating a static page.

We will create a controller that will define a route as well as the action for this route. Furthermore we will create a basic template in twig and the impressum page itself.

Creating the Route and the Controller

The first thing one has to do when adding a new page to a website is to define how the user can reach it and what part of the code should be executed in order to show it. Symfony2 names this process of mapping a url with a controller method routing.

Yaml, Xml and Annotation to define a Route in Symfony2

In Symfony2 there are three ways to define a new route: yaml, xml and annotation in the controller. The advantage of yaml is, that all defined routes can be seen in one place. Annotations on the other hand are defining the route right where it will be needed. The syntax of Xml does not rely on whitespace, but it is needlessly verbose and thereby unreadable, so I would not recommend using it. You have to decide which one you prefer, or you might want to mix them and choose one depending on the situation.

I will use annotations in this tutorial but touch on how it would look in yaml now and again.

Example of Annotation to define a Route and the Controller

So lets get right on with creating an impressum page (a page containing infos on the person legally responsible for the website): Create a controller:

// src/YourIdentifier/YourBundle/Controller/PageController.php
namespace YourIdentifier\YourBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class PageController extends Controller {

     * @Route("/impressum", name="page_impressum")
     * @Template()

    public function impressumAction()
        return $this->render('YourIdentifierYourBundle:Page\static:impressum.html.twig');

If you are unsure what namespace, class, or extends means, you should go read up on php namespace and oop in php.

We are defining the url by which a user may reach the impressum with the @Route annotation. You can choose the path and name freely. The path is the first argument and it is necessary. The name argument is optional, although it is nice to have to call the route later on.

Note that the route must be activated in the configurations (see Dans comment below). So for every class, create an entry in your routing.yml file like this:

 resource: "@YourIdentifierYourBundle/Controller/PageController.php"
 type: annotation

Example of Yaml

The yaml alternative to the above annotation is:

page_impressum:                 # the identifier
    pattern:  /impressum        # the route
    defaults: { _controller:  YourIdentifierYourBundle:Page:impressum }  # the controller + action
        _method:  GET           # restraints

As can be seen, it is pretty similar to the annotation method, except the definition of the controller which is used. In the example, YourIdentifierYourBundle defines the bundle in which to look, Page stands for PageController.php and impressum stands for the impressumAction method.

Notes on the Controller example

Note that the function name itself must be post-fixed with the string “Action”.

The executed action itself is rather uninteresting: We are rendering a static page (we are not passing any arguments to the twig template). The template we are rendering is /src/YourIdentifier/YourBundle/Resources/views/Page/static/impressum.html.twig .

If you are interested in Routing and what else is possible with it, you might want to read the Symfony2 chapter on Routing.

Creating the View

Creating a base template

As some parts of the website will be the same on almost all pages, we will first define a base twig template which will be included by most of the pages we will create later.

<!-- /src/YourIdentifier/YourBundle/Resources/views/base.html.twig -->
<!DOCTYPE html>
<html xmlns="" dir="ltr" lang="en-US">
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>{% block title %}Default for variable title part {% endblock %} - constant title part</title>
        <!--[if lt IE 9]>
           <script src=""></script>
        {% block stylesheets %}
        {% stylesheets filter='yui_css' 'css/main.css' %}
        <link rel="stylesheet" href="{{ asset_url }}" type="text/css" media="screen" />
        {% endstylesheets %}
        {% endblock %}
        <link rel="shortcut icon" href="{{ asset('favicon.ico') }}" />
        <div id="wrap">
        <header id="header">
            <h1>Page Name</h1>
            {% block navigation %}
                <ul class="navigation">
                    <li><a href="{{ path('page_impressum') }}">Impressum</a></li>                    
            {% endblock %}

        <section class="main">
            {% block body %}{% endblock %}
        <aside class="sidebar-right">

            {% block sidebarright %}Right Sidebar{% endblock %}

        <aside class="sidebar-left">
            {% block sidebarleft %}{% endblock %}

        <div id="footer">
            {% block footer %}
            Maybe a link to your privacy settings, a link to Symfony2, whatever.
            {% endblock %}
        {% block javascripts %}{% endblock %}
I am not too good with css or design, but for those interested here is the css file so far:

    Document   : main
    Created on : Jun 23, 2012, 8:46:13 PM
    Author     : developer
        Styling of the main site, including positioning of main conten, sidebar and footer,
        general font-styling and styling of nav-bar.

/* style text for whole site*/
html {

font-family: Arial, Helvetica, Sans-serif;
color: #666666;

/* site width and center */
#wrap {
margin:0 auto;

/* style links for whole site*/
#wrap a {
    text-decoration: none;

/* positioning of main, sidebar and footer */
.main {
line-height: 18px;

.sidebar-right {
line-height: 18px;

#footer {

/* position navigation*/
#header .navigation ul {
#header .navigation li {

/* style naviagion */
#header .navigation { border-bottom: 1px solid #ccc; border-top: 1px solid #ccc; }
#header .navigation li a { display: inline-block; padding: 10px 15px; border-left: 1px solid #ccc; color: black}

Here you have your basic parts of a website. The head – containing title, stylesheets and the like – and the body – containing a header, a left and a right sidebar, a footer and the main content.

The parts of it inside { and } are twig-code. Generally, {% means “do something”, {{ means print something and {# is for comments.

In twig, a block may be defined in the base template and it may contain a default value there. Later, it can be overridden in a template that extends the base template.

It can be seen that we are already using the route we defined in the controller above to link in the navigation to the impressum we are creating. This is done by calling the path function with the identifying name we used in the controller (in this case “page_impressum”).

In the example above, I used Assetic for the management of the css files. I will not go into details about it, but you can read about in the symfony cookbook: How to Use Assetic for Asset Management. Assetic is quite useful and I would suggest using it, but you can always use the standard way of importing css as well by using:

<!-- /src/YourIdentifier/YourBundle/Resources/views/base.html.twig -->
{% block stylesheets %}
    <link href="{{ asset('css/main.css') }}" type="text/css" rel="stylesheet" />
{% endblock %}
instead of the stylesheets block used above. In that case, the main.css file must be located at /web/css/main.css

If you are using Assetic and placed your css files in src/YourIdentifier/YourBundle/Resources/public/css/ they must be included by calling
php app/console assetic:dump

Thoughts on Twig and alternatives

Twig is alright in most contexts, but you may choose to use PHP instead of Twig for Templates. The only real downside is that you have to remember to escape the output yourself as php does not protect against code open to xss, while twig does. In this tutorial I will continue to use twig as I find it goes nicer together with html than php does (but it is somewhat limiting out of the box).

Creating the Impressum Page

<!-- /src/YourIdentifier/YourBundle/Resources/views/Page/static/impressum.html.twig -->
{% extends 'YourBundle::base.html.twig' %}

{% block title %}
{% endblock %}

{% block body %}
<p>Responcible for this website (§ 5 TMG, § 55 RfStV):</p>
<p>Fake Fakerson</p>
<p>123 Fakestreet</p>
<p>Fakestown - USA</p>
{% endblock %}

Not much going on here: The title- and body-blocks are overwritten with the impressum content.

If you now visit http://localhost/your_project/web/app_dev.php/impressum you should see the impressum as well as the navigation (which at this point only contains a – working – link to the impressum).

That is it for the third part of this Symfony2 Tutorial. In the following parts of this series some more possibilities of twig and the controller will be introduced.

More on Twig can also be found on the official Symfony2 website.

The next part of this tutorial is: User Submissions – Controller, Forms, E-Mails
Overview over all parts: Symfony2 Tutorial for Beginners