Symfony how to include controller on base.html.twig - php

I have a small question, I'm new to symfony, I created a controller and a menu template that I want to integrate into my base.html.twig.
I absolutely need the controller to be called because I am testing to know if the session variable is empty or not.
{% block menu %}
{% include 'menu/index.html.twig' %}
{% endblock %}
<body>
{% block body %}{% endblock %}
</body>
So I tried this (it works perfectly BUT it didn't call my controller so when I do my test on session it won't work....)
I searched but I can't include the controller instead of the template...
thanks in advance

In Symfony, you cannot call a Controller from inside a twig, what you can do is store variables inside a Controller, and then call those variables from inside the twig.
For example, in your case, in the Controller you create your variable and save it in the session as follows:
//...
class BaseController extends AbstractController
{
//...
$session->set('var_i_need', 222);
return $this->render('menu/index.html.twig', [
'controller_name' => 'BaseController',
]);
}
Then inside the twig you get the variable:
{% set var_i_need = app.session.get('var_i_need') %}
And test if it is empty or not:
{% if var_i_need is not NULL %}
{% ... %}
{% endif %}

The controller shouldn't be called from a twig. EOT
You need to move your code from controller to service or helper.
Then you should run the service from controller.
Also, you need to create a new twig function and call service/helper code in this function.
This way the code form controller will be executed in twig - in the right way.

Related

Is there a way, to change a block of a twig template within a controller (php file)

Let's say I have the following twig templates:
{% block header %}My header{% endblock %}
{% block middle %}My middle{% endblock %}
{% block footer %}My footer{% endblock %}
In my controller, I render the twig file (with laravel twig bridge, but it would be similar in other frameworks):
public function index() {
$view = view('template.twig');
return $view->render();
}
So is there a way, to manipulate the $view to set for example the block middle to My new middle, within the controller, without touching the template.twig file?
I know, I could create a new child.twig where I do
{% extends "template" %}
{% block middle %}My new middle{% endblock}
but is there a way to do it, without an extra twig file directly form the controller? Something like
$view->setBlock('middle', 'My new middle');

Inherit dynamic template in Phalcon Volt

