Controller

// First variant
public function action(Request $request)
{
    $qet = $request->query->all(); to get all GET params
    $post = $request->request->all(); to get all POST params.
    $cookies = $request->cookies->all(); to get all cookies params.
    $files = $request->files->all(); to get all files params.
    $session = $request->getSession();
    $session->set('foo', 'bar');
    $filters = $session->get('filters', array());

    // $_GET parameters
    $request->query->get('name');
    $request->query->get('name', 'default value');
    // $_POST parameters
    $request->request->get('name');

    $params = $request->request->all();
    $params['value1'];
}

// Second variant
public function dataAction(Request $request, $foo, $bar)
{
    echo $foo;
    echo $bar;
}

// which, then assumes that you defined {foo} and {bar} as part of your URL pattern in your routing.yml file:
myurl:
    pattern:  /{foo}/{bar}
    defaults: { _controller: NameBundle:Default:getdata }

// $this->addFlash is equivalent to $this->get('session')->getFlashBag()->add
$this->addFlash('notice', 'Your changes were saved!');

{% for flashMessage in app.session.flashbag.get('notice') %}
    <div class="flash-notice">
        {{ flashMessage }}
    </div>
{% endfor %}

Simple controller

/**
* @Route("/hello/{name}", name="hello")
*/
public function indexAction($name)
{
    return new Response('<html><body>Hello '.$name.'!</body></html>');
}

return $this->redirectToRoute('homepage', array(), 301);
return $this->redirectToRoute('homepage'); // equivalent redirect()
// return $this->redirect($this->generateUrl('homepage'), 301);

return $this->redirect('http://symfony.com/doc');

return $this->forward('AppBundle:Something:fancy', array(
    'name'  => $name,
    'color' => 'green',
));

// create a JSON-response with a 200 status code
$response = new Response(json_encode(array('name' => $name)));
$response->headers->set('Content-Type', 'application/json');

// 404 error
throw $this->createNotFoundException('The product does not exist');
// The createNotFoundException() method is just a shortcut to create a special NotFoundHttpException object, which ultimately triggers a 404 HTTP response inside Symfony.

throw new \Exception('Something went wrong!'); // 500 error

// renders app/Resources/views/hello/greetings/index.html.twig
return $this->render('hello/greetings/index.html.twig', array(
    'name' => $name
));

// Access any Symfony service via the get()
$templating = $this->get('templating');
$router = $this->get('router');
// get traslator for translated data
$translated = $this->get('translator');
$message = $translated->trans('submit', array(''), 'NameBundle');

Twig operators

[not] in  - check in;                      {% for user in users %}
is [not]  - test operator;                 {% if online == false %}
..        - create a sequence;             {% for i in 0..10 %}
|         - filter;                        {{ post.published_at|date("m/d/Y") }}
                                           {% filter upper %}
                                                Text uppercase
                                           {% endfilter %}
