I have a page where I render details of many users. Each user's html is quite heavy (tooltips etc.) so I don't want to copy/paste the same code. I'd like to reuse the same code on different pages as well.
I was using include with parameters but I'm not sure how good the performance will be. Is it better to make a Twig extension and just have there functions producing html based on passed User instance? Or is there another, better approach?
EDIT:
This is the kind of code I'm rendering in multiple places on multiple pages.
<span data-tooltip aria-haspopup="true" class="has-tip" title="{{ user.getJob }}, {{ user.getCompanyy.getName }}">
{{ user.getFirstName }}, {{ user.getLastName }}
</span>
Include is a very good solution and fit exactly your needs.
You could use macros too (documentation). But try to do not use include nor require in a macro because if you have an error in the included template, the line of the error will be the line where you called the template (not the one where you really have a bug) so it could become very difficult to debug.
And like you said, Twig extension could be good too for specifics cases. For instance, if you want to display a price, it's better to make your |price extension instead of include a little template. But extensions are better for highly reusable codes and shorts templates.
By the way, the worst case is using render(controller(...)) only in order to display a template because it's very consuming in terms of memory.
Answer to Edit:
Here you will find a benchmark: So extension seems to be the best solution in case of very lot of parameters. In your simple case, both solutions are good. Personnally, I prefer to use includes when I have lot of HTML and few parameters. But it's very a question of what you prefer.
You could even imagine doing both.
include of the html widget
and an extension in order to concatenate user firstname and lastname
Like this:
<span data-tooltip aria-haspopup="true" class="has-tip" title="{{ user.getJob }}, {{ user.getCompanyy.getName }}">
{{ user|fullName }}
</span>
In conclusion, Twig provides lot of differents tools and it's up to you to choose the once that fits your needs.
Related
I have to deal with django, so here goes my question. I have a template where I want to calculate values and then use them in css. It looks like:
padding-top: {{ VAL1|divide:VAL2|multiply:VAL3 }}px
It calculates the value I need albeit in some strange fashion via filters, I am ok with that since I am already dealing with django :( The problem is that the result of calculation has comma inside like 12,34 whereas 12.34 is needed for css to work properly - padding-top: 12,34px isn't valid css due to the comma (I use google chrome). I tried to use floatformat filter - no success. It looks like a simple thing but I cannot wrap my head around it...
After delving into django docs I learnt that the described effect may occur due to the localization, so I added the following in the template:
{% load l10n %} # at the beginning
...
{{ VAL1|divide:VAL2|multiply:VAL3|unlocalize }} # to output without localization
Seems it helped, although I don't mind if someone savvy brings another solution.
I'm having issues with a small and trivial application that I created to help me learn Symfony 3. The Application simple allows me to upload an image when I create a new blog post.
I'm using the Symfony 3 documentation to learn about uploading file, and in it, it suggests that I rename the file to a unique name using the md5() hash method to request a strange looking name for the file.
Everything works find until I want to display the image in the index.html.twig file. I was under the impression that I could simply use the asset() method that I was using to import bootstrap and other publicly viewable files, and then simply append the file name to the end of that. But nothing seems to work.
Here are some things that I have tried.
<img src="{{ asset('blog/images/') }}{{ blog.imageUrl }}">
<img src="{{ asset('blog/images/', { 'imageUrl': blog.imageUrl }) }}">
<img src="{{ asset('blog/images/' . blog.imageUrl) }} ">
And there is probably a few more different combinations that I have tried but can remember. Now I have since found the documentation that talks a little about the asset() method, but there is nothing there that seems to state that you can use it and then just append the file name to the end of it, And I haven't found any information that allows me to point directly to the web directories, where the blog/images folder now lives. So any help with this would be awesome. Thank you so much.
Not knowing the content of blog.imageUrl its hard to know what is expected. My guess for the 'correct' answer to your question is that you were very close with option #3, however in twig string concatenation is done using the ~ symbol and not .
So in your case you would use <img src="{{ asset('blog/images/' ~ blog.imageUrl) }}" />
Regards
Make sure that the new name of the file matches the name stored in the database. That and make sure the path you're using is correct.
Lets say I have two controllers that work with the same entity, and use the same set of templates. Every template is supposed to generate buttons/forms/links with URLs to actions of controller that generated this template. So basically, the only thing that is different in the templates are the URLs generated.
You can imagine the problem like a admin CRUD controller with a newAction and editAction, which use the same template, but form actions must differ. My case is more complicated than that, though.
I considered following:
Setting the routes from the controller, but it feels like a lot of code that is out of place.
Different set of templates. Seems like anti-DRY and a lot of reused code.
Using template inheritance, where base template is the one with all the HTML, and child templates only contain the links, but it feels really hacky.
Is there a clever approach to solve this problem?
EDIT: My problem is not generating CRUD. This is more of a "best-practice" question.
I encountered this problem while implementing something like a eshop cart with tons of javascript logic bound to it. It appears twice: in the website, and in a iframe, used by some other devices (iPads and stuff). Both carts have to look the same, but because of different logic, the links must lead to different URLs.
What I ended up doing for now is having 2 templates
The one with all the markup, cart.html.twig:
{% set edit_cart_item = path('edit_cart_item') %}
{% set remove_cart_item = path('remove_cart_item') %}
...html...
Edit item
...more html...
The one for usage in iframe, public_cart.html.twig:
{% extends 'MyCartBundle::cart.html.twig' %}
{% set edit_cart_item = path('public_edit_cart_item') %}
{% set remove_cart_item = path('public_remove_cart_item') %}
Does the problem have some better solution in all the fancy OOP principles?
There isn't a 'clever' approach really. Why not just use the specified Doctrine command to generate it for you, and then go from there? http://symfony.com/doc/current/bundles/SensioGeneratorBundle/commands/generate_doctrine_crud.html
php app/console generate:doctrine:crud with various options
That will get you a solid base done in an 'appropriate' manner, and then you can perform your customizations.
EDIT:
After reading your updated post, I would have a look at this: http://symfony.com/doc/current/book/forms.html#changing-the-action-and-method-of-a-form
So, if you'd like, you can handle the logic of which form to display by passing in options to the form, and then setting the target via setAction():
$form = $this->createFormBuilder($task)
->setAction($this->generateUrl('target_route'))
;
By design, Symfony gives you a lot of flexibility in how to do things. A good reference of their best practices for forms can be found here: http://symfony.com/doc/current/best_practices/forms.html
I also think what you're doing is just fine. When I have complex cases for forms I like to create a Twig template just for the form itself, and then include that in my other templates. In that template you can pass the target route to it if you'd like, and then you'd just have one form template.
Since a few weeks I started playing with Symfony2.
It seems a very powerful framework, but there are some things I cannot still understand.
In documentation I see that i18n (i.e. Translations) is managed by the Translator service. If I correctly understood, the main way to have a website translated is to put the collection of messages I want to translate inside the different files messages.XX.yml (XX=en,fr,it,etc...), one for each language.
This could be perfect for short texts, which possibly do not include any HTML markup. But how do you deal with long text? For instance, how can I manage the translation of a Terms Of Service or an About page?
I guess I should include different templates for each locale I want to use. Am I right?
Thanks for your help!
You can have long texts in .yml translation file as well as html tags. Put your Terms Of Service text in messages.xx.yml file like this:
TermsOfServiceText: >
<p>Here goes my Terms of service code</p>
<p>It can be put in several lines and <strong>can include html tags!</strong></p>
<p>It can also include links</p>
<p>Just make sure that you put '>' sign after your translation keyword like in the first line of this example code
and start your message in next line with double space indentation</p>
Now, in your twig template call translation with this:
{{ 'TermsOfServiceText'|trans|raw }}
raw is used to skip escaping html tags.
I don't think that different templates could be as solution. But feel free to choose what you prefer. I'll go with https://github.com/stof/StofDoctrineExtensionsBundle in particular with the Translatable behaviour.
Websites like Wordpress and Tumblr allow designers to create themes that users can select. In general how would you architect a website to be flexible enough to allow custom themes for users?
Take a look on how Django does it. Django uses a Model-View-Controller-like approach in which you use views to populate a context, and then use that context to process a template. Note that Django has its own MVC terminology.
For example, if we say that our context reads as follows (in pseudo code),
author = 'mntnoe'
title = 'My Title'
content = '<p>This is my content</p>'
we could use the following template:
<h1>{{ title }}</h1>
<div class="author">Author: {{ author }}</div>
<div class="content">
{{ content }}
</div>
Now, you are free to replace the template (or collection of templates) with another one without affecting how the site works.
Seperate content from formatting by using proper html and css. That means using css files for the style rather than inline style inside the html.
You can make several css files (themes if you wish), and switch between them using javascript.
Let your serverside technology of choice simply generate easy to adjust, by css and images, html. A great site of examples is http://www.csszengarden.com/. It emits the same html every time but uses different css and images to style it. Take a look at the html they generate to get ideas.