Is there a way to set a template block content from within a controller in Symfony?
Is there a way to do something like this from within a controller?
$this->get('templating')->setBlockContent('page_title', $page_title);
I need to set the page title dynamically and I want to avoid modifying every single action template.
I know I can pass the $page_title variable to Controller:render but I don't want to add
{% block title %}
{{ page_title }}
{% endblock %}
to every single action template.
Since any parent Twig templates handle variables that are passed to their children templates, there's a simpler method to achieve what you want to do. In fact, this method is the basic equivalent of writing content into an entire block from the controller since we're essentially just inserting a passed render variable directly into the contents using {% block %}{{ variable }}{% endblock %}
Start a base layout template with the title block
{# Resources/views/base.html.twig #}
<html>
<head>
<title>{% block title %}{{ page_title is defined ? page_title }}{% endblock %}</title>
{# ... Rest of your HTML base template #}
</html>
The {% block %} part is not necessary but useful if you ever want to override or append to it (using parent())
You can also add a site-wide title so the page_title can be appended if it exists:
<title>{% block title %}{{ page_title is defined ? page_title ~ ' | ' }}Acme Industries Inc.{% endblock %}</title>
Extend this base layout with every child template
{# Resources/views/Child/template.html.twig #}
{% extends '::base.html.twig' %}
{# You can even re-use the page_title for things like heading tags #}
{% block content %}
<h1>{{ page_title }}</h1>
{% endblock %}
Pass the page_title into your render function which references your child template
return $this->render('AcmeBundle:Child:template.html.twig', array(
'page_title' => 'Title goes here!',
));
Related
I have two templates:
Fields.html.twig, which includes a child template.
{% block important %}
This block should be renderable from the sub template
{% endblock important %}
{% include 'XButton.html.twig' %}
XButton.html.twig, which needs to render blocks defined in the template that includes it.
block('important')
It seems like an included template isn't able to simply render blocks of whoever included it.
How can the parent template pass the full context to the child, so that the child can access the blocks defined in the parent?
What you're trying to do it's impossible, because the included template has no way to know about blocks defined in other templates...
You'll need to structure your code a bit differently, so that the contents of the block are defined in the parent somehow - you have at least a couple of options:
Using set and include: https://twigfiddle.com/l536np
Fields.html.twig
{% set important %}
You define the child content as a variable in the parent...
{% endset %}
{% include 'XButton.html.twig' %}
XButton.html.twig
{{ important }}
Using embed: https://twigfiddle.com/y9pp6p
Fields.html.twig
{% embed 'XButton.html.twig' %}
{% block important %}
You define the block content in the parent...
{% endblock %}
{% endembed %}
XButton.html.twig
{{ block('important') }}
You can do it with include by passing the parent template name
{% block important %}
This block should be renderable from the sub template
{% endblock important %}
{% include 'XButton.html.twig' with {'parent': _self} %}
And then use it in the include template
{{ block('important', parent) }}
Although this way the content of the block will be rendered twice - once when you define it in the parent, and once again in the child - see https://twigfiddle.com/6t0l6p
I'm working with Symfony and Twig and I can't find solution for the next problem:
in my parent template (index.html.twig) I have such code:
<noscript>
{% block noscript %}
<div class="alert alert-warning">
<strong>{% block notice %}{{ notice_js_disabled }}{% endblock %} </strong>
{% block message %}{{ js_disabled }}{% endblock %}
</div>
{% endblock %}
</noscript>
I have child template (category.html.twig) which extends index.html.twig template.
Can I pass value of {{ notice_js_disabled }} var from index template to category template?
notice_js_disabled is returned from my Symfony indexAction controller.
UPD:
The solution for my problem I founded, next:
I have made base templae, called main.html.twig, where I'm rendering element from the controller:
{% block header %}
{{ render(controller('StoreBundle:Header:index')) }}
{% endblock %}
Then, on my index.html.twig file, I made next things:
{% extends 'Store/tpl/main.html.twig' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<p class="currentPage" hidden>home</p>
{{ parent() }}
{% endblock %}
I'm not sure is it correct solution, but it's work:)
The only way in Twig you can pass some variable to a child template is by the include tag.
{# template.html will have access to the variables from the current context and the additional ones provided #}
{% include 'template.html' with {'foo': 'bar'} %}
{% set vars = {'foo': 'bar'} %}
{% include 'template.html' with vars %}
However in this way you are not extending some parent template from the child, but you are doing the other way around: you are placing a submodule into the current template.
There are only a couple of variables which are global in symfony
You can set some custom global variables in configuration like described here
Otherwise you can use some predefined global variables, the app variable. (check it out here)
My personal advice is that you should review your application template logic.
Hope it helps!
What you have to do is the following:
-Create A variable in the parent template
{% set notice_js_disabled = value_received_from_indexAction %}
After the template that you need that value
{{ notice_js_disabled }}
I hope it helps you
what is the difference between referencing a widget block and customizing it : the docs say :
So far, to override a particular form block, the best method is to
copy the default block from form_div_layout.html.twig, paste it into a
different template, and then customize it. In many cases, you can
avoid doing this by referencing the base block when customizing it
But to me it looks the same :
{# app/Resources/views/Form/fields.html.twig #}
{% extends 'form_div_layout.html.twig' %}
{% block integer_widget %}
<div class="integer_widget">
{{ parent() }}
</div>
{% endblock %}
{# app/Resources/views/form/fields.html.twig #}
{% block integer_widget %}
<div class="integer_widget">
{% set type = type|default('number') %}
{{ block('form_widget_simple') }}
</div>
{% endblock %}
What is the difference?
The first example in the documentation that you are referencing shows how to override the entire widget that displays your form element.
The second example in the documentation that you are referencing shows how you can employ code re-use so that you are not rewriting form templating sections that you are not modifying. So, instead of having to declare
{% set type = type|default('number') %}
{{ block('form_widget_simple') }}
all over again in your overriding widget, you can instead reference the base block that already has this. If you are referencing base blocks from an external template, you can call the parent block via {{ parent() }}, and if you are referencing blocks from inside the same template as the form, you can call the base block via {{ block('base_integer_widget') }}
If you look at it from a PHP/Symfony point of view with inheritance that can help explain it as well. Say you have one PHP class that extends another and you want to override a function named doSomething() - you might rewrite the entire function as you need it. But, say that doSomething() has a block of common code that you always want to run, then you might perform your actions and call parent::doSomething() at the end of it. Or, if you're accessing a different Symfony service you might call $this->get('some.service')->doSomething() instead.
That's the same concept here, you can either override the entire widget or you can override parts of it - perhaps putting a surrounding <div></div> but calling {{ parent() }} from within that since you're changing nothing else about the widget.
I do have one example where I overrode standard button behavior in Symfony and used both cases. I have a separate template file in `app/Resources/views/Form/navigationButton.html.twig' with the following code:
{% use 'form_div_layout.html.twig' %}
{% block button_widget -%}
{% set attr = attr|merge({class: (attr.class|default(''))|trim}) %}
{{- parent() -}}
{%- endblock %}
{% block button_row -%}
{{- form_widget(form) -}}
{%- endblock button_row %}
I am overriding the button widget by allowing additional classes to be passed as attributes and then calling the parent widget to produce it as normal. I then override the button row widget to not put surrounding <div></div> tags since I didn't want that in my template (see the originals here and here).
Then to use in one of my templates I simply do:
{% form_theme form ':Form:navigationButton.html.twig' %}
I have splitted my layout and templates to few partials, mostly because of old Symfony1 habits.
file layout.html.twig:
...
<body>
{{ include("ABCBundle:Partials:breadcrumbs.html.twig") }}
{% block body %}{% endblock %}
</body>
...
file breadcrumbs.html.twig
<div class="abc">
{% block breadcrumbs %}
Home
{% endblock %}
</div>
file show.html.twig
{% extends "ABCBundle::layout.html.twig" %}
{% block breadcrumbs %}
{{ parent() }}
abc
{% endblock %}
{% block body %}
(something something)
{% endblock %}
Funny thing is, when I render show.html.twig, I can put data into body block, and everything works fine, but I can't do anything with breadcrumbs block. Whatever I do - write something inside that block or call parent(), nothing happens, only content from breadcrumbs.html.twig is being rendered. There's also no error about calling parent() and any other error related to extending block.
I think you should use {% include "..." %} rather than {{ include("...") }}
According to the twig documentation, the {% include %} tag "includes a template and returns the rendered content of that file into the current namespace" where as the include function "returns the rendered content of a template"
(Meaning the include function just returns the rendered content, where the tag adds the content to the current namespace which would include the blocks you defined)
Found the solution.
It looks like you can't extend block included in layout's include, from template extending this layout:
[partial.html.twig] --- [ layout.html.twig ] --- [ template.html.twig ]
{% block abc %} {% include 'partial.html.twig' %} {% extends layout.html.twig %}
{% block abc%} aaa {%endblock %}
You have to perform a little hack, including adding extra content to layout and replacing original block from partial.html.twig with conditional. More here: Overriding blocks within included Twig templates
NB: i´m using Twig in a non-Symfony context.
I want to register a master layout that all templates should inherit, so that i don´t have to forget to preface them with:
{% extends 'layout.html.twig' %}
I know i have seen this somewhere, and Symfony makes use of it.
It is possible!
After some experimenting i came up with this solution:
{# index.html.twig #}
{% block title %}Hello world{% endblock%}
Wrap global layout in a block:
{# layout.html.twig #}
{% block layout %}
<html>
<head>
<title>{% block title %}{% endblock%}</title>
</head>
<html>
{% endblock %}
Pass child template to twig:
// index.php
...
$twig->display(array('template'=>'index.html.twig'));
...
Inject child template via a proxy template:
{# proxy.twig #}
{% extends 'layout.html.twig' %}
{% block layout %}
{# Get extended block #}
{{ parent() }}
{# inject template into master layout #}
{% include template %}
{% endblock %}