Symfony2 layout composition or inheritance - symfony

I can't understand some principles about layout composition in sf2.
I have this App/Namespace/MyBundle/Resources/views/layout.html.twig template:
{% extends '::base.html.twig' %}
{% block title %}Main Title{% block subtitle %}{% endblock %}{% endblock %}
{% block head %}<h1>Placeholdertitle</h1>{% endblock %}
{% block body %}{% endblock %}
{% block sidebar %}{% endblock %}
How should I make the head.html.twig to replace the head block?
Currently I have this App/Bundle/Resources/views/head.html.twig template:
{% extends 'AppNamespaceMyBundle::layout.html.twig' %}
{% block head -%}
<h1>
Main Title
</h1>
{% endblock %}
Then I load a page with this index.html.twig:
{% extends 'AppNamespaceMyBundle::layout.html.twig' %}
{% block subtitle %} | Categories{% endblock %}
{% block body -%}
<h1>Categories list</h1>
<table class="records_list">
<thead>
<tr>
<th>Id</th>
<th>Text</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for entity in entities %}
<tr>
<td>{{ entity.id }}</td>
<td>{{ entity.text }}</td>
<td>
<ul>
<li>
show
</li>
<li>
edit
</li>
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<ul>
<li>
<a href="{{ path('category_new') }}">
Create a new entry
</a>
</li>
</ul>
{% endblock %}
And here I get the "Placeholdertitle" instead of the "Main Title", meaning that the head.html.twig isn't used. How am I supposed to use that head.html.twig to be in the layout.html.twig?

From what you are explaining, I guess that you want to render Layout + Head inside your Index.
You can use the following schema:
Layout <extended by> Head <extended by> Index. This way, when you will render Index, Twig will render both Head and Layout.
Another solution is to use the use.
PS: You cannot extends both head and layout in the same index file, as Twig says: Template inheritance is one of the most powerful Twig's feature but it is limited to single inheritance;

Did you try to remove the "-" in your head block in head.html.twig ?

Related

Get twig variable from a specific route

I have a template where the left column is used to display the top sell items.
here's a my master template code:
<html><body>
{% block menu %}
{% endblock menu %}
{% block columnleft %}
{% include 'TestBundle:Default:top_items.html.twig'%}
{% endblock columnleft %}
{% block body %}
{% endblock body %}
</body></html>
my top_items.html.twig code:
<table>
{% for entity in entities %}
<tr>
<td style="padding: 0px"><img src="{{entity.picture}}"
width="60px" height="60px" class="img-rounded"></td>
<td style="padding: 0px; vertical-align: middle">{{entity.name}}</td>
</tr>
{% endfor %}
Question:
Is there any chance to get 'entities' variable from a specific route(localhost/statistics/top_meals) that return an array as response?
I'm asking for this because I have many views, and passing the 'entities' variable using {%include 'TestBundle:Default:top_items.html.twig' with {'entities': array_var}%} need to be called in each view.
Thanks
You are way better of with render controller call:
<html><body>
{% block menu %}
{% endblock menu %}
{% block columnleft %}
{% render(controller('TestBundle:Default:topItems')) %}
{% endblock columnleft %}
{% block body %}
{% endblock body %}
</body></html>
and then create the controller:
/**
* #Template()
*/
public function topItems(){
// SOME LOGIC
return array(
'topItems' => $topItems
)
}

Twig batch filter with if condition for creating 3 columns gallery table

I would like to create a gallery with three columns and I have used twig batch filter. Is it possible to add an if condition so that all disabled images won't be listed? My example is not working:
<table>
{% for items in content.galleries|batch(3) if items.enabled %}
<tr>
{% for cell in items %}
<td><img src="{{ asset(cell.image) }}"></td>
{% endfor %}
</tr>
{% endfor %}
</table>

CSS not working in Django

