symfony twig render dynamic twig code - symfony

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

Related

Some mandatory parameters are missing ("user") to generate a URL for route

My motivation is to edit values displayed in this edit form. But when I press edit button it throws out this error. I can't figure it out. Can anyone help what is missing in my code?
An exception has been thrown during the rendering of a template ("Some
mandatory parameters are missing ("user") to generate a URL for route
"sokosimu_editor_edit_editoruser".") in
SokosimuEditorBundle:User:editUser.html.twig at line 7. 500 Internal
Server Error - Twig_Error_Runtime
Router
sokosimu_editor_edit_editoruser:
path: /edit/editoruser/{user}
defaults: {_controller:SokosimuEditorBundle:Editor:editEditorUser}
requirements:
_method: GET|POST
Controller
public function editEditorUserAction(User $user,Request $request){
$form = $this->createForm(new EditUserType(),$user);
//2. handle the submit (will happen on POST)
$form->handleRequest($request);
if($form ->isValid() && $form->isSubmitted()){
}
$em = $this->get('doctrine')->getManager();
$editUser = $user ->getEditoruser();
return $this->render('SokosimuEditorBundle:User:editUser.html.twig', array(
'form' => $form->createView()
));
}
View
{% block title %}Edit User{% endblock%}
{% block body %}
<form action="{{ path('sokosimu_editor_edit_editoruser') }}" method="post" {{ form_enctype(form) }} class="formedit">
{{ form_errors(form) }}
{{ form_row(form.alias)}}
{{ form_row(form.email) }}
{#{{ form_row(form.password) }}#}
{{ form_row(form.mobile) }}
{{ form_row(form.submit) }}
{{ form_rest(form) }}
</form>
{% endblock %}
Form
<?php
namespace Sokosimu\EditorBundle\Form\Type;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class EditUserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('alias','text',array('required'=>false));
$builder->add('email', 'email',array('required'=>true));
// $builder->add('password','password',array('required'=>true));
$builder->add('mobile','text',array('required'=>false));
$builder->add('submit', 'submit');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Sokosimu\UserBundle\Entity\User'
// 'data_class' => NULL
));
}
public function getName()
{
return 'editUser';
}
}
You need to pass user in the path:
<form action="{{ path('sokosimu_editor_edit_editoruser', {'user': user}) }}" method="post" {{ form_enctype(form) }} class="formedit">
And in controller render the twig with user:
return $this->render('SokosimuEditorBundle:User:editUser.html.twig', array(
'form' => $form->createView(),
'user' => $user
));
Fix route to
sokosimu_editor_edit_editoruser:
path: /edit/editoruser/{userId}
defaults: {_controller:SokosimuEditorBundle:Editor:editEditorUser}
requirements:
_method: GET|POST
Fix controller to
public function editEditorUserAction(Request $request, $userId)
{
$user = $this->getDoctrine()->getRepository('SokosimuEditorBundle:User')->find($userId);
$form = $this->createForm(new EditUserType(), $user);
//2. handle the submit (will happen on POST)
$form->handleRequest($request);
if ($form->isValid() && $form->isSubmitted()) {
$em = $this->get('doctrine')->getManager();
$editUser = $user->getEditoruser();
}
return $this->render('SokosimuEditorBundle:User:editUser.html.twig', array(
'form' => $form->createView()
));
}
With the help from #panche14, I have modified the code a bit.Answer from #panche14 returned object but the form #param expected to be string or integer.
return $this->render('SokosimuEditorBundle:User:editUser.html.twig',
array('form' => $form->createView(),
'user' => $user ->getId();
));
Also add this in twig file:
{'user': user}
as specified by #panche14
Now, the edit button works fine as desired.

How to create a breadcrumb with KNP Menu Bundle 2?

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>

Twig custom filter not recognized

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 %}

Forms symfony2, display my created form in Symfony2

