I am trying to create a filter that will convert an Array to a String.
The error
The filter "toString" does not exist in FooBarMainBundle:Page:News.html.twig at line 15
So far I have the following, mainly followed the official documentation, but during render the filter can not be found.
app/config/services.yml
services:
foobar_main.twig.main_extension:
class: FooBar\MainBundle\Twig\MainExtension
public: false
tags:
- { name: twig.extension }
src/FooBar/MainBundle/Twig/MainExtension.php
<?php
namespace FooBar\MainBundle\Twig;
class MainExtension extends \Twig_Extension
{
public function getFilters()
{
return array(
'toString' => new \Twig_SimpleFilter('toString', array($this, 'toString'))
);
}
public function toString($data)
{
return implode(", ", $data);
}
public function getName()
{
return 'main_extension';
}
}
the Twig template
{% createphp cmfMainContent as="rdf" %}
<div {{ createphp_attributes(rdf) }}>
{% set tags = createphp_content( rdf.tags ) %}
<h5 {{ createphp_attributes( rdf.tags ) }}>{{ tags|toString }}</h5>
</div>
{% endcreatephp %}
Related
I'm using Symfony 4.3 and Sonata 3.x version.
I'm trying to create a custom route in a custom Page but I get the error :
An exception has been thrown during the rendering of a template ("unable to find the route `admin.photocall|admin.photocall_gallery.moderate`")
I have an entity X with a OneToMany relation to the Y entity.
Explanation with code :
class XAdmin extends AbstractAdmin
{
[...]
protected function configureSideMenu(MenuItemInterface $menu, $action, AdminInterface $childAdmin = null)
{
$admin = $this->isChild() ? $this->getParent() : $this;
$id = $admin->getRequest()->get('id');
if ($this->isGranted('LIST')) {
$menu->addChild('Galerie', [
'uri' => $admin->generateUrl('admin.photocall_gallery.list', ['id' => $id])
]);
}
}
}
Then there is my YAdmin :
class YAdmin extends AbstractAdmin
{
protected function configureListFields(ListMapper $listMapper)
{
$listMapper->add('_action', null, [
'actions' => [
'clone' => [
'template' => 'admin/PhotocallListAdmin/__list_action_moderate.html.twig'
]
]
])
;
}
protected function configureRoutes(RouteCollection $collection)
{
if ($this->isChild()) {
$collection->clearExcept(['list', 'moderate']);
$collection->add($collection->getBaseCodeRoute().'.moderate', 'moderate');
return;
}
}
}
So there, I add an action with a template which look like this :
<a class="btn btn-sm" href="{{ admin.generateObjectUrl('moderate', object) }}">
{% if not object.ismoderate %}
Moderate
{% else %}
Undo moderation
{% endif%}
</a>
So the error says that it's unable to find the route admin.photocall|admin.photocall_gallery.moderate. But when I dump the $collection in YAdmin after adding the moderate route, I have two elements :
admin.photocall|admin.photocall_gallery.list (the current page)
admin.photocall|admin.photocall_gallery.moderate
I searched but it looks like that nobody else did this.
Thanks for you help
I write Gaska's comment to close this issue.
I just had to add :
$collection->add('moderate', 'moderate'); and then clear the cache.
Thanks to him
The complete error message
: ype error: Argument 3 passed to Symfony\Bundle\FrameworkBundle\Controller\Controller::render() must be an instance of Symfony\Component\HttpFoundation\Response or null, array given, called in C:\xampp\htdocs\tpOne\src\Esprit\ParcBundle\Controller\VoitureController.php on line 41*
list.html.twig
<ul>
{% for marque in marques %}
<li>{{ marque|upper }}</li>
{% else %}
<strong>la liste des marques est vide!</strong>
{% endfor %}
</ul>
routing.yml
esprit_parc_homepage:
path: /
defaults: { _controller: EspritParcBundle:Default:index }
esprit_parc_affichage:
path: //afficher/{marque}
defaults: { _controller: EspritParcBundle:Voiture:affichage }
esprit_parc_list:
path: /listvoiture
defaults: { _controller: EspritParcBundle:Voiture:list }
Voiture.controller.php
<?php
namespace Esprit\ParcBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
class VoitureController extends Controller
{
/**
* #Route("/affichage/{marque}")
*/
public function affichageAction($marque)
{
return $this->render("#EspritParc/Voiture/affichage.html.twig", array('marque'=>$marque
// ...
));
}
public function listAction() {
//array
$marques=array('BMW','RENAULT','PEUGEOT','FIAT');
$voitures=array(
array(
'id'=>'c2345',
'serie'=>'176',
'dateMiseCirculation'=>'11/10',
'marque'=>'BMW' ),
array(
'id'=>'A2345',
'serie'=>'156',
'dateMiseCirculation'=>'23/06',
'marque'=>'Renault' ),
array(
'id'=>'w0308',
'serie'=>'160',
'dateMiseCirculation'=>'30/08',
'marque'=> 'Fiat')
);
return $this->render("#EspritParc/Voiture/list.html.twig",array('marques'=>$marques),array('voitures'=>$voitures));
}
}
I found a solution. The problem is in the VoitureController.php. The render should be written like this:
return $this->render("#EspritParc/Voiture/list.html.twig", array(
'marques'=>$marques,
'voitures'=>$voitures
));
So I have a menu built as shown in the example below:
<?php namespace AppBundle\Menu;
use Doctrine\ORM\EntityManager;
use Knp\Menu\FactoryInterface;
use Knp\Menu\MenuFactory;
class AdminMenuBuilder
{
public function sidebarMenu(FactoryInterface $factory, array $options)
{
$menu = $factory->createItem('root', array(
'navbar' => true,
'childrenAttributes' => [
'class' => 'nav main-menu',
],
));
$menu->addChild('Dashboard')
->setAttributes([
'icon' =>'fa fa-dashboard',
'class' => 'dropdown',
'dropdown' => true
]);
$menu['Dashboard']->addChild('Details', ['route' => 'app.admin.dashboard']);
$menu['Dashboard']->addChild('Details 2', ['route' => 'app.admin.dashboard']);
$menu->addChild('Users', ['route' => 'app.admin.dashboard.users'])
->setAttribute('icon', 'fa fa-users');
return $menu;
}
}
How can I create a breadcumb using KNPMenuBundle v2? I'm using symfony2 2.7.5
KnpMenuBundle 2.1.0 (released some weeks ago) has a knp_menu_get_breadcrumbs_array() function which you can use. For instance:
{% set item = knp_menu_get('some_menu_item') %}
{% set breadcrumbs = knp_menu_get_breadcrumbs_array(item) %}
{% for breadcrumb in breadcrumbs %}
{{ breadcrumb.label }}
{% endfor %}
If you have nested menu the above solution won't work. Here is the extension that returns array of active menu items recursively:
<?php
namespace AnalyticsBundle\Twig;
use Knp\Menu\ItemInterface;
use Knp\Menu\Matcher\MatcherInterface;
use Knp\Menu\Twig\Helper;
/**
* Class MenuExtension
* #package AnalyticsBundle\Twig
*/
class MenuExtension extends \Twig_Extension
{
private $helper;
private $matcher;
public function __construct(Helper $helper, MatcherInterface $matcher)
{
$this->helper = $helper;
$this->matcher = $matcher;
}
public function getFunctions()
{
return [
new \Twig_SimpleFunction('analytics_get_current_menu_items', function($menu, array $path = array(), array $options = array()) {
$menu = $this->helper->get($menu, $path, $options);
return $this->getCurrentItems($menu);
}),
];
}
private function getCurrentItems(ItemInterface $item)
{
$items = [];
$getActiveItems = function (ItemInterface $item) use (&$getActiveItems, &$items) {
if ($this->matcher->isCurrent($item)) {
$items[] = $item;
foreach ($item->getChildren() as $child) {
$getActiveItems($child);
}
}
};
$getActiveItems($item);
return $items;
}
public function getName()
{
return 'analytics_menu';
}
}
Example usage:
<ul class="page-breadcrumb">
{% for item in analytics_get_current_menu_items('main') %}
<li>
<span>{{ item.label }}</span>
{% if not loop.last %}
|
{% endif %}
</li>
{% endfor %}
</ul>
In my symfony2 action, i have:
$twigCode = '<li>{{ data.value }}</li>'; //In database
$datas = array(array( 'value' => 'line 1'), array( 'value' => 'line 2'));
return $this->render(
'...List.html.twig',
array(
'twigCode' => $twigCode,
'datas' => $datas
)
);
In my twig template, i want something like:
<ul>
{% for data in data %}
{{ render({{ twigCode }}, {data: data}) }}
{% endfor %}
</ul>
Expected that:
<ul>
<li>line 1</li>
<li>line 2</li>
</ul>
You could render and concatenate the twig fragments in the controller:
$templating = $this->container->get('templating');
$someTwig = '';
foreach ($datas as $data)
{
$someTwig .= $templating->render($twigCode, $data);
}
return $this->render('...List.html.twig', array('someTwig' => $someTwig));
Then in the twig:
<ul>
{{ someTwig | raw }}
</ul>
Otherwise, if you really want to do this in the twig you can write a Custom Twig Extension that implements a twig function 'render' so that something like your suggested twig snippet will work:
In the twig extension (you will need to register it as a service, see link above):
class MyTwigExtension extends \Twig_Extension
{
private $templating;
public function__construct($templating)
{
$this->templating = $templating;
}
public function getFunctions()
{
return array(
'render' => new \Twig_Filter_Method($this, 'render'),
);
}
public function render($twigFragment, array $data)
{
return $this->templating->render($twigFragment, $data);
}
}
Then in the twig:
<ul>
{% for data in data %}
{{ render(twigCode, data) | raw }}
{% endfor %}
</ul>
NB - it's possible 'render' is a reserved word for twig, so the custom twig function may need a different name.
You will have to use twig core or may be customized view rendering
Check below code
$loader = new Twig_Loader_Array(array(
'index.html' => 'Hello {{ name }}!',
));
$twig = new Twig_Environment($loader);
echo $twig->render('index.html', array('name' => 'Fabien'));
check here for documentation: http://twig.sensiolabs.org/doc/api.html#built-in-loaders
I am currently developping using symfony2 and using FOSUserBundle for user management.
I built a menus.yml config file to separate html from menu structure. Basicaly I import menus.yml in my config.yml file and it's added to twig's global vars. Here's a look at my menus.yml (Abridged version)
twig:
globals:
menus:
loggedin:
topleft:
-
path: ~
caption: RĂ©seau
icon: glyphicon-comment
submenu:
-
path: nouvelles
caption: Fil de nouvelles
icon: glyphicon-globe
topright:
-
path: ~
caption: "{{ app.user.prenom }} {{ app.user.nom }}"
icon: glyphicon-user
Then, in my template html file, I render the menu using this
{% for m in menus.loggedin.topleft %}
<li class="dropdown">
{{ m.caption }}
<ul class="dropdown-menu">
{% for item in m.submenu %}
<li>{{item.caption}}</li>
{% if item.seperator is defined and item.seperator == true %}
<li class="divider"></li>
{% endif %}
{% endfor %}
</ul>
</li>
{% endfor %}
But I am unable to display the user's first name and last name as the textual value gets printed as is into the html page. I tried hooking the app.user into caption like this
caption: %app.user.prenom% %app.user.nom%
But it doesn't work, saying the value doesn't exist (yet?)
Anybody has a clue how I can work this around?
I looked for an equivalent of the eval() PHP or Javascript function in Twig and found this SO question: Twig variables in twig variable.
Here is the code from an answer by Berry Langerak which define a Twig filter:
<?php
/**
* A twig extension that will add an "evaluate" filter, for dynamic evaluation.
*/
class EvaluateExtension extends \Twig_Extension {
/**
* Attaches the innervars filter to the Twig Environment.
*
* #return array
*/
public function getFilters( ) {
return array(
'evaluate' => new \Twig_Filter_Method( $this, 'evaluate', array(
'needs_environment' => true,
'needs_context' => true,
'is_safe' => array(
'evaluate' => true
)
))
);
}
/**
* This function will evaluate $string through the $environment, and return its results.
*
* #param array $context
* #param string $string
*/
public function evaluate( \Twig_Environment $environment, $context, $string ) {
$loader = $environment->getLoader( );
$parsed = $this->parseString( $environment, $context, $string );
$environment->setLoader( $loader );
return $parsed;
}
/**
* Sets the parser for the environment to Twig_Loader_String, and parsed the string $string.
*
* #param \Twig_Environment $environment
* #param array $context
* #param string $string
* #return string
*/
protected function parseString( \Twig_Environment $environment, $context, $string ) {
$environment->setLoader( new \Twig_Loader_String( ) );
return $environment->render( $string, $context );
}
/**
* Returns the name of this extension.
*
* #return string
*/
public function getName( ) {
return 'evaluate';
}
}
Example usage:
$twig_environment->addExtension( new EvaluateExtension( ) );
Use it in the template:
{% set var = 'inner variable' %}
{{'this is a string with an {{var}}'|evaluate}}