{% extends "base.html" %}
{% load i18n %}
{% load staticfiles %}
{% block jsscript %}
<!-- Script code -->
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script>
$(function() {
$('#btnNext_picklocation').attr('disabled','disabled');
$("#location input[type='checkbox']").click(function(){
if($('#location input[type="checkbox"]').is(':checked'))
{
$('#btnNext_picklocation').removeAttr('disabled');
}
else
{
$('#btnNext_picklocation').attr('disabled','disabled');
}
});
$("#location .maps img").attr("src","{% static 'media/loading.gif' %}");
$("#location .maps img").error(function(){
$(this).unbind("error").attr("src","{% static 'media/loading.gif' %}");
});
{% for obj in filter_location %}
var url{{obj.city}}="http://maps.googleapis.com/maps/api/staticmap?center={{obj.suite}},{{obj.street}},{{obj.city}}&size=400x200&maptype=roadmap&markers=size:mid|color:green|{{obj.suite}},{{obj.city}}&sensor=true";
$("#map{{obj.city}}").attr("src",encodeURI(url{{obj.city}}));
{% endfor %}
$('#btnNext').click(function(){
window.location.assign("./pickpaymentplan/");
});
});
</script>
<link rel="stylesheet" href="{% static 'css/base.css' %}" />
{% endblock %}
{% block head %}
<h1 class="heading" >Place An Order</h1>
<h4 class="heading">Please choose a location</h4>
{% endblock %}
{% block content %}
<!-- Main Body Content -->
<form id="frmLocation" action="./" method="POST">{% csrf_token %}
<table border="0">
<tr>
<td>
<table border="1" id="location" >
<tr>
<th> </th>
<th>Locations</th>
<th>Map</th>
</tr>
{% if filter_location %}
{% for p in filter_location %}
<tr>
<td><input type="checkbox" id="{{p.location_id}}L" name="{{p.location_id}}L" ></td>
<td>{{p.suite}},{{p.street}},<br/>{{p.city}},{{p.state}},<br/>{{p.country}},{{p.zip}}</td>
<td class="maps" ><img id="map{{p.city}}" /></td>
</tr>
{% endfor %}
{% else %}
<tr></tr>
<tr><td colspan="5">No Locations!</td></tr>
{% endif %}
</table></td>
</tr>
<tr>
<td style="text-align:right"><input type="submit" id="btnNext_picklocation" name="btnNext_picklocation" class="btnNext" value="Next"/> </td>
</tr>
</table>
</form>
</div>
<div id="footer" name="footer">
</div>
{% endblock %}
I this code I have used a base.html file as a base template. Appropriate changes has been made to settings.py, like static_url, media_url. Still this page is not working as expected.
Can indentation be an issue?
Is there some extra steps to be followed for implementing css?
My first guess would be that you are overriding {% block jsscript %} in some descendant template. If that is not the case, then I would confirm that the output of {% static 'css/base.css' %} is actually giving you what you expect (can you visit that URL?)
Two other thoughts:
Spaces don't really matter in templates.
You should probably move your CSS into something like {% block stylesheets %} instead of {% block jsscript %}.
If you're overriding the template block, and want to maintain the block's original content, you can use {{block.super}} to output the original content, like this:
parent.html:
<html>
<head>
<title>{% block title %}MySite{% endblock %}</title>
<body>
{% block content %}{% endblock %}
</body>
</html>
child.html
{% extends 'parent.html' %}
{% block title %}Child Page - {{block.super}}{% endblock %}
{% block content %}Hello world!{% endblock%}
The titlefor a page rendered using child.html will be "Child Page - MySite"
The general steps to diagnose such issue in any framework are:
verify that the <link> tag is present in the generated page - use View Page Source in your browser or use HTML panel in Firebug*
verify that href attribute of the <link> tag looks ok-ish
Use Firebug's Net panel to see if your stylesheet is actually loaded
Enter the stylesheet's URL (as found in your generated page) directly in the browser's address bar to see if its actual contents is what you expect
If all of the above found no problems, use Firebug's CSS panel to see if there's another stylesheet which overrides your styles.
If you follow these steps, chances are high you'll be able to find the problem yourself, if not - you'll be able to ask a much more concrete question
* by "Firebug" I mean Firebug itself, Chrome Dev Tools or Opera Dragonfly, whatever suits your tastes.

Is a Twig block empty? - Symfony 2