i need your help please , I want to display my created form in Symfony2. I want to display my created form 92 times becouse i have 92 numbers in my database(every number is a form) , i didn't know how to do it here is my code:
controller:
class DefaultController extends Controller
{
public function QuestionsAction(Request $request)
{
$questions = $this->getDoctrine()->getEntityManager()
->getRepository('Tests\TestsPhpBundle\Entity\Question')
->findAll();
$task = new Question();
$forms = $this->createForm(new QuestionType(), $task);
if ($request->getMethod() == 'POST') {
$forms->bindRequest($request);
if ($forms->isValid())
{
$em = $this->getDoctrine()->getEntityManager();
$em->persist($task);
$em->flush();
}
}
{
return $this->render('TestsTestsPhpBundle:Default:index.html.twig', array(
'questions' => $questions,
'forms' => $forms->createView()
));
}
}
}
my form file:
class QuestionType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('categories', null, array('required' => false,
))
->add('text', 'entity', array(
'class' => 'TestsTestsPhpBundle:Question',
'query_builder' => function($repository) {
return $repository->createQueryBuilder('p')->orderBy('p.id', 'ASC'); },
'property' => 'text'))
;
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'Tests\TestsPhpBundle\Entity\Question',);
}
public function getName()
{
return 'question';
}
}
my twig file:
{% block content %}
<h2>Questions</h2>
{% for question in questions %}
<dl>
<dt>Number</dt>
<dd>{{ question.number }}<dd>
{% for form in forms %}
{{ form_row(forms.categories) }}
{{ form_row(forms.text) }}
</dl>
{% endfor %}
<hr />
{% endfor %}
{% endblock %}
I recommend to read capter: Embedding Controller
http://symfony.com/doc/2.0/book/templating.html
<div id="sidebar">
{% render "AcmeArticleBundle:Article:recentArticles" with {'max': 3} %}
</div>
You can make a for loop within Twig Template and call an action (with parameter if needed) where you render the form. -> QuestionsAction in your case.

Adding action in SonataAdminBundle

I'm trying to add an action in sonata admin bundle. I changed my Admin class with :
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('id')
->add('name')
// add custom action links
->add('_action', 'actions', array(
'actions' => array(
'view' => array(),
'calculate' => array('template' => 'myappMyBundle:Admin:list__action_calculate.html.twig'),
'edit' => array(),
)
))
;
}
and
protected function configureSideMenu(MenuItemInterface $menu, $action, Admin $childAdmin = null)
{
if (!$childAdmin && !in_array($action, array('edit'))) {
return;
}
$admin = $this->isChild() ? $this->getParent() : $this;
$id = $admin->getRequest()->get('id');
$menu->addChild('calculate', array('uri' => 'http://google.com?id=' . $id));
}
and put a template called list__action_calculate.html.twig in src/myapp/MyBundle/Resources/views/Admin/ :
{% if admin.isGranted('EDIT', object) and admin.hasRoute('edit') %}
<a href="{{ admin.generateObjectUrl('calculate', object) }}" class="calculate_link" title="{{ 'action_calculate'|trans({}, 'SonataAdminBundle') }}">
<img src="{{ asset('bundles/sonataadmin/famfamfam/page_white_edit.png') }}" alt="{{ 'action_calculate'|trans({}, 'SonataAdminBundle') }}" />
</a>
{% endif %}
But i got this error from symfony :
An exception has been thrown during the rendering of a template
("unable to find the route `mysite.mybundle.admin.myentity.calculate`")
in "SonataAdminBundle:CRUD:list.html.twig"
What have i missed ?
Is there a clue in the documentation than this page of the Doc.
Finally got it !
In the admin class :
protected function configureRoutes(RouteCollection $collection)
{
$collection->add('calculate');
}
# Override to add actions like delete, etc...
public function getBatchActions()
{
// retrieve the default (currently only the delete action) actions
$actions = parent::getBatchActions();
// check user permissions
if($this->hasRoute('edit') && $this->isGranted('EDIT') && $this->hasRoute('delete') && $this->isGranted('DELETE'))
{
// define calculate action
$actions['calculate']= array ('label' => 'Calculate', 'ask_confirmation' => true );
}
return $actions;
}
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('id')
->add('name')
// add custom action links
->add('_action', 'actions', array(
'actions' => array(
'view' => array(),
'calculate' => array('template' => 'chemoinfoEdrugBundle:CRUD:list__action_calculate.html.twig'),
'edit' => array(),
)
))
;
}
and in admin controller :
public function batchActionCalculate(ProxyQueryInterface $selectedModelQuery)
{
...
}
and in /src/mysite/mybundle/Resources/views/CRUD :
{% if admin.isGranted('EDIT', object) and admin.hasRoute('edit') %}
<a href="{{ admin.generateObjectUrl('calculate', object) }}" class="calculate_link" title="{{ 'action_calculate'|trans({}, 'SonataAdminBundle') }}">
<img src="{{ asset('bundles/sonataadmin/famfamfam/calculator.png') }}" alt="{{ 'action_calculate'|trans({}, 'SonataAdminBundle') }}" />
</a>
{% endif %}

Resources