Twig Assetic Stylesheets Among Several Templates - symfony

I'm trying to add stylesheets to an array so that as twig templates extend through a second and third levels the aggregated styles will carry through.
This topic is related to Combining Assetic Resources across inherited templates
From config.yml, I made a global array mystyles so that we can add to the list of necessary styles as we "bubble up" through the rendering process.
twig:
debug: %kernel.debug%
strict_variables: %kernel.debug%
globals:
mystyles: []
The first template called from my action is from CommunicatorBundle/Resources/views/Admin/Workspace.html.twig and I've set the specific style for this page called admin.workspace.css.
{% extends "DJCommunicatorBundle::base.html.twig" %}
{% set mystyles = ["#DJCommunicatorBundle/Resources/public/css/admin.workspace.css"]|merge(mystyles) %}
It extends CommunicatorBundle/Resources/views/base.html.twig which has it's own requirement data-table.css.
{% extends "DJSharedBundle::base.html.twig" %}
{% set mystyles = ["#DJCommunicatorBundle/Resources/public/css/data-table.css" ]|merge(mystyles) %}
Finally, we load the outermost template, SharedBundle/Resources/views/base.html.twig, which has it's own styles to add before all others.
<head>
{% set mystyles = ['#DJSharedBundle/Resources/public/css/global.css', '#DJSharedBundle/Resources/public/css/grid.990.9-col.css']|merge(mystyles) %}
{% stylesheets {{ mystyles }} %}
<link rel="stylesheet" href="{{ asset_url }}" type="text/css" />
{% endstylesheets %}
</head>
However, it breaks at this line
{% stylesheets {{ mystyles }} %}
inspite of this type of test that prints the array that I expect in the proper order
{{ mystyles|join(', ') }}
It seems that the {% stylesheets %} tag wants something like the following snippit to work (which is understandably not an array object, but a whitespace separated list of delimited strings).
{% stylesheets
'#DJSharedBundle/Resources/public/css/global.css'
'#DJSharedBundle/Resources/public/css/grid.990.9-col.css'
'#DJCommunicatorBundle/Resources/public/css/data-table.css'
'#DJCommunicatorBundle/Resources/public/css/admin.workspace.css'
%}
<link rel="stylesheet" href="{{ asset_url }}" type="text/css" />
{% endstylesheets %}
Even then, I tried setting a string to such a long value and printing it, but this doesn't work either:
{%
set str = "#DJSharedBundle/Resources/public/css/global.css
#DJSharedBundle/Resources/public/css/grid.990.9-col.css
#DJCommunicatorBundle/Resources/public/css/data-table.css
#DJCommunicatorBundle/Resources/public/css/admin.workspace.css"
%}
{% stylesheets {{ str }} %}
I feel like the global should be a viable solution, though not currently working. Hopefully I'm close. What might fix this?

This is not possible right now because Assetic statically analyzes your templates to find any assets you've defined there. Supporting these dynamic cases is on the roadmap.

Related

Use a template to set a variable