I have a twig template with the following block:
{% block dashboard %}
{% include "::user_dashboard.html.twig" %}
{% endblock dashboard %}
Later in that template, I want to set a class on a div based on whether or not there is anything in that block (i.e., by default, it will have the include above, but children of this template may override it and empty it out).
What I had (that somewhat worked) was ...
{% set _dashboard = block('dashboard') %}
{% set _mainWidth = ( _dashboard|trim is empty ? "no-dashboard" : "with-dashboard" ) #}
<div id="main" class="{{ _mainWidth }}">
The problem here is that whole dashboard block gets called twice. This wouldn't bother me too much except that block renders a few controller actions, i.e. ...
{% render "UserWidget:userAppMenu" %}
... and the code in that action is being called twice. For various reasons, not the least of which is performance, this messes with some of the stuff in that dashboard block.
So, my question is ... is there any way to tell if that block is empty without loading it twice? Is there something really simple I'm missing or is this even possible?
Thanks!
EDIT:
Here is my full template if it helps clarify things:
{% extends '::base.html.twig' %}
{% block layout %}
{% block header %}
{% include "::header.html.twig" %}
{% endblock header %}
<div id="container" class="row-fluid">
{% block dashboard %}
{% include "::user_dashboard.html.twig" %}
{% endblock dashboard %}
{% set _dashboard = block('dashboard') %}
{% set _mainWidth = ( _dashboard|trim is empty ? "no-dashboard" : "with-dashboard" ) %}
<div id="main" class="{{ _mainWidth }}">
<h1 class="page-title">{% block page_title %}{% endblock %}</h1>
{% block main_filters %}{% endblock %}
{% if app.session.flashbag.has('message') %}
<div class="alert alert-block alert-success">
<ul>
{% for flashMessage in app.session.flashbag.get('message') %}
<li>{{ flashMessage }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if app.session.flashbag.has('warning') %}
<div class="alert alert-block alert-success">
<ul>
{% for flashWarning in app.session.flashbag.get('warning') %}
<li>{{ flashWarning }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% block body %}{% endblock %}
{% block footer %}
{% include "::footer.html.twig" %}
{% endblock footer %}
</div>
</div>
{% endblock layout %}
Here you can see on lines 11 and 15 - both of those actually seem to include and process what is in that include.
What about this? This way the block should only be rendered once, when you call block('dashboard').
{# at top of twig #}
{% set _dashboard = block('dashboard') %}
{# where ever you include your block #}
<div>
{{ _dashboard|raw }}
</div>
{# and your main #}
{% set _mainWidth = ( _dashboard|trim is empty ? "no-dashboard" : "with-dashboard" ) #}
<div id="main" class="{{ _mainWidth }}">

symfony2 form error vs field error theme (twig)

In Twig, is there a way to define a different theme for field errors as oppose to form related errors like CSRF error or composite unique constraints?
I want to display the field errors with a <span> and the form errors with a <ul>
{{ form_errors(form) }}
<table>
<tbody>
<tr>
<td>{{ form_label(form.tabla) }}</td>
<td>
{{ form_widget(form.tabla) }}
{{ form_errors(form.tabla) }}
</td>
<td></td>
<td>{{ form_label(form.descripcion) }}</td>
<td>
{{ form_widget(form.descripcion) }}
{{ form_errors(form.descripcion) }}
</td>
<td></td>
</tr>
</tbody>
</table>
This is my form theme that is being used for both cases (not what I want).
{% block field_errors %}
{% if errors|length > 0 %}
<span class="val-error">
{% for error in errors %}
{{ error.messageTemplate|trans(error.messageParameters, 'validators')~'. ' }}
{% endfor %}
</span>
{% endif %}
{% endblock field_errors %}
Is there a way to differentiate both cases?
Form class extends Field. If you set a new theme to field it will be applied to form.
You should override the field_errors block as you did, and then define the form_errors block using another template (with th ul tag).
{% block field_errors %}
{% if errors|length > 0 %}
<span class="val-error">
{% for error in errors %}
{{ error.messageTemplate|trans(error.messageParameters, 'validators')~'. ' }}
{% endfor %}
</span>
{% endif %}
{% endblock field_errors %}
{% block form_errors %}
{% if errors|length > 0 %}
<ul class="val-error">
{% for error in errors %}
<li>{{ error.messageTemplate|trans(error.messageParameters, 'validators')~'. ' }}</li>
{% endfor %}
</ul>
{% endif %}
{% endblock form_errors %}
Since field_* is removed in 2.3 the approved solution will no longer work. A hacky solution I have found is
{% block form_errors %}
{% if errors|length > 0 %}
{% if form.parent is empty %}
<ul class="val-error">
{% for error in errors %}
<li>{{ error.messageTemplate|trans(error.messageParameters, 'validators')~'. ' }}</li>
{% endfor %}
</ul>
{% else %}
<span class="val-error">
{% for error in errors %}
{{ error.messageTemplate|trans(error.messageParameters, 'validators')~'. ' }}
{% endfor %}
</span>
{% endif %}
{% endif %}
{% endblock form_errors %}
So basically what this does is if there is no parent, it knows it is the top level.

Resources