~         - concatenation;                 {{ 'http://' ~ app.request.host }}
. or []   - get an attribute of an object; {{ app.user }} {{ post[0] }}
?:        - ternary operator;              {{ foo ?: 'no' }}
                                           is the same as {{ foo ? foo : 'no' }}
{{  }}    - print the result;              {{ companyName }}
{%  %}    - execute statements;            {% set index = 0 %}
                                           {% set text %}
                                               <div id="text">
                                                    Main Text
                                               </div>
                                           {% endset %}
{#  #}    - comment                        {# This is comment #}

{% macro sum(value, valueAdd) %}
   <div>Summ: {{ value + valueAdd }}</div>
{% endmacro %}

{% import "form.html" as form %}
{% from 'form.html' import input as input_field %}

{{ '{{' }} - escaping

{% raw %}
    {% set value = 'Text escaping' %}
    <h1>{{ value }}</h1>
{% endraw %}


Popular filters
date        {{ post.createdAt|date("d.m.Y") }}
format      {{ "My text %s with %s|format('block', 'samples') }}
replace     {{ "Text %block%|replace({'%block%': 'menu'}) }}
url_encode  URL encodes a string
json_encode Get JSON of a string
upper       Get uppercase of a value
lower       Get lowercase of a value
join
reverse     Reverses an array
length      Count items
sort        Sort an array
default     Set default value {{ var|default('is not defined') }}
keys        {% for key in items|keys %}   {% endfor %}
escape      HTML - safe
raw         Without escaped
merge       Merge array]
abs         Abs
trim        Trim of string

constant    {% if var is constant('FOO::BAR') %}    {% endif %}
even        {% if var is even %}    {% endif %}
odd         {% if var is odd %}    {% endif %}
defined     {% if var is defined %}    {% endif %}
empty       {% if var is empty %}    {% endif %}

constant    {{ date.createdAt|date(constant('MY_DATE_FORMAT')) }}

Twig Control Structures

{% for item in collection %} {{ item }} {% endfor %}
{% for i in 0..20 %} {{ i }} {% endfor %}
{% for key, item in items %} {{ key }} : {{ item }} {% endfor %}

{% for item in collection %}
    {{ loop.index }} {# Current iteration of the loop #}
    {{ loop.first }} {# Is first iteration #}
    {{ loop.last }} {# Is last iteration #}
    {{ loop.length }} {# Count items #}
{% endfor %}

{% if (condition) %} {% elseif %} {% else %} {% endif %}

{% block menu %} <div class="menu"></div>  {% endblock %}

{% extends "parent.html.twig" %} - Extends a template

{% include "layout.html.twig" %} - Include a template
{% include "layout.html.twig" with { 'foo' : 'bar' } %}

{% use "my_block.html.twig" %} - Import block from a template
{% use "my_block.html.twig" with menu as block_menu %}

{{ block('block_menu') }} - Call a block

{% autoescape %} This text will be escaped {% endautoescape %}
{% autoescape 'html' %} This text will be escaped using HTML strategy {% endautoescape %}
{% autoescape false %} This text will not be escaped {% endautoescape %}


# Generate URL
{{ path('route_name', {'param': 'value'}) }}
{{ url('route_name') - absolute URL
 <img src="{{ asset("images/favicon.png") }}" />

# Debug
{{ dump(object) }}
{{ dump() }} {# show all variables in twig #}

Global TWIG variables
app.security
app.user
app.request
app.request.get('foo') // get
app.request.request.get('bar') // post
app.session
app.environment
app.debug

Console commands

< > required
[ ] optional

// usage
php app/console [options] command [arguments]

--help           -h Display help message
--quiet          -q Do not output any message
--verbose        -v Increase verbosity of messages
--version        -V Display application version
--ansi              Force ANSI output
--no-ansi           Disable ANSI output
--no-interaction -n Do not as any interactive question
--shell          -s Launch the shell
--env            -e The Environment name
--no-debug          Switch off debug mode


php app/console [list]  -  List available commands and show the Symfony version
php app/console help [command]  -  Displays help for a command
php app/console container:debug [--show-private] [service_name]  -  Display all configured public services
php app/console assetic:dump [--watch] [--force] [--period=...] [write_to]  -  Dumps all assets to the filesystem
php app/console config:dump-reference <bundle_or_extension_alias>  -  Dumps the default configuration for a bundle
php app/console translation:update [--prefix=...] [--update-format=...]  -  Extract translation strings from templates
                          [--dump-messages] [--force] <locale> <bundle>     of a given bundle.
php app/console twig:lint <filename>

php app/console cache:clear [--no-warmup] [--no-optional-warmers]  -  Clear the cache
php app/console cache:warmup [--no-optional-warmers]  -  Warms up an empty cache

php app/console router:debug [route_name]  -  Displays current routes for an application
php app/console router:dump-apache [--base-uri=...] [script_name]  -  Dumps all routes
php app/console router:match <path_info>  -  Debug routes by match
php app/console fos:js-routing:debug <name>  -  Displays current exposed routes

php app/console assets:install [--symlink] [--relative] <target_dir>  -  Install bundles web assets
php app/console generate:bundle [--namespace=...] [--dir=...]  -  Generate a bundle
             [--bundle-name=...] [--format=...] [--structure]
php app/console fos:user:activate <username>  -  Activate an user
php app/console fos:user:deactivate <username>  -  Disable an user
php app/console fos:user:promote [--super] <username> [role]  -  Add role
php app/console fos:user:demote [--super] <username> [role]  -  Remove role
php app/console fos:user:create [--inactive] <username> [email] [password] [--super-admin]  -  Create an user
php app/console fos:user:change-password <username> <password>  -  Change password

php app/console doctrine:cache:clear-metadata [--em=...] [--flush]  -  Clears all metadata cache
php app/console doctrine:cache:clear-query [--em=...] [--flush]  -  Clears all query cache
php app/console doctrine:cache:clear-result [--em=...] [--flush]  -  Clears all result cache
php app/console doctrine:database:create [--connection=...]  -  Creates a database
php app/console doctrine:database:drop [--connection=...] [--force]  -  Drop a database
php app/console doctrine:mapping:convert [--filter=...] [--force] [--from-database]  -  Converts mapping information
    [--extend=...] [--num-spaces=...] [--namespace=...] [--em=...] <to-type> <dest-path>
php app/console doctrine:mapping:import [--em=...] [--filter=...] [--force]  -  Imports mapping information
    <bundle> <mapping-type>
php app/console doctrine:mapping:info [--em=...]  -  Show basic information
php app/console doctrine:generate:entity [--entity=...] [--fields=...] [--format=...] [--with-repository]  -  Generates a new Doctrine entity
php app/console doctrine:generate:entities [--path=...] [--no-backup] <name>  -  Generates entity classes and methods
php app/console doctrine:generate:form <entity>  -  Generates a form class based on a Doctrine entity
php app/console doctrine:generate:crud [--entity=...] [--route-prefix=...] [--with-write] [--format=...]  -  Generates a CRUD based on a Doctrine entity
php app/console doctrine:query:dql [--hydrate=...] [--first-result=...]  -  Executes arbitrary DQL directly
    [--max-result=...] [--depth=...] [--em=...] <dql_to_execute>
php app/console doctrine:query:sql [--depth=...] [--connection=...] <sql_to_execute>  -  Executes arbitrary SQL directly
php app/console doctrine:schema:create [--dump-sql] [--em=...]  -  Executes the SQL needed to generate the database
php app/console doctrine:schema:drop [--dump-sql] [--force] [--full-database] [--em=...]  -  Executes the SQL needed to drop the database
php app/console doctrine:schema:update [--complete] [--dump-sql] [--force] [--em=...]  -  Executes the SQL needed to update the database
php app/console doctrine:schema:validate [--em=...]  -  Validates the Doctrine mapping files
php app/console doctrine:ensure-production-settings [--complete] [--em=...]  -  Check Doctrine configured for a production environment
php app/console doctrine:fixtures:load [--fixtures=...] [--append] [--em=...] [--purge-with-truncate]  -  Load data fixtures to your database

php app/console api:doc:dump [--format="..."]
    

Routing

framework:
    router: { resource: "%kernel.root_dir%/config/routing.yml" }

// Defining custom routes:
hello_yml:
    resource: "@NameBundle/Resources/config/routing.yml"
hello_annotation:
    resource: "@NameBundle/Controller/NameController.php"
    type:     annotation

// Prefix
prefix_yml:
    resource: "@NameBundle/Resources/config/routing.yml"
    prefix: /admin
// Prefix annotation
/**
 * @Route("/blog")
 */
class NameController extends Controller
{
    /**
     * @Route("/{id}")
     */
    public function showAction($id)
    {
    }
}

Route: http://www.myurl.com/name/en/2
route_name:
    path: /name/{culture}/{page}
    defaults: { _controller: NameBundle:Name:index, page: 1}
    requirments:
        page: \d+
        culture: en|ru
        methods: [GET]
home: # http://host.myurl.com/
    path: /
    host: "{user}.example.com"
    defaults: { _controller: NameBundle:Api:Login }
main:
    path: /
    defaults: { _controller: NameBundle:Main:homepage }

class BlogController extends Controller{
    /**
    * @Route("/blog/ / ", requirements={"page" = "\d+"}, defaults={"page" = 1}, name="blog")
    * @Method({"GET"})
    */
    public function indexAction($page) {
    }
    or
    public function indexAction($page = 1) {
    }
}

// Relative URL
$url = $this->get('router')->generate('blog', array('culture' => 'ru', 'page' => 2)); // /blog/en/2
$urlSlug = $this->get('router')->generate('blog_slug', array('slug' => 'my-post')); // /blog/my-post

// Absolute URL
$url = $this->get('router')->generate('blog', array('culture' => 'ru', 'page' => 2), true); // http://www.url.com/blog/en/2
$urlSlug = $this->get('router')->generate('blog_slug', array('slug' => 'my-post'), true); // http://www.url.com/blog/my-post

Testing

Symfony2 works with PHPUnit

# specify the configuration directory on the command line
$ phpunit -c app/

# run all tests in the Utility directory
$ phpunit -c app src/Acme/DemoBundle/Tests/Utility/

# run tests for the Calculator class
$ phpunit -c app src/Acme/DemoBundle/Tests/Utility/DemoTest.php

# run all tests for the entire Bundle
$ phpunit -c app src/Acme/DemoBundle/

The createClient() method returns a client, which is like a browser that you'll use to crawl your site:
$client = static::createClient();
The request() method returns a Crawler object which can be used to select elements in the Response, click on links, and submit forms.
$crawler = $client->request('GET', '/demo/hello/Fabien');

Validation

Basic
NotBlank 	@Assert\NotBlank()
Blank 	@Assert\Blank()
NotNull 	@Assert\NotNull()
Null 	@Assert\Null()
True 	@Assert\True(message = "The token is invalid")
False 	@Assert\False()
Type 	@Assert\Type(type="integer", message="The value {{ value }} is not a valid {{ type }}.")

String
Email 	@Assert\Email(message = "The email '{{ value }}' is not a valid email.", checkMX = true, checkHost = true)
MinLength 	Assert\MinLength(limit=3, message="Your name must have at least {{ limit }} characters.")
MaxLength 	@Assert\MaxLength(100)
Length 	@Assert\Length( min = "2",max = "50", minMessage = "msg", maxMessage = "msg" )
Url 	@Assert\Url(message="msg1", protocolos=array('http','https')
Regex 	@Assert\Regex("/^\w+/") => options (pattern, match, message)
Ip 	@Assert\Ip

Number
Max 	@Assert\Max(limit=5, message="msg1")
Min 	@Assert\Min(limit=5, message="msg1")
Range 	@Assert\Range(min = "120", max = "180",minMessage = "msg",maxMessage = "msg")

Date
Date 	@Assert\Date()
DateTime 	@Assert\DateTime()
Time 	@Assert\Time()

Collection
Choice 	@Assert\Choice(choices = {"male", "female"}, message = "Choose a valid gender.")
Collection 	http://symfony.com/doc/current/reference/constraints/Collection.html
Count 	@Assert\Count(min = "1", max = "5", minMessage = "msg", maxMessage = "msg" )
UniqueEntity 	@ORM\Column(name="email", type="string", length=255, unique=true) (Suppose you have an AcmeUserBundle bundle with a User entity that has an email field. You can use the UniqueEntity constraint to guarantee that the email field remains unique between all of the constraints in your user table)
Language 	@Assert\Language (Validates that it is a valid language code)
Locale 	@Assert\Locale (Validates a valid Locale code (ej : ISO639-1)
Country 	@Assert\Country (Valid two letter country code)

File
File 	Assert\File(maxSize = "1024k",mimeTypes = {"application/pdf", "application/x-pdf"},mimeeTypesMessage = "msg") http://symfony.com/doc/current/reference/constraints/File.html
Image 	@Assert\Image(minWidth = 200, maxWidth = 400, minHeight = 200, maxHeight = 400) http://symfony.com/doc/current/reference/constraints/Image.html

Other
Callback 	@Assert\Callback(methods={"isAuthorValid"})
All 	@Assert\All({ @Assert\NotBlank @Assert\MinLength(5),}) (Aplies all constraints to each element of the Transversable object)
UserPassword 	@SecurityAssert\UserPassword(message = "Wrong password") (This validates that an input value is equal to the current authenticated user's password.)
Valid 	This constraint is used to enable validation on objects that are embedded as properties on an object being validated. This allows you to validate an object and all sub-objects associated with it. http://symfony.com/doc/current/reference/constraints/Valid.html

// src/Acme/BlogBundle/Entity/Author.php
use Symfony\Component\Validator\Constraints as Assert;

/**
* @Assert\Callback(methods={"isAuthorValid"})
* or more complex example:
* @Assert\Callback(methods={"Acme\BlogBundle\MyStaticValidatorClass", "isAuthorValid"})
*/
class Author
{
    private $firstName;

    public function isAuthorValid(ExecutionContext $context)
    {
        // somehow you have an array of "fake names"
        $fakeNames = array();

        // check if the name is actually a fake name
        if (in_array($this->getFirstName(), $fakeNames)) {
            $context->addViolationAtSubPath('firstname', 'This name sounds totally fake!', array(), null);
        }
    }
}

Forms

// src/Acme/TaskBundle/Controller/DefaultController.php
namespace Acme\TaskBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Acme\TaskBundle\Entity\Task;
use Symfony\Component\HttpFoundation\Request;

class DefaultController extends Controller
{
    public function newAction(Request $request)
    {
    // create a task and give it some dummy data for this example
    $task = $this->createForm(new Task());
    $task->setTask('Write a blog post');
    $task->setDueDate(new \DateTime('tomorrow'));

    $form = $this->createFormBuilder($task)
        ->add('task', 'text')
        ->add('dueDate', 'date')
        ->getForm();

    return $this->render('AcmeTaskBundle:Default:new.html.twig', array(
        'form' => $form->createView()
    ));

    }
}


// src/Acme/TaskBundle/Form/Type/TaskType.php
namespace Acme\TaskBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class TaskType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('task');
        $builder->add('dueDate', null, array('widget' => 'single_text'));

        //Any extra field not mapped to the object must define property_path.
        $builder->add('agree','checkbox', array('property_path' => false));

        //Embedding one form, you need to create first the categoryType class as usual.
        $builder->add('category', new CategoryType());

        //Embedding a collection of TAGS forms. You already have a tagType form.
        $builder->add('tags', 'collection', array('type' => new TagType()));

    }

    public function getName()
    {
        return 'task'; //must be unique.
    }

    //Symfony can guess the type but it is a good practice to always set de data_class because embedding forms is necessary.
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Acme\TaskBundle\Entity\Task',
            'cascade_validation' => true, //needed to validate embeed forms.
            'validation_groups' => array('registration'), //use of validation groups.
            'csrf_protection' => true,
            'csrf_field_name' => '_token',
            // a unique key to help generate the secret token
            'intention' => 'task_item',
        ));
    }

}

<form action="{{ path("task_new") }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<input type="submit" />
</form>


<form action="{{ path("task_new") }}" method="post" {{ form_enctype(form) }}>
{{ form_errors(form) }}

{{ form_row(form.task) }}
{{ form_row(form.dueDate) }}

{{ form_rest(form) }}

<input type="submit" />
</form>


<form action="{{ path("task_new") }}" method="post" {{ form_enctype(form) }}>
{{ form_errors(form) }}
<div>
    {{ form_label(form.task,"custom label") }}
    {{ form_errors(form.task) }}
    {{ form_widget(form.task, { "attr": {"class": "span3"} })) }}
</div>
<div>
    {{ form_label(form.dueDate) }}
    {{ form_errors(form.dueDate) }}
    {{ form_widget(form.dueDate) }}
</div>

{# Render one embedded form #}
<h3>Category</h3>
<div class="category">
    {{ form_row(form.category.name) }}
</div>

{# Render multiple embedded forms #}
<h3>Tags</h3>
<ul class="tags">
    {% for tag in form.tags %}
    <li>{{ form_row(tag.name) }}</li>
    {% endfor %}
</ul>

{{ form_rest(form) }}

</form>

 

// if form has multiple buttons

$request = $this->get('request');
if ($request->request->has('delete'))
{
   ...
}

 

Translation

Translations are handled by a Translator service that uses the user's locale to lookup and return translated messages. Before using it, enable the Translator in your configuration:

# app/config/config.yml
framework:
    translator: { fallback: en }
    default_locale: en

Basic translation

$t = $this->get('translator')->trans('Symfony2 is great');
$t = $this->get('translator')->trans('Hello %name%', array('%name%' => $name));

When this code is executed, Symfony2 will attempt to translate the message "Symfony2 is great" based on the locale of the user.

<!-- messages.fr.xliff -->
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="en" datatype="plaintext" original="file.ext">
        <body>
            <trans-unit id="1">
            <source>Symfony2 is great</source>
            <target>J"aime Symfony2</target>
            </trans-unit>
            <trans-unit id="2">
            <source>Hello %name%</source>
            <target>Bonjour %name%</target>
            </trans-unit>
        </body>
    </file>
</xliff>

Each time you create a new translation resource (or install a bundle that includes a translation resource), be sure to clear your cache so that Symfony can discover the new translation resource:

Using Real or Keyword Messages

$t = $translator->trans('Symfony2 is great');
$t = $translator->trans('symfony2.great');

In the first method, messages are written in the language of the default locale (English in this case). That message is then used as the "id" when creating translations. In the second method, messages are actually "keywords" that convey the idea of the message. The keyword message is then used as the "id" for any translations. In this case, translations must be made for the default locale (i.e. to translate symfony2.great to Symfony2 is great).

symfony2.is.great: Symfony2 is great
symfony2.is.amazing: Symfony2 is amazing
symfony2.has.bundles: Symfony2 has bundles
user.login: Login

Using Message Domains

When translating strings that are not in the default domain (messages), you must specify the domain as the third argument of trans():

* messages.fr.xliff
* admin.fr.xliff
* navigation.fr.xliff

$this->get('translator')->trans('Symfony2 is great', array(), 'admin');

Pluralization

To translate pluralized messages, use the transChoice() method:

$t = $this->get('translator')->transChoice(
    'There is one apple|There are %count% apples',
    10,
    array('%count%' => 10)
);

Translations in Templates

Translating in Twig templates example:

//you can set de translation domain for entire twig temples
{% trans_default_domain "app" %}

{% trans %}Hello %name%{% endtrans %}

{% transchoice count %}
    {0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples
{% endtranschoice %}

//variables traduction
{{ message|trans }}

{{ message|transchoice(5) }}

{{ message|trans({'%name%': 'Fabien'}, "app") }}

{{ message|transchoice(5, {'%name%': 'Fabien'}, 'app') }}

If you need to use the percent character (%) in a string, escape it by doubling it: {% trans %}Percent: %percent%%%{% endtrans %}
Translating Database Content

The translation of database content should be handled by Doctrine through the Translatable Extension

Translating constraint messages

# src/Acme/BlogBundle/Resources/config/validation.yml
Acme\BlogBundle\Entity\Author:
    properties:
        name:
            - NotBlank: { message: "author.name.not_blank" }

Create a translation file under the validators catalog:


<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file source-language="en" datatype="plaintext" original="file.ext">
        <body>
            <trans-unit id="1">
            <source>author.name.not_blank</source>
            <target>Please enter an author name.</target>
            </trans-unit>
        </body>
    </file>
</xliff>
Read more about Symfony