How to load a controller function and render it in a twig tag using Symfony2? - symfony

I am using Symfony2 and Twig. I have a function (below) in my controller that returns a specific text. Is it possible to call that function directly from my template and change the {{text}} in my template to whatever the function returns, possibly via Ajax?
Here's my function:
public function generateCode($url) {
$url = $_SERVER['SERVER_NAME'] . '/embed/' . $url;
$return = '<iframe>'.$url.'</iframe>';
return $return;
}
Another controller function calls the function above and renders my template:
public function getCodeAction($url) {
$text = $this->generateCode($url);
return $this->render('MyMyBundle:User:code.html.twig', array('text' => $text));
}
In my template I am using:
{{ text }}
to display the value.

In Symfony 2.2, this was changed.
The render tag signature and arguments changed.
Before:
{% render 'BlogBundle:Post:list' with { 'limit': 2 }, { 'alt': BlogBundle:Post:error' } %}
After:
{% render controller('BlogBundle:Post:list', { 'limit': 2 }), { 'alt': 'BlogBundle:Post:error' } %}
or
{{ render(controller('BlogBundle:Post:list', { 'limit': 2 }), { 'alt': 'BlogBundle:Post:error'}) }}
Note: The function is the preferred way.
See https://github.com/symfony/symfony/blob/2.2/UPGRADE-2.2.md

You can use ajax if you have dynamic data, but as far as I can see from your brief info, you can always execute that controller function directly from your view:
{% render "MyMyBundle:User:generateCode" with { 'url': 'your url here' } %}
More Information on this available at:
http://symfony.com/doc/2.0/quick_tour/the_view.html, under Embedding other Controllers

For the record, in new versions you need to use the absolute URL:
{{ render url('my_route_id', {'param': value}) }}

{{ render(controller("AcmeDemoBundle:Demo:topArticles", {'num': 10})) }}

In Silex I solved it like this:
{{ render(url('route_name', {'param': value})) }}
If you do not have the route name, URL can be used:
{{ render(app.request.baseUrl ~ '/some-path/' ~ value) }}
If using URL we should always concat the baseUrl.

Symfony 2.6+
in twig:
{{ render(controller('AppBundle:PropertySearch:featuredProperties', {'limit': 15})) }}
controller:
/**
* featuredPropertiesAction
*
* #param Request $request
* #param int $limit
*
* #return Response
*/
public function featuredPropertiesAction(Request $request, $limit)
{
$search = $this->resultsHelper->featuredSearch($limit);
return $this->render('HASearchBundle::featured_properties.html.twig', [
'search' => $search,
]);
}

Related

Timber how to implement get_current_url wp

Ive been using Wordpress for more than a year now. But I was stuck with the implementation of Timber twig framework get the current URL. I tried these codes below codes but no luck,.
{{ site.url.current }}
{{ app.request.getRequestUri() }}
Twig templates engine: get current url
Have you tried:
URLHelper::get_current_url()
Doc: https://timber.github.io/docs/reference/timber-urlhelper/#get_current_url
So, you should be able to feed this as a variable into your template.
Or if you want to get a step further and extend Timber's Twig i.e. creating a filter or function like:
$twig->addFilter(new \Twig_SimpleFilter('is_current_url', function ($link) {
return (URLHelper::get_current_url() == $link) ? true : false;
}));
Which should bring things down to:
{{ 'http://example.org/2015/08/my-blog-post' | is_current_url }}
BTW: Internally, get_current_url() returns: $_SERVER['HTTP_HOST']/$_SERVER['SERVER_NAME'] + $_SERVER["REQUEST_URI"]
Adding ['current_url'] in functions.php under add_to_context function worked for me:
public function add_to_context($context)
{
// $context['foo'] = 'bar';
$context['current_url'] = Timber\URLHelper::get_current_url();
$context['site'] = $this;
return $context;
}
You then will be able to use it globally in your twig templates:
<pre>
Current Url: {{ dump(current_url) }}
</pre>

can i pass my php code to twig code of timber

I would like to know if I can convert any types of PHP code to twig, what I want to know is, for example, whether I can pass the code.
<?php
if (ICL_LANGUAGE_CODE == 'in'):?
to
{{ lang.en }}
Is there a way to add any PHP code and turn it into a twig and recognize it?
I use the Timber template for WordPress.
There is a good way to pass your functions (more correctly, register the function to Twig).
Using Timber Hook: timber/twig
There is a class in filter hook timber/twig could help us pass functions to Twig. It calls Timber\Twig_Function.
new Timber\Twig_Function(
'function_name_that_will_be_called_in_Twig',
'function_name_in_php'
);
// OR
new Timber\Twig_Function(
'function_name_that_will_be_called_in_Twig',
function( $input ) {
// anonymous function is ok too.
}
);
functions.php
add_filter( 'timber/twig', 'add_to_twig' );
function hello_in_php( $name = 'world' ) {
$hello = 'Hello ';
$hello .= $name;
return $hello;
}
function add_to_twig( $twig ) {
$func = new Timber\Twig_Function('hello', 'hello_in_php');
$filter = new Timber\Twig_Function('introduce', function( $name ) {
return "I'm ${name}!";
});
$twig->addFunction($func); //Registering a pre-defined function
$twig->addFunction($filter); //Registering a filter function
return $twig;
}
index.twig:
<p id='a'>{{ hello() }}</p>
<p id='b'>{{ hello('who?') }}</p>
<p id='c'>{{ "Batman"|introduce }}</p>
Result is:
<p id='a'>Hello World</p>
<p id='b'>Hello who?</p>
<p id='c'>I'm Batman!</p>
Source: https://timber.github.io/docs/guides/extending-timber/#adding-functionality-to-twig
You mean something like this comparison ?
{% if constant('ICL_LANGUAGE_CODE') == 'en' %}
{# your output here #}
{% endif %}

How to get formatted HTML generated by Symfony

I'm using Symfony2 to generate forms, or actually Twig, which uses Symfony's functions, so the view looks like this:
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
This generates HTML code without any newlines or indentation. This is unreadable when I look into HTML source code.
Is there any way to force Symfony/Twig to format the generated HTML?
This link explains form customization in twig beautifully. There are numerous ways of applying css styling to form elements. For example, if you have a form with a field name you can add a css class to it this way:
{# render a widget, but add a "foo" class to it #}
{{ form_widget(form.name, {'attr': {'class': 'foo'}}) }}
or to the label:
{{ form_label(form.name, 'Your Name', {'label_attr': {'class': 'foo'}}) }}
Then you can use the css classes to render form elements as per your design. Hope you get the idea. The docs and link provided in the answer are both useful in this regard.
Update: the below "solution" made me a headache precisely this line:
$html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
It converts all non-ascii characters to entities, which is not very smart. Javascript's confirm and alert functions don't convert it back to UTF-8, they display strings as they are.
Thanks everybody, but I think I wasn't clear enough:) I didn't mean formatting by css or generally changing how the rendered page looks like, but rather changing HTML source code.
Anyway, with these two articles I finally managed to do what I wanted:
How do you format DOM structures in PHP?
http://php-and-symfony.matthiasnoback.nl/2011/10/symfony2-create-a-response-filter-and-set-extra-response-headers/
Step 1.
So, first the response listener, in (for example) AppBundle/EventListener/ResponseListener.php:
namespace AppBundle\EventListener;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
class ResponseListener {
private $container;
public function __construct(Container $container) {
$this->container = $container;
}
function tidyHtml($html)
{
$dom = new \DOMDocument();
if (libxml_use_internal_errors(true) === true)
{
libxml_clear_errors();
}
$html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
$html = preg_replace(array('~\R~u', '~>[[:space:]]++<~m'), array("\n", '><'), $html);
if ((empty($html) !== true) && ($dom->loadHTML($html) === true))
{
$dom->formatOutput = true;
if (($html = $dom->saveXML($dom->documentElement, LIBXML_NOEMPTYTAG)) !== false)
{
$regex = array
(
'~' . preg_quote('<![CDATA[', '~') . '~' => '',
'~' . preg_quote(']]>', '~') . '~' => '',
'~></(?:area|base(?:font)?|br|col|command|embed|frame|hr|img|input|keygen|link|meta|param|source|track|wbr)>~' => ' />',
);
return '<!DOCTYPE html>' . "\n" . preg_replace(array_keys($regex), $regex, $html);
}
}
return false;
}
public function onKernelResponse(FilterResponseEvent $event) {
$request = $event->getRequest();
//only when format == html and environment == dev
if ($request->getRequestFormat() == 'html' && $this->container->get('kernel')->getEnvironment() == 'dev') {
$event->getResponse()->setContent($this->tidyHtml($event->getResponse()->getContent()));
}
}
}
Step 2.
In services.yml:
response_listener:
class: AppBundle\EventListener\ResponseListener
arguments: ['#service_container']
tags:
- { name: kernel.event_listener, event: kernel.response, method : onKernelResponse }

Passing multiple arguments through twig path

I have this twig code:
<div style="padding-left: 5em" class="comment">
<p>{{ comment.author.name }} - {{ comment.created|date('j. n. Y H:i') }}</p>
<p>{{ comment.text }}</p>
<p>Odpovědět na komentář</p>
{% for child in comment.children %}
{% include 'BlogApplicationBundle:Post:_comment.html.twig' with {'comment' : child}%}
{% endfor %}
</div>
and this is function that processes the output from link in twig code:
/**
* #Route("/post/{id}/newcommentresponse", name="comment_response_new")
* #Template("BlogApplicationBundle:Post:form.html.twig")
*/
public function commentResponceAction($id,$idc)
{
$comment = new Comment();
$form = $this->createForm(new CommentType(), $comment);
return array(
'form' => $form->createView()
);
}
when i try to run code i get this error :
Controller "Cvut\Fit\BiWt1\Blog\ApplicationBundle\Controller\CommentController::commentResponceAction()"
requires that you provide a value for the "$idc" argument (because
there is no default value or because there is a non optional argument
after this one).
So it seems that second argument passsed through link is ignored and i have no idea what am i doing wrong.
You are missing the $idc definition in your #Route annotation. It should look something like this:
#Route("/post/{id}/newcommentresponse/{idc}", name="comment_response_new")
or this:
#Route("/post/{id}/{idc}/newcommentresponse", name="comment_response_new")
You can also leave it out of the route and function declaration and grab it directly from the Controller:
/**
* #Route("/post/{id}/newcommentresponse", name="comment_response_new")
* #Template("BlogApplicationBundle:Post:form.html.twig")
*/
public function commentResponceAction($id)
{
$idc = $request->query->get('idc');

Can verbatim be used on contents of an include?

I'm sharing templates between client and server and would like to output the raw template inside a script tag which is possible with verbatim.
http://twig.sensiolabs.org/doc/tags/verbatim.html
However it would be nicer if this could be applied as a filter to the include but it doesn't seem possible?
I'm new to twig so excuse me if i've missed obvious functionality.
I ran into the same problem, and this page came up in my search results. In the time since this question was answered, the Twig developers added this functionality into the library. I figured I should add some details for future searchers.
The functionality to include raw text (aka for client-side templates using the same syntax as Twig) is accomplished with the source function.
Ie: {{ source('path/to/template.html.twig') }}
http://twig.sensiolabs.org/doc/functions/source.html
I was looking for something like this too because I'm using Twig.js for some client-side templating along with Symfony. I was trying to share templates between the server-side and client-side code, so I needed content to be parsed in some cases and treated as verbatim in others, which proved to be a bit tricky.
I couldn't find anything built into Twig to help with this, but luckily, it's pretty easy to extend Twig to get what you're looking for. I implemented it as a function, but you may be able to do it as a filter too.
services.yml
statsidekick.twig.include_as_template_extension:
class: StatSidekick\AnalysisBundle\Twig\IncludeAsTemplateExtension
tags:
- { name: twig.extension }
IncludeAsTemplateExtension.php
<?php
namespace StatSidekick\AnalysisBundle\Twig;
use Twig_Environment;
use Twig_Extension;
class IncludeAsTemplateExtension extends Twig_Extension {
/**
* Returns a list of global functions to add to the existing list.
*
* #return array An array of global functions
*/
public function getFunctions() {
return array(
new \Twig_SimpleFunction( 'include_as_template', array( $this, 'includeAsTemplate' ), array( 'needs_environment' => true, 'is_safe' => array( 'html' ) ) )
);
}
function includeAsTemplate( Twig_Environment $env, $location, $id ) {
$contents = $env->getLoader()->getSource( $location );
return "<script data-template-id=\"{$id}\" type=\"text/x-twig-template\">{$contents}</script>";
}
/**
* Returns the name of the extension.
*
* #return string The extension name
*/
public function getName() {
return 'include_as_template_extension';
}
}
Usage in Twig file
{{ include_as_template( 'Your:Template:here.html.twig', 'template-id' ) }}
If you have a Twig file like this:
<ul class="message-list">
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
The output will be this:
<script data-template-id="template-id" type="text/x-twig-template">
<ul class="message-list">
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
</script>
The work is derived from Kari Söderholm's answer here. Hope that helps!

Resources