I'm using craftcms and the template language they use is Twig.
The _layout/base.html:
<!DOCTYPE html>
<html>
<head>
{% include '_layout/_seo_default.html %}
</head>
_layout/_seo_default.html:
{% if seo is not defined %}
{% set seo = {title: "Default values for things", description:"Default Description"} %}
{% endif %}
<title>{{ seo.title }}</title>
<meta name="description" content="{{ seo.description }}">
I have a blog/_entry template which shows an entry from the CMS based on the url. The blog/_entry.html:
{% extends '_layout/base.html' %}
{% block main %}
{# i want this include to set a variable used in _seo_default.html #}
{% include '_seo/_from_article_type_entry.html' with {entry: entry} %}
<article>
html irrelevant to question
</article>
{% endblock %}
The _seo/_from_article_type_entry.html
{% set seo = { title: entry.title, description: entry.short_description } %}
The idea was that i would be able to map the fields to the correct keys in one template / at one place. So i don't have to reuse it for the news/blog/story templates the client wants. But the 'seo' variable set in _seo/_from_article_type_entry.html does not get set (either not at all, or not in time that the _layout/_seo_default.html picks it up, and default values are always used.
If i replace the {% include '_seo/_from_article_type_entry.html' with {entry: entry} %} line in blog/_entry.html with the contents of _seo/_from_article_type_entry.html it does work, so it just doesn't seem to get set in the include. But I can't figure out what i'm missing. Or maybe i'm trying to do something that Twig is not supposed to do.
In either case, any help would be very welcome :)
Included templates have their own variable scope, templates outside the included one can't access these variables as seen here

Symfony - Find asset name with assetic

I would like to know the names of my assets in a controller. I use assetic, so the assets names are random.
For example for my css, in my Twig I have:
{% block stylesheets %}
{% stylesheets filter='uglifycss' filter='cssrewrite'
'assets/css/bootstrap.min.css'
'assets/css/core.css'
%}
<link rel="stylesheet" href="{{ asset(asset_url) }}" />
{% endstylesheets %}
{% endblock %}
The result:
<link rel="stylesheet" href="http://local.example.com/css/c491e8f-285c78f.css" />
Now, I would like to find the name c491e8f-285c78f.css automatically in my controller.
I tried:
var_dump($this->get('assetic.asset_manager')->getNames(),
$this->get('assetic.asset_manager')->get('c491e8f')->getTargetPath());
The result:
array(3) {
[0] => string(7) "c491e8f"
[1] => string(7) "b011b98"
[2] => string(7) "f4e7a09"
}
string(35) "_controller/css/c491e8f-285c78f.css"
It's not bad, but I have cheated to find the "c491e8f" name... How I can know it's my css asset name ? And how I can find automatically the asset path ?
As you read the source code of bundle kriswallsmith/assetic you realize that it's not trivial to get the names of you assets
(assets have really unique names) and they are in the getNames() array in order of appeararance in the templates.
One of the solutions is to Using Named Assets
http://symfony.com/doc/current/assetic/asset_management.html#using-named-assets
in config.yml:
assets:
bootstrap_and_core:
inputs:
- 'assets/css/bootstrap.min.css'
- 'assets/css/core.css'
you will probably also need to run the command_php app/console assetic:dump
and then:
var_dump($this->get('assetic.asset_manager')->get('bootstrap_and_core')->getTargetPath());
string 'assetic/bootstrap_and_core.css' (length=30)
Names:
var_dump($this->get('assetic.asset_manager')->getNames());
array (size=1)
0 => string 'bootstrap_and_core' (length=18)
Twig:
{% block stylesheets %}
{% stylesheets filter='uglifycss' filter='cssrewrite'
'#bootstrap_and_core'
%}
<link rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}
{% endblock %}
Also note:
you don't have to use {{ asset(asset_url) }} - it would be enough to {{ asset_url }}

load css in child of a twig

I have a super class twig which has the following block:
{% stylesheets filter='css_url_rewrite,?yui_css'
'#MainBundle/Resources/public/css/bootstrap.css'
'#MainBundle/Resources/public/css/vendor/*.css'
'#MainBundle/Resources/public/css/_normalize.css'
'#MainBundle/Resources/public/css/main.css'
'#MainBundle/Resources/public/css/fonts.css'
'#MainBundle/Resources/public/css/include/*.css'
'#MainBundle/Resources/public/css/footer.css'
%}
I have another twig that extends from the twig above, but I wanted to add an additional css on this page, so I did:
{% block stylesheets %}
{{ parent() }}
{% stylesheets filter='css_url_rewrite,?yui_css'
'#ShopiousMainBundle/Resources/public/css/shippingconfirm/*.css'
%}
{% endstylesheets %}
{% endblock %}
however this doesn't import the css that I have inside shippingconfirm,
Any idea on how to fix this?
You need to set the link element again in your stylesheets block. So it should work with the following:
{% block stylesheets %}
{{ parent() }}
{% stylesheets filter='css_url_rewrite,?yui_css'
'#ShopiousMainBundle/Resources/public/css/shippingconfirm/*.css' %}
<link rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}
{% endblock %}
But your additional stylesheets in the shippingconfirm folder will be in an extra file. Assetic won't put all stylesheets (css from parent and css from the current template) into one file.
A similar question was posted here: Combining Assetic Resources across inherited templates
There you can find some approaches to fix your problem.

Can't override extended twig template block to empty

