i want to use the php stripslashes function inside a twig template but this function is not a standard twig function, so i have to add it to twig as an extension, i tried this code inside a controller, but it doesnt work:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
class XController extends Controller
{
public function YAction($page)
{
$twig=$this->get('twig');
$twig->addFunction('functionName', new Twig_Function_Function('someFunction'));
...
do i need a use statement for the "Twig_Function_Function" class?
am i doing this wrong?
If you want to use it in your twig templates, you don't need to make any add or call inside your controller, Read the How to write a custom Twig Extension section of the documentation.
Basicaly, you need to create an Extension Class that extends \Twig_Extension , then you need to register it as a service using the twig.extension tag. And finally you need to implement the getFunctions() method in order to add customized twig functions.
But in your case better is to add a filter, with the same logic you can also add a getFilters() method in your extension class so that you can specify your customized filters.
Also, take a deeper look at the Extending Twig section of the documentation to understand all the ways twig can be extended.
Or {{ function('stripslashes', "This\\'ll do") }}
(or apply stripslashes() when building your Twig context)
But, also, if you do this in php:
add_filter('timber/twig', function(\Twig_Environment $twig) {
$twig->addFunction(new Twig\TwigFunction('stripslashes', 'stripslashes'));
return $twig;
});
Then this works in twig:
{{ stripslashes("This\'ll do...") }}
Related
How can i create the global variable in symfony controller like in laravel (example: view()->share('now', date('Y-m-d')); ), that it availiable in all templates?
Setting a global template variable
It is possible to set a global variable available in every template using the addGlobal function in the BaseController class.
$this->get('twig')->addGlobal('today', date('Y-m-d'));
The Twig date functions
Remember that Twig is at its core simply a templating enging for php; it's a skin, an illusion. It replaces the old style <?php echo date('Y-m-d'); ?> commonly used in php. This means two things:
Twig statements are executed server-side
Twig can access (most) php's native function
So in order to set a global variable with today's date, you can imply add the following line:
{% set today = date() %}
If you want to have today be available every template, simply set it in your base.twig.html template. Alternatively you can also use the function only when needed.
Set it as a class property. Eg
class DefaultController extends Controller
{
private $now = new \DateTime();
public function page1Action()
{
$this->render('...', ['now'=>$this->now]);
}
public function page2Action()
{
$this->render('...', ['now'=>$this->now]);
}
}
one possibility is to create variable in session like this.
$session = $this->get('session');
$session->set('var', $my_variable);
in another controller you just get it like this
$session->get('var');
in twig you can get your variable
{% app.session.get('var') %}
it can resolve your issue and it is avalaible for a user not globally.
I have a function in my controller like this:
<?php
namespace GradeBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use GradeBundle\Entity\User;
use GradeBundle\Entity\SchoolClass;
class MainController extends Controller
{
/**
* #Route("/", name="index_page")
*/
public function index()
{
return $this->render('GradeBundle:Default:index.html.twig');
}
It renders the twig template correctly. However when I use other function:
/**
* #Route("/adminNew", name="add_admin")
*/
public function addAdmin()
{
$session = new Session();
if($session->get('loggedIn') == null)
return $this->redirect($this->generateUrl('index_page'));
else
return $this->render('GradeBundle:Add:newAdmin.html.twig');
}
I have the following error:
Unable to find template "GradeBundle:Default:index.twig.html".
Does anybody have any idea what might be wrong?
It's a typo somewhere you call template:
GradeBundle:Default:index.twig.html
But you have only GradeBundle:Default:index.html.twig template.
Note the difference: html.twig twig.html
I suspect that you extend it in GradeBundle:Add:newAdmin.html.twig by:
{% extends 'GradeBundle:Default:index.twig.html' %}
but should be:
{% extends 'GradeBundle:Default:index.html.twig' %}
Have you made sure to use the correct namespace for the Controller you're using? And are you including the correct files? Also I'm not sure I understand the question correctly - are you saying if you add another function with a different twig file render, the first one no longer renders? Could I see your class names and the namespaces / use statements?
Usually in these instances, it's that the templates are in the wrong place or the correct file is not included in order to find it.
Michael
I do have a twig extension which has a method that uses another method from a different controller to render a json output via dependency jsonResponse.
How can I render a controller within a twig extension?
The following code below doesn't seem to work, because render() needs a view file instead of a controller. And I am now referencing to a controller.
class AreaExtension extends \Twig_Extension {
public function add()
{
$outputJson = $this->container->get('templating')->render(new ControllerReference('CMSCoreBundle:Area:index'));
}
}
$ref = new ControllerReference('CMSCoreBundle:Area:index');
$this->handler->render( $ref, 'inline', $options );
Where $this->handler is the fragment.handler service.
In your case:
$outputJson = $this->container->get('fragment.handler')->render(new ControllerReference('CMSCoreBundle:Area:index'));
You can find a full example in this symfony twig extension, see:
https://github.com/symfony/symfony/blob/4.1/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension.php#L28
and
https://github.com/symfony/symfony/blob/4.1/src/Symfony/Bridge/Twig/Extension/HttpKernelRuntime.php#L41
In my Symfony2 app, I want to globally fetch a value from my database on each template and don't want to call on each Controller. I know I could define that as a service and inject that service into my twig templates (by defining it as a twig global).
Is that the common and recommended way? Or should I rather create an abstract Controller class where I fetch that value in my constructor and then inherit from all my other Controllers?
Note: It is actually not a static value that is the same for all users, but it is a user specific value which is different for each user.
If this variables are used to render the same spot on your page you can render an embedded controller. Like this:
<div id="sidebar">
{{ render(controller('YourBundle:User:stats')) }}
</div>
This will inject whole output of YourBundle/UserController/statsAction to the #sidebar div. Inside this action you can extract all inforamtion that you need.
If you need to use this variables in other way maybe you should look at response event.
Are you familiar with event listeners? http://symfony.com/doc/current/cookbook/service_container/event_listener.html
An event listener can be used to inject twig globals.
class ModelEventListener extends ContainerAware implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(
KernelEvents::CONTROLLER => array(
array('doProject', -1300),
),
KernelEvents::VIEW => array(
array('doView', -2100),
),
);
}
public function doProject(FilterControllerEvent $event)
{
$project = $whatever_is_needed_to_find_the_project();
if (!$project) throw new NotFoundHttpException('Project not found ' . $projectSearch);
// Add to request
$event->getRequest()->attributes->set('project',$project);
// Give all twig templates access to project
$twig = $this->container->get('twig');
$twig->addGlobal('project',$project);
}
# services.yml
cerad_core__model__event_listener:
class: '%cerad_core__model__event_listener__class%'
calls:
- [setContainer, ['#service_container']]
tags:
- { name: kernel.event_subscriber }
If it's a user value like you said you can get app.user.XXX on every twig template you need without processing nothing ;)
Am not very familiar with twig, am trying to get an image extention, but am not sure how to do this in twig ,in php it's very easy using string functions such as substr and indexof or with the following: ext=pathinfo('/testdir/dir2/image.gif', PATHINFO_EXTENSION), i don't want to code it in controller and pass it to twig as parameter,instead i want to extract it directly in the twig layout,so how am going to do this?
You can get file extension by this way
{{ "filename.txt"|split('.')|last }}
One approach would be to use Twig's slice filter.
For example, if the path to your image file is imgSrc, then imgSrc|slice(-4) will give you the last 4 characters of the filename (eg. .gif, .jpg, jpeg).
You can create Twig extension, that will contain
namespace YourApp\AcmeBundle\Twig;
class MyTwigExtension extends \Twig_Extension
{
public function getFilters(){
return array(
new \Twig_SimpleFilter('ext', array($this, 'ext')),
);
}
public function ext($filepath){
$ext = pathinfo($filepath, PATHINFO_EXTENSION);
return $ext;
}
}
In twig, use the split filter. see http://twig.sensiolabs.org/doc/filters/split.html
you can also simply get the extension in the controller and pass it to twig.