I need to load a page, that will be "inserted" in a template - as I read it, Volt's Template Inheritance should do the trick and it does... kinda. Hardcoded values, as shown in the examples, work fine - the following example works:
<!-- Template -->
<div id="site_content">
{% block test %}
{% endblock %}
</div>
and the page, that inherits the template:
{% extends "../../templates/de/index.volt" %}
{% block test %}
{{ content() }} {# this is a registered volt function that outputs the generated content #}
{% endblock %}
However, the same page might need to inherit a different template and that must be decided on runtime, so the name of the template must be generated dynamically. Two options occurred to me:
Set the template name to a variable and use it when extending - the problem here is that I don't see a way to use it afterwards. That guy seems to have had the same problem, but there is neither an answer of how to do it, nor a confirmation that it isn't possible at all.
Register another function to generate the complete string (e.g. {% extends "../../templates/de/index.volt" %}) and then compile it, e.g.
$compiler->addFunction('get_template',
function ($resolvedArgs, $exprArgs) use ($volt) {
return $volt->getCompiler()
->compileString('{% extends "../../templates/de/index.volt" %}');
});
and then use that function in the page, e.g.
{{ get_template() }}
{% block test %}
{{ content() }}
{% endblock %}
However, using that approach does not parse the page content (e.g. the content returned by the registered content() function is not shown). I'm also open to other solutions (using Twig instead of Volt is only a last resort, for performance issues), advices of what I'm doing wrong or pointers of useful articles on the topic. Thanks in advance!
Try using partials as documented in the Phalcon doc: Using Partials

embedding a form view in a parent view

My Symfony app view layout is a three level hierarchy, such that there is the baseview.html.twig and then the child of that is layout.html.twig and then the child of layout view is X,Y,Z,.... .html.twig. I wanted to pass in a form to the layout.html.twig, however where in my controller should I do this?
Here's some code to make it more clear of the hierarchy. In the bottom base line view I have the following:
{% extends 'AppMainBundle::layout.html.twig' %}
and then in layout.html.twig I have:
{% extends '::base.html.twig' %}
so I wanted to pass in a formView to my layout.html.twig, the question is how??
Use blocks like block content in documentation
For Ex:
{% extends '::base.html.twig' %}
{% block content %}
{{form_widget(form)}}
{% endblock %}
Now content block will be replaced in parent by your block.

How to embed an action from a sub-namespaced controller in Symfony 2?

I'm trying to render an action which is in a sub-namespaced controller from within a Twig view in Symfony 2.
The problem is: The render helper cannot find the controller/action because it's in a namespace below Controller.
This is my controller:
src/Acme/Bundle/TestBundle/Controller/FirstModule/ExampleController.php
namespace Acme\Bundle\TestBundle\Controller\FirstModule;
class ExampleController extends Controller
{
public function exampleAction(Request $request)
{
return $this->render('AcmeTestBundle:FirstModuleExample:example.html.twig');
}
public function embedAction(Request $request)
{
return $this->render('AcmeTestBundle:FirstModuleExample:embed.html.twig');
}
}
This is my view:
src/Acme/Bundle/TestBundle/Resources/views/FirstModuleExample/example.html.twig
{% render "AcmeTestBundle:Example:embed" %}
// or
{% render "Acme\Bundle\TestBundle\Controller\FirstModule\Example:example" %}
// or
{% render "Acme\Bundle\TestBundle\Controller\FirstModule\ExampleController:exampleAction" %}
I have read the Embedding Controllers documentation but no clue there how to handle Controllers that are in a sub-namespace.
Thanks.
Either of these should work. Remember, backslashes in strings need to be escaped (i.e., doubled)
{% render "AcmeTestBundle:FirstModule\\Example:embed" %}
or
{% render "Acme\\Bundle\\TestBundle\\Controller\\FirstModule\\ExampleController::embedAction" %}
Have you tried this?
{% render "AcmeTestBundle:FirstModule/Example:embed" %}
or this?
{% render "AcmeTestBundle:FirstModule\\Example:embed" %}
I think you should be able to use backslash-notation but I haven't tried it since I practice to put all controllers into single namespace (which is bad if you have a lot of them).
Something like this:
{% render "Acme\Bundle\TestBundle\Controller\FirstModule\Example:example" %}

Twig extend template on condition

I use Symfony 2 with Twig and my question is pretty straightforward:
In a view I want to extend one of the layouts based on a variable. If the variable is false I want to extend UdoWebsiteBundle::layout.html.twig and if it's true I want to extend UdoWebsiteBundle::layout_true.html.twig.
Here is the code I tried:
{% block layout_extender %}
{% if intro == 'false' %}
{% extends 'UdoWebsiteBundle::layout.html.twig' %}
{% else %}
{% extends 'UdoWebsiteBundle::layout_true.html.twig' %}
{% endif %}
{% endblock %}
I get this error:
Multiple extends tags are forbidden in "UdoWebsiteBundle:home:home.html.twig" at line 7
Is there any other way to achieve this?
Try this one:
{% extends intro == 'false'
? 'UdoWebsiteBundle::layout.html.twig'
: 'UdoWebsiteBundle::layout_true.html.twig' %}
Idea taken from here: http://jorisdewit.ca/2011/08/27/extending-different-layouts-for-ajax-requests-in-twig-symfony2/
To keep it neat you should use Twig dynamic inheritance support by using a variable, defined in your controller, as the base template:
{% extends parent_template_var %}
If the variable evaluates to a Twig_Template object, Twig will use it as the parent template.
Define parent_template_var in your controller:
if($intro == 'false')
$parent_template_var = 'UdoWebsiteBundle::layout.html.twig';
}else{
$parent_template_var = 'UdoWebsiteBundle::layout_true.html.twig';
}
return $this->render('::/action.html.twig', array('parent_template_var' => $parent_template_var ));
http://twig.sensiolabs.org/doc/tags/extends.html
Answer from the official documentation:
Conditional Inheritance
As the template name for the parent can be any valid Twig expression, it's possible to make the inheritance mechanism conditional:
{% extends standalone ? "minimum.html" : "base.html" %}
In this example, the template will extend the "minimum.html" layout template if the standalone variable evaluates to true, and "base.html" otherwise.
You cannot extends multiple template, that's why you've got the error, if you want to so, you need to push them in an array like below.
{% extends ['MyAppCustomBundle::Layout/layout.html.twig', 'FOSUserBundle::layout.html.twig'] %}
But you will need to use Twig version 1.2 to do it.
twig documentation
This all makes sense to do either this template or that template.
But let me describe another situation. You have a profile form and a form where users can upload personal profile related documents. Since the profile form is already very long the documents moved to a new form.
Everything works great. Now we want to use the bootstrap tabs to do Profile | Documents for user friendliness.
Now I know because we are using two seperate forms if you submit the documents the changes on the profile won't save and vice versa.
I have added the document form in the tab using
<div role="tabpanel" class="tab-pane" id="documents">
{{ render(controller('ManyAppBundle:Document:createDocument', {'viewOnly': true})) }}
</div>
The 'viewOnly': true is a query parameter and is not required by the action.
My question now becomes if the profile tab renders the document template it must only show the upload widget and the submit where as when you go directly to the document page it must show the title and side bar and everything. So I did try
{% if not viewOnly %}
{% extends ... %}
{% endif %}
That gave problems because you can't use extends within a if. Like you suggested in other answers try using
{% extends viewOnly == true ? ... %}
This reolved the Twig issue up to the execution of the code when viewOnly is false.
When viewOnly is false it must extend the base template used by all other templates but if it is true I only want to show this:
{{ form_start(form, { 'style': 'horizontal', 'col_size': 'sm' }) }}
{% if form.documents is defined %}
{{ form_row(form.documents) }}
{% endif %}
{{ form_row(form.submit, { 'attr': { 'class': 'btn btn-success' } }) }}
{{ form_end(form) }}
But now with the top
{% extends viewOnly == true ? ... %}
if viewOnly becomes false it fails with Template "" can't be find.
Is there a way to say extends this specific template that will be the same result of not extending any template?
Or alternatively is there a way of saying extend this when viewOnly true but nothing happens on the fail?

Categories