Symfony Selfstudy Sample
Symfony Selfstudy Sample
Raúl Fraile
This book is for sale at http://leanpub.com/symfony-selfstudy
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.
8. Twig . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Exam goals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Answers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Takeaways . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Answer sheet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
8. Twig
Exam goals
8.1. Auto escape
8.2. Template inheritance
8.3. Global functions
8.4. Filters
8.5. Template includes
8.6. Control statements (loops and conditions)
8.7. URLs generation
8.8. Call a controller from a view
8.9. Translations
Questions
1. Which of the following sentences are true about Twig?
1. Yes
2. No
3. Only in the dev environment
4. Only when twig.debug is set to true
1. {{ ... }}
2. {# ... #}
3. {* ... *}
8. Twig 2
4. {- ... -}
4. Are Twig templates recompiled when changes are made when debug mode is enabled?
1. Yes
2. No
3. Only in the dev environment
4. Only when apc.stat is set to 1 in the PHP settings
1. … is disabled by default
2. … is enabled by default
3. … can be disabled with the e filter
4. … is necessary to prevent XSS attacks
6. If the current time is 16:22:42 Europe/Madrid, does the following template print 16:22?
{# time.html.twig #}
{{ now | date(timezone="Europe/Madrid", format="H:i") }}
1. Yes
2. No
8. What is the command to check the syntax of one or more Twig files?
1. twig:validate
2. twig:syntax
3. twig:lint
4. There is not such a command
1. twig:export
2. twig:convert
3. twig:compile
4. There is not such a command
10. What is the output of the following code inside a controller that extends from the base
controller?
13. How can we get the current route name from Twig?
1. {{ app.request.attributes._route }}
2. {{ app.request.attributes._routeName }}
3. {{ app.routing.route }}
4. {{ app.routing.routeName }}
14. What application specific variables are available in the app global variable?
1. app.security
8. Twig 4
2. app.user
3. app.request
4. app.session
15. How can you get the name of the current environment from a Twig template?
1. {{ env.name }}
2. {{ app.env.name }}
3. {{ app.environment }}
4. {{ app.environment.name }}
16. How can you get the HTTP method of the current request from a Twig template?
1. {{ app.request.method }}
2. {{ app.request.getMethod() }}
3. {{ app.request.http }}
4. It is not possible to get the HTTP method from Twig without custom extensions
17. How can you get the current charset from a Twig template?
1. {{ app.request.charset }}
2. {{ app.request.attributes._charset }}
3. {{ _charset }}
4. It is not possible to get the current charset from Twig
// IndexController.php
$data = [
'first' => 0,
'first-page' => 1
];
return $this->render('index.html.twig', [
'page' => 5,
'data' => $data
]);
8. Twig 5
{# index.html.twig #}
{{ data.first-page }}
{# index.html.twig #}
{{ data }}
1. strtolower
2. lowercase
3. lower
4. lowerize
21. Is it possible to define additional global variables to be available in all Twig templates?
22. Which of the following solutions would be better to have a variable called env in all Twig
templates containing the current environment name? (Only 1 answer)
8. Twig 6
1. Adding {% set env = app.environment %} in the base template which every other template
inherits from
2. Adding env: "%kernel.environment%" to twig.globals
3. Overriding the render() method of the base controller
4. Looking for the definition of the twig service in TwigBundle and adding <call method="addGlobal">
<argument>env</argument> <argument>%kernel.environment%</argument> </call>
23. Given the following Twig template, what would be its output?
{# spaceless.html.twig #}
{% spaceless %}
<div id="hello">
<span >Hello world</span>
</div>
{% endspaceless %}
24. In Twig, for loops create a special variable to get some information such as the current
iteration or whether the current iteration is the first/last. What is its name?
1. loop
2. index
3. for
4. app
25. What error do you get if you render the following Twig template from a controller, if the
route name is book_list?
{# render_controller.html.twig #}
{% render(controller(app.request.attributes.get("_route"))) %}
26. Which of the following are good use cases for the cycle function in Twig?
{# object_first.html.twig #}
{{ {one: 1, two: 2} | first }}
1. one
2. 1
3. Error: Array to string conversion
4. Error: Object to string conversion
28. The goal of the following template is to choose a different layout for AJAX requests. Would
it work?
{# conditional_layout.html.twig #}
{% set ajax = app.request.xmlHttpRequest %}
{% set prefix = 'AppBundle::' %}
{% extends prefix ~ (ajax ? "layout_ajax.html.twig" : "layout.html.twig") %}
{# ... #}
29. In nested loops, how can you access to the loop.index variable of the parent loop?
1. {{ parent.index }}
2. {{ parent.loop.index }}
3. {{ loop.parent.loop.index }}
4. {{ loop.loop.parent.loop.index }}
30. Given the following Twig extension, what would be the output of {{ hello("bye") }}?
8. Twig 8
// AppBundle/Twig/Extension/MagicExtension.php
class MagicExtension extends \Twig_Extension
{
1. bye
2. hello:bye
3. bye:hello
4. Error: The function "hello" does not exist
31. What is the output of the following template if not_found.html.twig doesn’t exist and
error.html.twig contains An error occurred?
{# test.html.twig #}
{{ include('not_found.html.twig') | default('error.html.twig') }}
1. An error occurred
2. Error: The filter "default" does not exist
3. Error: Unable to find template "not_found.html.twig"
4. Error: Unexpected token "An" of value "error"
8. Twig 9
32. In which of the following scenarios would you use the Twig verbatim tag?
1. Framework::layout.html.twig
2. :views:layout.html
3. app::layout.html.twig
4. ::layout.html.twig
Answers
1. Which of the following sentences are true about Twig?
Answers 1, 2 and 4 are correct. Twig does not process PHP tags, it just prints out the PHP code as if
it were plain text. Before using Twig templates, they are compiled down to native PHP and cached
for future use, so the performance impact is really low compared to plain PHP code.
{# unclosed_comment.html.twig #}
{#
{{ 'hello' }}
4. Are Twig templates recompiled when changes are made when debug mode is enabled?
Answer 1 is correct. When the debug mode is enabled, Twig templates are recompiled if the
templating engine detects that the file has changed. This is the default mode in the dev environment,
but it can be used in any other environment, even with prod. The apc.stat setting has no effect
when compiling Twig templates, as APC (or OpCache) only caches PHP code (but when apc.stat
is 0, clearing the template cache won’t update the APC cache).
In Symfony, Twig templates are compiled down in the twig directory of the environment cache (i.e.
app/cache/dev). For example, the following simple template:
{# test.html.twig #}
{# print something #}
{{ 'hello world' }}
// app/cache/dev/twig/8a/89/24ac44...php
/* AppBundle::test.html.twig */
class __TwigTemplate_8a8924ac extends Twig_Template
{
public function __construct(Twig_Environment $env)
{
parent::__construct($env);
$this->parent = false;
$this->blocks = [];
}
// line 2
echo "";
// line 3
echo "hello world";
}
As you can see, it’s plain PHP code. The class extends from Twig_Template and the doDisplay()
method is responsible or rendering the template. The {{ 'hello' }} instruction has been converted
to a simple echo, while the comment has just been ignored. The getDebugInfo() method is used for
debugging purposes, and maps lines of the PHP compiled template and the Twig template. Here, the
3rd line of the template corresponds with the 22nd line of the PHP file.
<a href="http://example.com"></a>gt;
²http://en.wikipedia.org/wiki/Cross-site_scripting
8. Twig 12
6. If the current time is 16:22:42 Europe/Madrid, does the following template print 16:22?
Answer 2 is correct, as there is an error in the template. The variable now doesn’t exist, it should be
the string "now", which is interpreted by the date‘ filter as the current date and time:
{# date.html.twig #}
{{ "now" | date(timezone="Europe/Madrid", format="H:i") }}
In case you are wondering, named arguments are supported since Twig 1.12. The previous code is
equivalent to these two:
{# date.html.twig #}
{{ "now" | date("H:i", "Europe/Madrid") }}
Internally, the date filter makes use of the date() PHP function, so you can use any
value that is accepted by the function, such as +1 hour. {{ "+1 hour"|date("H:i",
"Europe/Madrid") would print 17:22.
Twig bridge
In addition to url() and path(), the Twig bridge integrates Twig with other components
like Form, HttpKernel, Security and Yaml. All functions and filters that are useful in a
Symfony project but not for a templating engine in isolation, are probaby defined here:
form-related functions, the trans and transchoice filters or other important functions
like render(), controller() or is_granted().
8. What is the command to check the syntax of one or more Twig files?
8. Twig 13
Answer 3 is correct. The TwigBundle bundle defines the command twig:lint to check the syntax
of Twig files. For the validation process, it first tokenizes the contents of the Twig file and then tries
to parse it. If an error is thrown, the file contains a syntax error. Remember that linters don’t check
other errors, like undefined variables or wrong array positions, so the following template will be
valid for the linter but will throw an error when is executed:
{# no_array_key.html.twig #}
{% set data = [1, 2, 3] %}
{{ data[4] }}
Unlike the PHP linter, the twig:lint command takes into account all tags, functions and filters
defined by bundles.
10. What is the output of the following code inside a controller that extends from the base
controller?
Answer 3 is correct. The render() method defined in the base controller throws an exception as it
expects a file path, not actual Twig code.
set in loops
In Twig, loops are scoped, so any variable declared inside a loop won’t be available outside.
used to capture the output generated by its body ‘capture’ chunks of text, that’s why answers 2 and
3 work. Answer 4 works as well because in Twig you can set the same variable more than once.
13. How can we get the current route name from Twig?
Answer 1 is correct. The app global variable provides the Request object in app.request. This object
contains a parameter bag called attributes, with information about the controller (_controller),
the route (_route) and the route parameters (_route_params).
14. What application specific variables are available in the app global variable?
All answers are correct. The app global variable provides 6 application specific variables: security,
user, request, session, environment and debug.
15. How can you get the name of the current environment from a Twig template?
Answer 3 is correct. The app.environment variable contains a string with the current environment:
dev, prod, etc. While there are better ways (data collectors or HTTP headers), it can be used to output
additional information for debugging purposes:
{# layout.html.twig #}
{# ... #}
{% if app.environment == 'dev' %}
IP: {{ app.request.clientIp }}
{% endif %}
{# ... #}
16. How can you get the HTTP method of the current request from a Twig template?
Answers 1 and 2 are both correct. As app.request contains the Request object, you can get the cur-
rent HTTP method using the getMethod() method. In addition, when using app.request.method,
Twig does the following checks:
17. How can you get the current charset from a Twig template?
Answer 3 is correct. In addition to the app global variable (defined by Symfony), self, context and
charset (defined by Twig itself) are always available in Twig templates.
21. Is it possible to define additional global variables to be available in all Twig templates?
Answers 1 and 3 are correct. The easiest way to add global variables for all Twig templates is using
the twig.globals setting, and accepts primitive values, service container parameters and services.
For more advanced use cases, Twig extensions can define global variables too. It is not possible to
use a listener to add global variables as there is no event generated just before the template is parsed
(kernel.view is only generated when the return value of a controller is not a Response object).
Overriding the render() method of the base controller would also be an option.
22. Which of the following solutions would be better to have a variable called env in all Twig
templates containing the current environment name? (Only 1 answer)
All answers could work, but the easiest and cleanest way is by adding the variable to the
twig.globals setting. Answer 1 would not work for templates that don’t inherit from the base
template. Similarly, answer 3 would force all controllers to inherit from the base controller. Answer
4 is not recommended at all as you would be editing Symfony itself.
23. Given the following Twig template, what would be its output?
Answer 4 is correct. The spaceless tag removes whitespaces between HTML tags, not within tags
or text.
24. In Twig, for loops create a special variable to get some information such as the current
8. Twig 17
iteration or whether the current iteration is the first/last. What is its name?
Answer 1 is correct. The loop array is created for the for loop scope and contains several keys:
For example, the following template would generate the resulting trace:
{# loop_variable.html.twig #}
{% for letter in ['a', 'b', 'c'] %}
{# ... #}
{% endfor %}
25. What error do you get if you render the following Twig template from a controller, if the
route name is book_list?
Answer 2 is correct. The controller() function expects a controller name, not the current route
name. As the route name (book_list) is not in the format Bundle:Controller:Action, it cannot be
parsed.
Answer 1 would be true if you change _route by _controller, as it contains the value of the current
controller in the right format. The following code generates an infinite loop, so when the maximum
level is reached it throws an error:
{# infinite_loop.html.twig #}
{% render(controller(app.request.attributes.get("_controller"))) %}
8. Twig 18
26. Which of the following are good use cases for the cycle function in Twig?
Answer 1 is correct. Zebra stripes on HTML tables is a common use case for the cycle function, as
it can be used to easily apply different styles to even and odd rows:
{# cycle.html.twig #}
{% set rows = [[1, 'one'], [2, 'two']] %}
<table>
{% for row in rows %}
<tr class="{{ cycle(['odd', 'even'], loop.index0) }}">
<td>{{ row[0] }}</td>
<td>{{ row[1] }}</td>
</tr>
{% endfor %}
</table>
<table>
<tr class="odd">
<td>1</td>
<td>one</td>
</tr>
<tr class="even">
<td>2</td>
<td>two</td>
</tr>
</table>
{# first_filter.html.twig #}
{{ ['hello', 'bye'] | first }} {# result: 'hello' #}
{{ {one: 'hello', two: 'bye'} | first }} {# result: 'hello' #}
{{ 'hello'| last }} {# result: 'h' #}
The last filter works the same way, but returns the last element of the input data:
{# last_filter.html.twig #}
{{ ['hello', 'bye'] | last }} {# result: 'bye' #}
{{ {one: 'hello', two: 'bye'} | last }} {# result: 'bye' #}
{{ 'hello'| last }} {# result: 'o' #}
28. The goal of the following template is to choose a different layout for AJAX requests. Would
it work?
Answer 4 is correct, the approach is correct. It is possible to make a layout conditional, as well as
making it depend on a variable. In fact, the template name can be any valid expression.
29. In nested loops, how can you access to the loop.index variable of the parent loop?
Answer 3 is correct. In Twig, each loop has its own scope, but the loop variable contains a reference
to the parent scope. For example, the following template prints out 1 1 1 2 2 2 3 3 3:
{# parent_loop.html.twig #}
{% for i in 'a'..'c' %}
{% for j in 'a'..'c' %}
{{ loop.parent.loop.index }}
{% endfor %}
{% endfor %}
30. Given the following Twig extension, what would be the output of {{ hello("bye") }}?
Answer 2 is correct. It’s basically a catch-all function. Twig supports dynamic functions since version
1.5, so if you define a function that includes *, it can be replaced by any string.
Symfony itself makes use of dynamic functions for the render_* function, which is executed when
using render_esi or render_hinclude. This function is defined in the Twig bridge.
8. Twig 20
Similarly, you can define dynamic filters as well. The following example defines the dynamic filter
add_*, which adds two numbers:
// AppBundle/Twig/Extension/MagicExtension.php
class MagicExtension extends \Twig_Extension
{
31. What is the output of the following template if not_found.html.twig doesn’t exist and
error.html.twig contains An error occurred?
Answer 3 is correct. The default filter returns the passed value if the input is undefined or empty,
but it doesn’t catch errors.
32. In which of the following scenarios would you use the Twig verbatim tag?
Answer 1 is correct. When Twig finds a verbatim section, its content is not parsed, but treated as
8. Twig 21
raw text. For example, the following template outputs {{ [1, 2, 3] | join(', ') }}:
{# verbatim.html.twig #}
{% verbatim %}
{{ [1, 2, 3] | join(', ') }}
{% endverbatim %}
• Bundle name.
• Directory inside Resources/views.
• Template file name.
In the current example, as the template is not inside any bundle but belongs to the application, the
first fragment is empty. Also, as it is not located in any subdirectory of Resources/views, the second
fragment is empty as well. The following table contains some examples of templates and their logical
names:
Location Logical name
app/Resources/views/layout.html.twig ::layout.html.twig
app/Resources/views/Static/tos.html.twig :Static:tos.html.twig
src/AppBundle/Resources/views/mail.txt.twig AppBundle::mail.txt.twig
Takeaways
• General
– The Twig bridge defines functions and filters that make use of Symfony components,
such as url(), path(), is_granted() or render(). They are not included in the core of
Twig.
– Loops have their own scope and define a special variable called loop, which can be used
to get the index and access to the parent scope.
8. Twig 22