Symfony Quick Tour 2.5

28
The Quick Tour for Symfony 2.5 generated on June 11, 2014 What could be better to make up your own mind than to try out Symfony yourself? Aside from a little time, it will cost you nothing. Step by step you will explore the Symfony universe. Be careful, Symfony can become addictive from the very first encounter!

description

Symfony Quick Tour 2.5

Transcript of Symfony Quick Tour 2.5

Page 1: Symfony Quick Tour 2.5

The Quick Tourfor Symfony 2.5

generated on June 11, 2014

What could be better to make up your own mind than to try out Symfony yourself? Aside froma little time, it will cost you nothing. Step by step you will explore the Symfony universe. Becareful, Symfony can become addictive from the very first encounter!

Page 2: Symfony Quick Tour 2.5

The Quick Tour (2.5)

This work is licensed under the “Attribution-Share Alike 3.0 Unported” license (http://creativecommons.org/licenses/by-sa/3.0/).

You are free to share (to copy, distribute and transmit the work), and to remix (to adapt the work) under thefollowing conditions:

• Attribution: You must attribute the work in the manner specified by the author or licensor (butnot in any way that suggests that they endorse you or your use of the work).

• Share Alike: If you alter, transform, or build upon this work, you may distribute the resulting workonly under the same, similar or a compatible license. For any reuse or distribution, you must makeclear to others the license terms of this work.

The information in this book is distributed on an “as is” basis, without warranty. Although every precautionhas been taken in the preparation of this work, neither the author(s) nor SensioLabs shall have any liability toany person or entity with respect to any loss or damage caused or alleged to be caused directly or indirectly bythe information contained in this work.

If you find typos or errors, feel free to report them by creating a ticket on the Symfony ticketing system(http://github.com/symfony/symfony-docs/issues). Based on tickets and users feedback, this book iscontinuously updated.

Page 3: Symfony Quick Tour 2.5

Contents at a Glance

The Big Picture ...................................................................................................................................4The View ..........................................................................................................................................12The Controller ..................................................................................................................................17The Architecture ...............................................................................................................................21

PDF brought to you bygenerated on June 11, 2014

Contents at a Glance | iii

Page 4: Symfony Quick Tour 2.5

Listing 1-1

Listing 1-2

Chapter 1

The Big Picture

Start using Symfony2 in 10 minutes! This chapter will walk you through some of the most importantconcepts behind Symfony2 and explain how you can get started quickly by showing you a simple projectin action.

If you've used a web framework before, you should feel right at home with Symfony2. If not, welcome toa whole new way of developing web applications.

Installing Symfony2First, check that the PHP version installed on your computer meets the Symfony2 requirements: 5.3.3or higher. Then, open a console and execute the following command to install the latest version ofSymfony2 in the myproject/ directory:

1 $ composer create-project symfony/framework-standard-edition myproject/ ~2.5

Composer1 is the package manager used by modern PHP applications and the only recommendedway to install Symfony2. To install Composer on your Linux or Mac system, execute the followingcommands:

12

$ curl -sS https://getcomposer.org/installer | php$ sudo mv composer.phar /usr/local/bin/composer

To install Composer on a Windows system, download the executable installer2.

Beware that the first time you install Symfony2, it may take a few minutes to download all itscomponents. At the end of the installation process, the installer will ask you four questions:

1. Would you like to use Symfony 3 directory structure? [y/N] The upcoming Symfony 3version will modify the default directory structure for Symfony applications. If you want to test

1. https://getcomposer.org/

2. http://getcomposer.org/download

PDF brought to you bygenerated on June 11, 2014

Chapter 1: The Big Picture | 4

Page 5: Symfony Quick Tour 2.5

Listing 1-3

Listing 1-4

drive this new structure, type y. In order to follow this tutorial, press the <Enter> key to acceptthe default N value and to keep using the default Symfony2 structure.

2. Would you like to install Acme demo bundle? [y/N] Symfony versions prior to 2.5 includeda demo application to test drive some features of the framework. However, as this demoapplication is only useful for newcomers, installing it is now optional. In order to follow thistutorial, type the y key to install the demo application.

3. Some parameters are missing. Please provide them. Symfony2 asks you for the value of allthe configuration parameters. For this first project, you can safely ignore this configuration bypressing the <Enter> key repeatedly.

4. Do you want to remove the existing VCS (.git, .svn..) history? [Y,n]? The developmenthistory of large projects such as Symfony can take a lot of disk space. Press the <Enter> key tosafely remove all this history data.

Running Symfony2Before running Symfony2 for the first time, execute the following command to make sure that yoursystem meets all the technical requirements:

12

$ cd myproject/$ php app/check.php

Fix any error reported by the command and then use the PHP built-in web server to run Symfony:

1 $ php app/console server:run

If you get the error There are no commands defined in the "server" namespace., then you are probablyusing PHP 5.3. That's ok! But the built-in web server is only available for PHP 5.4.0 or higher. If youhave an older version of PHP or if you prefer a traditional web server such as Apache or Nginx, read theConfiguring a web server article.

Open your browser and access the http://localhost:8000 URL to see the Welcome page of Symfony2:

PDF brought to you bygenerated on June 11, 2014

Chapter 1: The Big Picture | 5

Page 6: Symfony Quick Tour 2.5

Listing 1-5

Listing 1-6

Listing 1-7

Understanding the FundamentalsOne of the main goals of a framework is to keep your code organized and to allow your application toevolve easily over time by avoiding the mixing of database calls, HTML tags and business logic in thesame script. To achieve this goal with Symfony, you'll first need to learn a few fundamental concepts andterms.

Symfony comes with some sample code that you can use to learn more about its main concepts. Go tothe following URL to be greeted by Symfony2 (replace Fabien with your first name):

1 http://localhost:8000/app_dev.php/demo/hello/Fabien

What's going on here? Have a look at each part of the URL:

• app_dev.php: This is a front controller. It is the unique entry point of the application and itresponds to all user requests;

• /demo/hello/Fabien: This is the virtual path to the resource the user wants to access.

Your responsibility as a developer is to write the code that maps the user's request (/demo/hello/Fabien)to the resource associated with it (the Hello Fabien! HTML page).

Routing

Symfony2 routes the request to the code that handles it by matching the requested URL (i.e. the virtualpath) against some configured paths. The demo paths are defined in the app/config/routing_dev.ymlconfiguration file:

123456

# app/config/routing_dev.yml# ...

# AcmeDemoBundle routes (to be removed)_acme_demo:

resource: "@AcmeDemoBundle/Resources/config/routing.yml"

This imports a routing.yml file that lives inside the AcmeDemoBundle:

PDF brought to you bygenerated on June 11, 2014

Chapter 1: The Big Picture | 6

Page 7: Symfony Quick Tour 2.5

Listing 1-8

Listing 1-9

123456789

1011

# src/Acme/DemoBundle/Resources/config/routing.yml_welcome:

path: /defaults: { _controller: AcmeDemoBundle:Welcome:index }

_demo:resource: "@AcmeDemoBundle/Controller/DemoController.php"type: annotationprefix: /demo

# ...

The first three lines (after the comment) define the code that is executed when the user requests the "/"resource (i.e. the welcome page you saw earlier). When requested, the AcmeDemoBundle:Welcome:indexcontroller will be executed. In the next section, you'll learn exactly what that means.

In addition to YAML files, routes can be configured in XML or PHP files and can even beembedded in PHP annotations. This flexibility is one of the main features of Symfony2, aframework that never imposes a particular configuration format on you.

Controllers

A controller is a PHP function or method that handles incoming requests and returns responses (oftenHTML code). Instead of using the PHP global variables and functions (like $_GET or header()) tomanage these HTTP messages, Symfony uses objects: Request and Response. The simplest possiblecontroller might create the response by hand, based on the request:

12345

use Symfony\Component\HttpFoundation\Response;

$name = $request->get('name');

return new Response('Hello '.$name);

Symfony2 chooses the controller based on the _controller value from the routing configuration:AcmeDemoBundle:Welcome:index. This string is the controller logical name, and it references theindexAction method from the Acme\DemoBundle\Controller\WelcomeController class:

123456789

101112

// src/Acme/DemoBundle/Controller/WelcomeController.phpnamespace Acme\DemoBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class WelcomeController extends Controller{

public function indexAction(){

return $this->render('AcmeDemoBundle:Welcome:index.html.twig');}

}

PDF brought to you bygenerated on June 11, 2014

Chapter 1: The Big Picture | 7

Page 8: Symfony Quick Tour 2.5

Listing 1-10

Listing 1-11

Listing 1-12

You could have used the full class and method name -Acme\DemoBundle\Controller\WelcomeController::indexAction - for the _controller value.But using the logical name is shorter and allows for more flexibility.

The WelcomeController class extends the built-in Controller class, which provides useful shortcutmethods, like the render() method that loads and renders a template(AcmeDemoBundle:Welcome:index.html.twig). The returned value is a Response object populated withthe rendered content. So, if the need arises, the Response can be tweaked before it is sent to the browser:

1234567

public function indexAction(){

$response = $this->render('AcmeDemoBundle:Welcome:index.txt.twig');$response->headers->set('Content-Type', 'text/plain');

return $response;}

No matter how you do it, the end goal of your controller is always to return the Response object thatshould be delivered back to the user. This Response object can be populated with HTML code, representa client redirect, or even return the contents of a JPG image with a Content-Type header of image/jpg.

The template name, AcmeDemoBundle:Welcome:index.html.twig, is the template logical name and itreferences the Resources/views/Welcome/index.html.twig file inside the AcmeDemoBundle (locatedat src/Acme/DemoBundle). The Bundles section below will explain why this is useful.

Now, take a look at the routing configuration again and find the _demo key:

123456

# src/Acme/DemoBundle/Resources/config/routing.yml# ..._demo:

resource: "@AcmeDemoBundle/Controller/DemoController.php"type: annotationprefix: /demo

The logical name of the file containing the _demo routes is @AcmeDemoBundle/Controller/DemoController.php and refers to the src/Acme/DemoBundle/Controller/DemoController.php file.In this file, routes are defined as annotations on action methods:

123456789

1011121314151617

// src/Acme/DemoBundle/Controller/DemoController.phpuse Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class DemoController extends Controller{

/*** @Route("/hello/{name}", name="_demo_hello")* @Template()*/public function helloAction($name){

return array('name' => $name);}

// ...}

PDF brought to you bygenerated on June 11, 2014

Chapter 1: The Big Picture | 8

Page 9: Symfony Quick Tour 2.5

Listing 1-13

The @Route() annotation creates a new route matching the /hello/{name} path to the helloAction()method. Any string enclosed in curly brackets, like {name}, is considered a variable that can be directlyretrieved as a method argument with the same name.

If you take a closer look at the controller code, you can see that instead of rendering a templateand returning a Response object like before, it just returns an array of parameters. The @Template()annotation tells Symfony to render the template for you, passing to it each variable of the returnedarray. The name of the template that's rendered follows the name of the controller. So, in this example,the AcmeDemoBundle:Demo:hello.html.twig template is rendered (located at src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig).

Templates

The controller renders the src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig template(or AcmeDemoBundle:Demo:hello.html.twig if you use the logical name):

12345678

{# src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig #}{% extends "AcmeDemoBundle::layout.html.twig" %}

{% block title "Hello " ~ name %}

{% block content %}<h1>Hello {{ name }}!</h1>

{% endblock %}

By default, Symfony2 uses Twig3 as its template engine but you can also use traditional PHP templates ifyou choose. The second part of this tutorial will introduce how templates work in Symfony2.

Bundles

You might have wondered why the Bundle word is used in many names you have seen so far. All the codeyou write for your application is organized in bundles. In Symfony2 speak, a bundle is a structured setof files (PHP files, stylesheets, JavaScripts, images, ...) that implements a single feature (a blog, a forum,...) and which can be easily shared with other developers. As of now, you have manipulated one bundle,AcmeDemoBundle. You will learn more about bundles in the last part of this tutorial.

Working with EnvironmentsNow that you have a better understanding of how Symfony2 works, take a closer look at the bottom ofany Symfony2 rendered page. You should notice a small bar with the Symfony2 logo. This is the "WebDebug Toolbar", and it is a Symfony2 developer's best friend!

3. http://twig.sensiolabs.org/

PDF brought to you bygenerated on June 11, 2014

Chapter 1: The Big Picture | 9

Page 10: Symfony Quick Tour 2.5

Listing 1-14

But what you see initially is only the tip of the iceberg; click on any of the bar sections to open the profilerand get much more detailed information about the request, the query parameters, security details, anddatabase queries:

Of course, it would be unwise to have this tool enabled when you deploy your application, so by default,the profiler is not enabled in the prod environment.

What is an Environment?

An Environment represents a group of configurations that's used to run your application. Symfony2defines two environments by default: dev (suited for when developing the application locally) and prod(optimized for when executing the application on production).

Typically, the environments share a large amount of configuration options. For that reason, you put yourcommon configuration in config.yml and override the specific configuration file for each environmentwhere necessary:

PDF brought to you bygenerated on June 11, 2014

Chapter 1: The Big Picture | 10

Page 11: Symfony Quick Tour 2.5

Listing 1-15

1234567

# app/config/config_dev.ymlimports:

- { resource: config.yml }

web_profiler:toolbar: trueintercept_redirects: false

In this example, the dev environment loads the config_dev.yml configuration file, which itself importsthe common config.yml file and then modifies it by enabling the web debug toolbar.

When you visit the app_dev.php file in your browser, you're executing your Symfony application in thedev environment. To visit your application in the prod environment, visit the app.php file instead.

The demo routes in our application are only available in the dev environment. Therefore, if you try toaccess the http://localhost/app.php/demo/hello/Fabien URL, you'll get a 404 error.

If instead of using PHP's built-in webserver, you use Apache with mod_rewrite enabled and takeadvantage of the .htaccess file Symfony2 provides in web/, you can even omit the app.php partof the URL. The default .htaccess points all requests to the app.php front controller:

1 http://localhost/demo/hello/Fabien

For more details on environments, see "Environments & Front Controllers" article.

Final ThoughtsCongratulations! You've had your first taste of Symfony2 code. That wasn't so hard, was it? There's a lotmore to explore, but you should already see how Symfony2 makes it really easy to implement web sitesbetter and faster. If you are eager to learn more about Symfony2, dive into the next section: "The View".

PDF brought to you bygenerated on June 11, 2014

Chapter 1: The Big Picture | 11

Page 12: Symfony Quick Tour 2.5

Listing 2-1

Chapter 2

The View

After reading the first part of this tutorial, you have decided that Symfony2 was worth another 10minutes. In this second part, you will learn more about Twig1, the fast, flexible, and secure templateengine for PHP. Twig makes your templates more readable and concise; it also makes them more friendlyfor web designers.

Getting familiar with Twig

The official Twig documentation2 is the best resource to learn everything about this new template engine.This section just gives you a quick overview of its main concepts.

A Twig template is a text file that can generate any type of content (HTML, CSS, JavaScript, XML,CSV, LaTeX, ...). Twig elements are separated from the rest of the template contents using any of thesedelimiters:

• {{ ... }}: prints the content of a variable or the result of an expression;• {% ... %}: controls the logic of the template; it is used for example to execute for loops and

if statements;• {# ... #}: allows including comments inside templates.

Below is a minimal template that illustrates a few basics, using two variables page_title andnavigation, which would be passed into the template:

123456789

<!DOCTYPE html><html>

<head><title>{{ page_title }}</title>

</head><body>

<h1>{{ page_title }}</h1>

<ul id="navigation">

1. http://twig.sensiolabs.org/

2. http://twig.sensiolabs.org/documentation

PDF brought to you bygenerated on June 11, 2014

Chapter 2: The View | 12

Page 13: Symfony Quick Tour 2.5

Listing 2-2

Listing 2-3

Listing 2-4

101112131415

{% for item in navigation %}<li><a href="{{ item.url }}">{{ item.label }}</a></li>

{% endfor %}</ul>

</body></html>

To render a template in Symfony, use the render method from within a controller and pass the variablesneeded as an array using the optional second argument:

123

$this->render('AcmeDemoBundle:Demo:hello.html.twig', array('name' => $name,

));

Variables passed to a template can be strings, arrays, or even objects. Twig abstracts the differencebetween them and lets you access "attributes" of a variable with the dot (.) notation. The following codelisting shows how to display the content of a variable depending on the type of the variable passed by thecontroller:

123456789

10111213141516171819

{# 1. Simple variables #}{# array('name' => 'Fabien') #}{{ name }}

{# 2. Arrays #}{# array('user' => array('name' => 'Fabien')) #}{{ user.name }}

{# alternative syntax for arrays #}{{ user['name'] }}

{# 3. Objects #}{# array('user' => new User('Fabien')) #}{{ user.name }}{{ user.getName }}

{# alternative syntax for objects #}{{ user.name() }}{{ user.getName() }}

Decorating TemplatesMore often than not, templates in a project share common elements, like the well-known header andfooter. Twig solves this problem elegantly with a concept called "template inheritance". This featureallows you to build a base "layout" template that contains all the common elements of your site anddefines "blocks" that child templates can override.

The hello.html.twig template uses the extends tag to indicate that it inherits from the commonlayout.html.twig template:

12345

{# src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig #}{% extends "AcmeDemoBundle::layout.html.twig" %}

{% block title "Hello " ~ name %}

PDF brought to you bygenerated on June 11, 2014

Chapter 2: The View | 13

Page 14: Symfony Quick Tour 2.5

Listing 2-5

Listing 2-6

Listing 2-7

Listing 2-8

678

{% block content %}<h1>Hello {{ name }}!</h1>

{% endblock %}

The AcmeDemoBundle::layout.html.twig notation sounds familiar, doesn't it? It is the same notationused to reference a regular template. The :: part simply means that the controller element is empty, sothe corresponding file is directly stored under the Resources/views/ directory of the bundle.

Now, simplify the layout.html.twig template:

12345

{# src/Acme/DemoBundle/Resources/views/layout.html.twig #}<div>

{% block content %}{% endblock %}

</div>

The {% block %} tags tell the template engine that a child template may override those portions of thetemplate. In this example, the hello.html.twig template overrides the content block, meaning that the"Hello Fabien" text is rendered inside the <div> element.

Using Tags, Filters, and FunctionsOne of the best feature of Twig is its extensibility via tags, filters, and functions. Take a look at thefollowing sample template that uses filters extensively to modify the information before displaying it tothe user:

1234567

<h1>{{ article.title|trim|capitalize }}</h1>

<p>{{ article.content|striptags|slice(0, 1024) }}</p>

<p>Tags: {{ article.tags|sort|join(", ") }}</p>

<p>Next article will be published on {{ 'next Monday'|date('M j, Y')}}</p>

Don't forget to check out the official Twig documentation3 to learn everything about filters, functions andtags.

Including other Templates

The best way to share a snippet of code between several templates is to create a new template fragmentthat can then be included from other templates.

First, create an embedded.html.twig template:

12

{# src/Acme/DemoBundle/Resources/views/Demo/embedded.html.twig #}Hello {{ name }}

And change the index.html.twig template to include it:

12

{# src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig #}{% extends "AcmeDemoBundle::layout.html.twig" %}

3. http://twig.sensiolabs.org/documentation

PDF brought to you bygenerated on June 11, 2014

Chapter 2: The View | 14

Page 15: Symfony Quick Tour 2.5

Listing 2-9

Listing 2-10

Listing 2-11

Listing 2-12

34567

{# override the body block from embedded.html.twig #}{% block content %}

{{ include("AcmeDemoBundle:Demo:embedded.html.twig") }}{% endblock %}

Embedding other Controllers

And what if you want to embed the result of another controller in a template? That's very useful whenworking with Ajax, or when the embedded template needs some variable not available in the maintemplate.

Suppose you've created a topArticlesAction controller method to display the most popular articles ofyour website. If you want to "render" the result of that method (e.g. HTML) inside the index template, usethe render function:

12

{# src/Acme/DemoBundle/Resources/views/Demo/index.html.twig #}{{ render(controller("AcmeDemoBundle:Demo:topArticles", {'num': 10})) }}

Here, the AcmeDemoBundle:Demo:topArticles string refers to the topArticlesAction action of theDemo controller, and the num argument is made available to the controller:

123456789

10111213141516

// src/Acme/DemoBundle/Controller/DemoController.php

class DemoController extends Controller{

public function topArticlesAction($num){

// look for the $num most popular articles in the database$articles = ...;

return $this->render('AcmeDemoBundle:Demo:topArticles.html.twig', array('articles' => $articles,

));}

// ...}

Creating Links between Pages

Creating links between pages is a must for web applications. Instead of hardcoding URLs in templates,the path function knows how to generate URLs based on the routing configuration. That way, all yourURLs can be easily updated by just changing the configuration:

1 <a href="{{ path('_demo_hello', { 'name': 'Thomas' }) }}">Greet Thomas!</a>

The path function takes the route name and an array of parameters as arguments. The route name is thekey under which routes are defined and the parameters are the values of the variables defined in the routepattern:

12

// src/Acme/DemoBundle/Controller/DemoController.phpuse Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

PDF brought to you bygenerated on June 11, 2014

Chapter 2: The View | 15

Page 16: Symfony Quick Tour 2.5

Listing 2-13

3456789

1011121314

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

// ...

/*** @Route("/hello/{name}", name="_demo_hello")* @Template()*/public function helloAction($name){

return array('name' => $name);}

The url function is very similar to the path function, but generates absolute URLs, which is veryhandy when rendering emails and RSS files: {{ url('_demo_hello', {'name': 'Thomas'}) }}.

Including Assets: Images, JavaScripts and Stylesheets

What would the Internet be without images, JavaScripts, and stylesheets? Symfony2 provides the assetfunction to deal with them easily:

123

<link href="{{ asset('css/blog.css') }}" rel="stylesheet" type="text/css" />

<img src="{{ asset('images/logo.png') }}" />

The asset function's main purpose is to make your application more portable. Thanks to this function,you can move the application root directory anywhere under your web root directory without changinganything in your template's code.

Final ThoughtsTwig is simple yet powerful. Thanks to layouts, blocks, templates and action inclusions, it is very easy toorganize your templates in a logical and extensible way. However, if you're not comfortable with Twig,you can always use PHP templates inside Symfony without any issues.

You have only been working with Symfony2 for about 20 minutes, but you can already do pretty amazingstuff with it. That's the power of Symfony2. Learning the basics is easy, and you will soon learn that thissimplicity is hidden under a very flexible architecture.

But I'm getting ahead of myself. First, you need to learn more about the controller and that's exactly thetopic of the next part of this tutorial. Ready for another 10 minutes with Symfony2?

PDF brought to you bygenerated on June 11, 2014

Chapter 2: The View | 16

Page 17: Symfony Quick Tour 2.5

Listing 3-1

Listing 3-2

Chapter 3

The Controller

Still here after the first two parts? You are already becoming a Symfony2 addict! Without further ado,discover what controllers can do for you.

Using FormatsNowadays, a web application should be able to deliver more than just HTML pages. From XML for RSSfeeds or Web Services, to JSON for Ajax requests, there are plenty of different formats to choose from.Supporting those formats in Symfony2 is straightforward. Tweak the route by adding a default value ofxml for the _format variable:

123456789

1011121314

// src/Acme/DemoBundle/Controller/DemoController.phpuse Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

// ...

/*** @Route("/hello/{name}", defaults={"_format"="xml"}, name="_demo_hello")* @Template()*/public function helloAction($name){

return array('name' => $name);}

By using the request format (as defined by the special _format variable), Symfony2 automatically selectsthe right template, here hello.xml.twig:

1234

<!-- src/Acme/DemoBundle/Resources/views/Demo/hello.xml.twig --><hello>

<name>{{ name }}</name></hello>

PDF brought to you bygenerated on June 11, 2014

Chapter 3: The Controller | 17

Page 18: Symfony Quick Tour 2.5

Listing 3-3

Listing 3-4

Listing 3-5

Listing 3-6

That's all there is to it. For standard formats, Symfony2 will also automatically choose the best Content-Type header for the response. If you want to support different formats for a single action, use the{_format} placeholder in the route path instead:

123456789

10111213141516171819

// src/Acme/DemoBundle/Controller/DemoController.phpuse Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

// ...

/*** @Route(* "/hello/{name}.{_format}",* defaults = { "_format" = "html" },* requirements = { "_format" = "html|xml|json" },* name = "_demo_hello"* )* @Template()*/public function helloAction($name){

return array('name' => $name);}

The controller will now match URLs like /demo/hello/Fabien.xml or /demo/hello/Fabien.json.

The requirements entry defines regular expressions that variables must match. In this example, if youtry to request the /demo/hello/Fabien.js resource, you will get a 404 HTTP error, as it does not matchthe _format requirement.

Redirecting and ForwardingIf you want to redirect the user to another page, use the redirect() method:

1 return $this->redirect($this->generateUrl('_demo_hello', array('name' => 'Lucas')));

The generateUrl() is the same method as the path() function used in the templates. It takes the routename and an array of parameters as arguments and returns the associated friendly URL.

You can also internally forward the action to another using the forward() method:

1234

return $this->forward('AcmeDemoBundle:Hello:fancy', array('name' => $name,'color' => 'green'

));

Displaying Error PagesErrors will inevitably happen during the execution of every web application. In the case of 404 errors,Symfony includes a handy shortcut that you can use in your controllers:

1 throw $this->createNotFoundException();

PDF brought to you bygenerated on June 11, 2014

Chapter 3: The Controller | 18

Page 19: Symfony Quick Tour 2.5

Listing 3-7

Listing 3-8

Listing 3-9

Listing 3-10

For 500 errors, just throw a regular PHP exception inside the controller and Symfony will transform itinto a proper 500 error page:

1 throw new \Exception('Something went wrong!');

Getting Information from the RequestSymfony automatically injects the Request object when the controller has an argument that's type hintedwith Symfony\Component\HttpFoundation\Request:

123456789

101112

use Symfony\Component\HttpFoundation\Request;

public function indexAction(Request $request){

$request->isXmlHttpRequest(); // is it an Ajax request?

$request->getPreferredLanguage(array('en', 'fr'));

$request->query->get('page'); // get a $_GET parameter

$request->request->get('page'); // get a $_POST parameter}

In a template, you can also access the Request object via the app.request variable:

123

{{ app.request.query.get('page') }}

{{ app.request.parameter('page') }}

Persisting Data in the SessionEven if the HTTP protocol is stateless, Symfony2 provides a nice session object that represents the client(be it a real person using a browser, a bot, or a web service). Between two requests, Symfony2 stores theattributes in a cookie by using native PHP sessions.

Storing and retrieving information from the session can be easily achieved from any controller:

123456789

101112131415

use Symfony\Component\HttpFoundation\Request;

public function indexAction(Request $request){

$session = $this->request->getSession();

// store an attribute for reuse during a later user request$session->set('foo', 'bar');

// get the value of a session attribute$foo = $session->get('foo');

// use a default value if the attribute doesn't exist$foo = $session->get('foo', 'default_value');

}

PDF brought to you bygenerated on June 11, 2014

Chapter 3: The Controller | 19

Page 20: Symfony Quick Tour 2.5

Listing 3-11

Listing 3-12

Listing 3-13

You can also store "flash messages" that will auto-delete after the next request. They are useful whenyou need to set a success message before redirecting the user to another page (which will then show themessage):

12

// store a message for the very next request (in a controller)$session->getFlashBag()->add('notice', 'Congratulations, your action succeeded!');

12

{# display the flash message in the template #}<div>{{ app.session.flashbag.get('notice') }}</div>

Caching ResourcesAs soon as your website starts to generate more traffic, you will want to avoid generating the sameresource again and again. Symfony2 uses HTTP cache headers to manage resources cache. For simplecaching strategies, use the convenient @Cache() annotation:

123456789

10111213

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;

/*** @Route("/hello/{name}", name="_demo_hello")* @Template()* @Cache(maxage="86400")*/public function helloAction($name){

return array('name' => $name);}

In this example, the resource will be cached for a day (86400 seconds). Resource caching is managedby Symfony2 itself. But because caching is managed using standard HTTP cache headers, you can useVarnish or Squid without having to modify a single line of code in your application.

Final ThoughtsThat's all there is to it, and I'm not even sure you'll have spent the full 10 minutes. You were brieflyintroduced to bundles in the first part, and all the features you've learned about so far are part of the coreframework bundle. But thanks to bundles, everything in Symfony2 can be extended or replaced. That'sthe topic of the next part of this tutorial.

PDF brought to you bygenerated on June 11, 2014

Chapter 3: The Controller | 20

Page 21: Symfony Quick Tour 2.5

Listing 4-1

Chapter 4

The Architecture

You are my hero! Who would have thought that you would still be here after the first three parts? Yourefforts will be well rewarded soon. The first three parts didn't look too deeply at the architecture ofthe framework. Because it makes Symfony2 stand apart from the framework crowd, let's dive into thearchitecture now.

Understanding the Directory StructureThe directory structure of a Symfony2 application is rather flexible, but the recommended structure is asfollows:

• app/: the application configuration;• src/: the project's PHP code;• vendor/: the third-party dependencies;• web/: the web root directory.

The web/ Directory

The web root directory is the home of all public and static files like images, stylesheets, and JavaScriptfiles. It is also where each front controller lives:

123456789

// web/app.phprequire_once __DIR__.'/../app/bootstrap.php.cache';require_once __DIR__.'/../app/AppKernel.php';

use Symfony\Component\HttpFoundation\Request;

$kernel = new AppKernel('prod', false);$kernel->loadClassCache();$kernel->handle(Request::createFromGlobals())->send();

The controller first bootstraps the application using a kernel class (AppKernel in this case). Then, itcreates the Request object using the PHP's global variables and passes it to the kernel. The last step is tosend the response contents returned by the kernel back to the user.

PDF brought to you bygenerated on June 11, 2014

Chapter 4: The Architecture | 21

Page 22: Symfony Quick Tour 2.5

Listing 4-2

The app/ Directory

The AppKernel class is the main entry point of the application configuration and as such, it is stored inthe app/ directory.

This class must implement two methods:

• registerBundles() must return an array of all bundles needed to run the application;• registerContainerConfiguration() loads the application configuration (more on this

later).

Autoloading is handled automatically via Composer1, which means that you can use any PHP classwithout doing anything at all! All dependencies are stored under the vendor/ directory, but this is just aconvention. You can store them wherever you want, globally on your server or locally in your projects.

Understanding the Bundle SystemThis section introduces one of the greatest and most powerful features of Symfony2, the bundle system.

A bundle is kind of like a plugin in other software. So why is it called a bundle and not a plugin? This isbecause everything is a bundle in Symfony2, from the core framework features to the code you write foryour application.

Bundles are first-class citizens in Symfony2. This gives you the flexibility to use pre-built featurespackaged in third-party bundles or to distribute your own bundles. It makes it easy to pick and choosewhich features to enable in your application and optimize them the way you want. And at the end of theday, your application code is just as important as the core framework itself.

Registering a Bundle

An application is made up of bundles as defined in the registerBundles() method of the AppKernelclass. Each bundle is a directory that contains a single Bundle class that describes it:

123456789

1011121314151617181920212223

// app/AppKernel.phppublic function registerBundles(){

$bundles = array(new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),new Symfony\Bundle\SecurityBundle\SecurityBundle(),new Symfony\Bundle\TwigBundle\TwigBundle(),new Symfony\Bundle\MonologBundle\MonologBundle(),new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),new Symfony\Bundle\DoctrineBundle\DoctrineBundle(),new Symfony\Bundle\AsseticBundle\AsseticBundle(),new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),

);

if (in_array($this->getEnvironment(), array('dev', 'test'))) {$bundles[] = new Acme\DemoBundle\AcmeDemoBundle();$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();$bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle();$bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();

}

return $bundles;}

1. http://getcomposer.org

PDF brought to you bygenerated on June 11, 2014

Chapter 4: The Architecture | 22

Page 23: Symfony Quick Tour 2.5

Listing 4-3

In addition to the AcmeDemoBundle that was already talked about, notice that the kernel also enablesother bundles such as the FrameworkBundle, DoctrineBundle, SwiftmailerBundle and AsseticBundlebundle. They are all part of the core framework.

Configuring a Bundle

Each bundle can be customized via configuration files written in YAML, XML, or PHP. Have a look atthe default Symfony configuration:

123456789

1011121314151617181920212223242526272829303132333435363738394041424344454647484950

# app/config/config.ymlimports:

- { resource: parameters.yml }- { resource: security.yml }

framework:#esi: ~#translator: { fallback: "%locale%" }secret: "%secret%"router:

resource: "%kernel.root_dir%/config/routing.yml"strict_requirements: "%kernel.debug%"

form: truecsrf_protection: truevalidation: { enable_annotations: true }templating: { engines: ['twig'] } #assets_version: SomeVersionSchemedefault_locale: "%locale%"trusted_proxies: ~session: ~

# Twig Configurationtwig:

debug: "%kernel.debug%"strict_variables: "%kernel.debug%"

# Assetic Configurationassetic:

debug: "%kernel.debug%"use_controller: falsebundles: [ ]#java: /usr/bin/javafilters:

cssrewrite: ~#closure:# jar: "%kernel.root_dir%/Resources/java/compiler.jar"#yui_css:# jar: "%kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar"

# Doctrine Configurationdoctrine:

dbal:driver: "%database_driver%"host: "%database_host%"port: "%database_port%"dbname: "%database_name%"user: "%database_user%"password: "%database_password%"charset: UTF8

orm:

PDF brought to you bygenerated on June 11, 2014

Chapter 4: The Architecture | 23

Page 24: Symfony Quick Tour 2.5

Listing 4-4

51525354555657585960

auto_generate_proxy_classes: "%kernel.debug%"auto_mapping: true

# Swift Mailer Configurationswiftmailer:

transport: "%mailer_transport%"host: "%mailer_host%"username: "%mailer_user%"password: "%mailer_password%"spool: { type: memory }

Each first level entry like framework, twig or doctrine defines the configuration for a specific bundle.For example, framework configures the FrameworkBundle while swiftmailer configures theSwiftmailerBundle.

Each environment can override the default configuration by providing a specific configuration file. Forexample, the dev environment loads the config_dev.yml file, which loads the main configuration (i.e.config.yml) and then modifies it to add some debugging tools:

123456789

101112131415161718192021222324

# app/config/config_dev.ymlimports:

- { resource: config.yml }

framework:router: { resource: "%kernel.root_dir%/config/routing_dev.yml" }profiler: { only_exceptions: false }

web_profiler:toolbar: trueintercept_redirects: false

monolog:handlers:

main:type: streampath: "%kernel.logs_dir%/%kernel.environment%.log"level: debug

firephp:type: firephplevel: info

assetic:use_controller: true

Extending a Bundle

In addition to being a nice way to organize and configure your code, a bundle can extend another bundle.Bundle inheritance allows you to override any existing bundle in order to customize its controllers,templates, or any of its files. This is where the logical names (e.g. @AcmeDemoBundle/Controller/SecuredController.php) come in handy: they abstract where the resource is actually stored.

Logical File Names

When you want to reference a file from a bundle, use this notation: @BUNDLE_NAME/path/to/file;Symfony2 will resolve @BUNDLE_NAME to the real path to the bundle. For instance, the logical path@AcmeDemoBundle/Controller/DemoController.php would be converted to src/Acme/DemoBundle/Controller/DemoController.php, because Symfony knows the location of the AcmeDemoBundle.

PDF brought to you bygenerated on June 11, 2014

Chapter 4: The Architecture | 24

Page 25: Symfony Quick Tour 2.5

Listing 4-5

Logical Controller Names

For controllers, you need to reference method names using the formatBUNDLE_NAME:CONTROLLER_NAME:ACTION_NAME. For instance, AcmeDemoBundle:Welcome:index maps tothe indexAction method from the Acme\DemoBundle\Controller\WelcomeController class.

Logical Template Names

For templates, the logical name AcmeDemoBundle:Welcome:index.html.twig is converted to the filepath src/Acme/DemoBundle/Resources/views/Welcome/index.html.twig. Templates become evenmore interesting when you realize they don't need to be stored on the filesystem. You can easily storethem in a database table for instance.

Extending Bundles

If you follow these conventions, then you can use bundle inheritance to "override" files, controllersor templates. For example, you can create a bundle - AcmeNewBundle - and specify that it overridesAcmeDemoBundle. When Symfony loads the AcmeDemoBundle:Welcome:index controller, it will firstlook for the WelcomeController class in AcmeNewBundle and, if it doesn't exist, then look insideAcmeDemoBundle. This means that one bundle can override almost any part of another bundle!

Do you understand now why Symfony2 is so flexible? Share your bundles between applications, storethem locally or globally, your choice.

Using VendorsOdds are that your application will depend on third-party libraries. Those should be stored in thevendor/ directory. This directory already contains the Symfony2 libraries, the SwiftMailer library, theDoctrine ORM, the Twig templating system, and some other third party libraries and bundles.

Understanding the Cache and LogsSymfony2 is probably one of the fastest full-stack frameworks around. But how can it be so fast if itparses and interprets tens of YAML and XML files for each request? The speed is partly due to its cachesystem. The application configuration is only parsed for the very first request and then compiled down toplain PHP code stored in the app/cache/ directory. In the development environment, Symfony2 is smartenough to flush the cache when you change a file. But in the production environment, to speed thingsup, it is your responsibility to clear the cache when you update your code or change its configuration.

When developing a web application, things can go wrong in many ways. The log files in the app/logs/directory tell you everything about the requests and help you fix the problem quickly.

Using the Command Line InterfaceEach application comes with a command line interface tool (app/console) that helps you maintain yourapplication. It provides commands that boost your productivity by automating tedious and repetitivetasks.

Run it without any arguments to learn more about its capabilities:

1 $ php app/console

The --help option helps you discover the usage of a command:

PDF brought to you bygenerated on June 11, 2014

Chapter 4: The Architecture | 25

Page 26: Symfony Quick Tour 2.5

Listing 4-6 1 $ php app/console router:debug --help

Final ThoughtsCall me crazy, but after reading this part, you should be comfortable with moving things around andmaking Symfony2 work for you. Everything in Symfony2 is designed to get out of your way. So, feel freeto rename and move directories around as you see fit.

And that's all for the quick tour. From testing to sending emails, you still need to learn a lot to become aSymfony2 master. Ready to dig into these topics now? Look no further - go to the official The Book andpick any topic you want.

PDF brought to you bygenerated on June 11, 2014

Chapter 4: The Architecture | 26

Page 27: Symfony Quick Tour 2.5
Page 28: Symfony Quick Tour 2.5