I'm using MopaBootstrapBundle in Symfony 2.1.3 with Twig templates.
This bundle has base.html.twig template which contains scripts block:
{% block foot_script %}
{# To only use a subset or add more js overwrite and copy paste this block
To speed up page loads save a copy of jQuery in your project and override this block to include the correct path
Otherwise the regeneration is done on every load in dev more with use_controller: true
#}
{% javascripts
'http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-transition.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-modal.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-dropdown.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-scrollspy.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-tab.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-tooltip.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-popover.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-alert.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-button.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-collapse.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-carousel.js'
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-typeahead.js'
'#MopaBootstrapBundle/Resources/public/js/mopabootstrap-collection.js'
'#MopaBootstrapBundle/Resources/public/js/mopabootstrap-subnav.js'
%}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
{% endblock foot_script %}
I'm extending it in my template using:
{% extends 'MopaBootstrapBundle::base.html.twig' %}
{% block foot_script %}{% endblock foot_script %}
But it still tries to load Bundle's base.html.twig template and I get:
An exception has been thrown during the compilation of a template
("Unable to find file
"#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-transition.js".")
in "MopaBootstrapBundle::base.html.twig".
What I've found out is, that if you extend it like this:
{% extends 'MopaBootstrapBundle::base.html.twig' %}
{% block foot_script %}
{% javascripts
'#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-typeahead.js'
'#MopaBootstrapBundle/Resources/public/js/mopabootstrap-collection.js'
'#MopaBootstrapBundle/Resources/public/js/mopabootstrap-subnav.js'
%}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
{% endblock foot_script %}
Note the typeahead.js
I get:
An exception has been thrown during the compilation of a template
("Unable to find file
"#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-typeahead.js".")
in "MopaBootstrapBundle::base.html.twig".
If I remove just one line:
{% extends 'MopaBootstrapBundle::base.html.twig' %}
{% block foot_script %}
{% javascripts
'#MopaBootstrapBundle/Resources/public/js/mopabootstrap-collection.js'
'#MopaBootstrapBundle/Resources/public/js/mopabootstrap-subnav.js'
%}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
{% endblock foot_script %}
I get:
An exception has been thrown during the compilation of a template
("Unable to find file
"#MopaBootstrapBundle/Resources/bootstrap/js/bootstrap-transition.js".")
in "MopaBootstrapBundle::base.html.twig".
It still tries to load all the scripst from base template.
Any suggestions how to override *foot_script* block to make it empty and not to load these JS files?
What you want is to embed the MopaBootstrapBundle::base.html.twig instead of extending it. You should use Twig's embed tag:
{% embed 'MopaBootstrapBundle::base.html.twig' %}
{% block foot_script %}{% endblock foot_script %}
{% endembed %}
From Twig's documentation:
The embed tag combines the behaviour of include and extends. It allows you to include another template's contents, just like include does. But it also allows you to override any block defined inside the included template, like when extending a template.

Symfony2 Assetic + Twig Template JavaScript Inheritance

My problem:
I have 3 templates:
main.html.twig (main layout file)
layout.html.twig (a bundle specific layout override which contains some bundle specific JS tags)
create.html.twig (a page specific template file which also contains some page specific JS tags)
I am defining a block called 'javascript' in my base layout (main.html.twig), then overriding it (but calling {{ parent() }} in layout.html.twig. This works fine, and the JS tags from the main template file are still included above those in the layout.html.twig template.
I then do the same in the create.html.twig file, overriding the block as follows:
{% block javascripts %}
{{ parent() }}
{% javascripts '#BundleName/Resources/public/js/application.album.uploader.js'
'#BundleName/Resources/public/js/jquery.uploadify.js'
'#BundleName/Resources/public/js/swfuploadify.js' filter='?yui_js' %}
<script src='{{ asset_url }}' type='text/javascript'></script>
{% endjavascripts %}
{% endblock %}
At this point, instead of just overriding the javascript block in the parent (layout.html.twig) and including all the scripts defined in the templates above it, it does the following:
Dumps the <script> tags in the middle of the output (which causes an error, because in my main.html.twig file I am only including the jQuery library at the end of the HTML markup
Then it also dumps the scripts out along with the rest of the others (as I would expect it to)
I am not sure what is causing the scripts to be dumped in the middle of the create.html.twig template, and I'm also confused as to why they're being dumped to the screen twice (once in the middle of the create and then once at the bottom along with all the rest of my scripts from main.html.twig and layout.html.twig.
Has anyone got any ideas? Let me know if anything is unclear or if I can provide some more information.
EDIT:
File contents are below...
main.html.twig: https://gist.github.com/7f29353eaca0947528ce
layout.html.twig: https://gist.github.com/734947e9118b7765715e
create.html.twig: https://gist.github.com/c60c8d5c61e00ff86912
EDIT 2:
I've been having another look at the issue this morning and it looks as though its doing the same thing for stylesheets. I tried to define a new block called pagescripts in my layout.html.twig and then use the block in my create.html.twig but this had the same outcome, it just seems to dump the scripts and stylesheets wherever I use the
{% block pagescripts %}
(scripts here)
{% endblock}
I found the issue. In create.html.twig I was defining my {% block javascripts %} content inside inside my {% block content %}, so I assume Twig was rendering the output of the javascripts block inside the content block.
Moving the {% block javascripts %} content outside of the {% block content %} block fixed the issue.
Here is an example of main.html.twig:
<body>
{% block stylesheets %}
{% endblock %}
{% block jsscript %}
{% endblock %}
{% block content %}
{% endblock %}
</body>
into your create.html.twig
{% extends '::base.html.twig' %}
{% block jsscript %}
my javascript files...
{% endblock %}
{% block content %}
<h1>Create</h1>
<form action="{{ path('entity_create') }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<p>
<button type="submit">Create</button>
</p>
</form>
{% endblock %}
If you still have issue, you can add a document ready function :
$(document).ready(function() {
// put all your jQuery goodness in here.
});

Resources