embedded controller vs twig extension - symfony

This is more a discussion question:
Given you have a component in your bundle, that consists of a service, maybe a model and template and you want to give an easy way to include it in your main templates.
You could provide a twig extension which internally uses a helper to render the template like:
{{ acme_render_component({foo: 'bar'}) }}
or you would decide to let the main template use a embedded controller like:
{{ render(controller('AcmeBundle:CoolComponent:render', { 'foo': bar })) }}
I guess the cases behave different:
With the twig extension, you would probably use the service first to fill the model and fetch it again in the template.
With the controller you would probably execute the service on demand.
What are the differences, advantages or caveats?
When should you provide the one or the other, or both?

I guess one reason to use a custom Twig extension is performance. A call to "render" in a Twig template is a completely new Request that goes through the whole Symfony lifecycle.

Related

Handlebars Dynamic Partial Failover

Is there a way to have partial failover when using dynamic partials?
Handlebars partials documentation
Shows dynamic partials, and only shows failover with hardcoded partial names.
There is a github issue being tracked for this here - https://github.com/wycats/handlebars.js/issues/1371#issuecomment-361727713 - and link above includes a "hack" to achieve what you are wanting:
{{#>( lookup . 'intendedTemplate' )}}
No template matched for "{{intendedTemplate}}"
{{/undefined}}
That is, you close your dynamic partial block with {{/undefined}}.

Best practice for rendering page fragments

I have trivial complex page.
For example: content(left) and sidebar(right).
Sidebar consists of a plurality of parts. We take a look at one of theese. This fragment contains list of users(for example) subscribed to the event. The list displays only 5 users and "More" button, which loads more users when clicked (ajax).
If i use:
{% render controller('SomeBundle:Event:subcribers', {page: 1, limit: 5}) %}
Or:
{% render path('event_subcribers_route', {...}) %}
It will cause a subrequest. Notice: in this case i use this route 'event_subcribers_route' for ajax request.
Question: Maybe exists way to avoid dozens subrequests?
I'm aware that i can use services, with render logic inside them, but maybe exists some best practice for this common task.
What is wrong with subrequests?
Maybe you think about more traffic between browser and server as it will happen if you have many images, css files or javascript directives in your HTML.
This is not the point using internal subrequests within the Symfony framework. actually this is just some program-logic or design pattern.
browser->request->[router->controller->view]->response->browser
^ |
| |
|<-subrequest-V
This is a very simplified schema of a subrequest like it happens using the {% render controller() %} in Twig. Between the [ and ] is inside Symfony. You just stay into the application.
Everytime you include that piece of HTML you will need to do the according subrequest to the database no matter which method you use.
But, you can optimize the query to recover those users. You can select only the fields you actually need (username, slug, etc.) and also you can do it on a single query. That single query will become a prepared statement and you can even put index on the table to make the query faster.
In addition, you can implement the symfony cache system to avoid those subrequest that symfony does on every load. If your snippet loads always the same 5 users or they change after X minutes you can easily implement an efficient cache.

What's the difference between the include tag and the include function?

I saw someone including a template on his application using the twig template system.
He included his template like this:
{{ include( 'Bundlename:Directory:template.html.twig' ) }}
instead of this:
{% include 'Bundlename:Directory:template.html.twig' %}
At first I thought he was using a custom twig extension, but it actually
works on symfony in general, even though its not documented.
http://twig.sensiolabs.org/doc/tags/include.html
So is there a difference between the two?
why is it not documented?
if the syntax is wrong why is it even working?
It is documented http://twig.sensiolabs.org/doc/functions/include.html.
Twig tag include vs function include

Custom routes inside shared template

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.

How to get objects in a razor template in Tridion?

I am writing a common Razor TBB, which will use in Component Template and Page template as per my requirement.
So that, I need a Page and Component object in the razor TBB according to applying TBB on Page Template and component Template
My requirement to display/use the metadata field values from Page/Component in specific area of the page.
That's why, i want to access metadata values by the object but unable to get the object,
Please also follow-up my comments with Frank.
Can any one suggest me?
Did you have a look at the (remarkably helpful) documentation that is available for the Razor mediator?
http://code.google.com/p/razor-mediator-4-tridion/
http://code.google.com/p/razor-mediator-4-tridion/downloads/detail?name=RazorMediatorDocumentation_v1.2.docx
These are full of examples that access the current Component and the Page. Just my 10 second search gives these fragments:
<body class=”#Page.Metadata.BodyClass”>
<div class=”#Component.Fields.NewsStyle”>
<img src=”#Fields.HeaderImage.ID” alt=”#Fields.HeaderImage.AltText” />
Edit: I see you added some more details in your follow-up comment. You might want to do as Bart suggests and add those details to the question. In the meantime, I'll spend a few more minutes searching the documentation for you.
The official documentation (the Word document I linked above), contains this example that seems to process metadata:
#foreach (var keyword in Publication.MetaData.SomeKeywordFields) {
<li>#keyword.Title (#keyword.Id)</li>
}
The output of the Razor template will become the Output item in the Package. So it doesn't make any sense to use a Razor mediator to process the Output item. For that you might as well use a regular C# (fragment or assembly) TBB.
Another edit: It seems that the Razor mediator's implicit Fields variable always maps to the Component fields and the Metadata variable always maps to the Component's meatadata fields. I've linked the above names to the relevant fragments on Google code for your convenience.
So you seem to have two options:
detect whether you are in Page or Component (e.g. by looking at whether the implicit Page variable is null or not) and then have conditional expressions everywhere (isInPage ? Page.Metadata : Metadata)
fix this limitation of the Razor mediator code yourself or hire someone to fix it for you

Resources