Symfony2 include and access to the variables - symfony

I dont have access to variables when try to include other file.
I try to add with keyword in include but dont work, all time i get message:
Variable "entity" does not exist in
ISLabBundlesBlogBundle:Post:last_post.html.twig at line 6
First i have indexAction() where i list all published blog post.
public function indexAction()
{
$posts = $this->getDoctrine()->getRepository('ISLabBundlesBlogBundle:Post')->getAllPublishedPosts();
return $this->render('ISLabBundlesBlogBundle:Page:index.html.twig', array(
'posts' => $posts
));
}
And have method where list only last posts
public function lastPostAction($count = 1)
{
$entity = $this->getDoctrine()->getRepository('ISLabBundlesBlogBundle:Post')->getLastPosts($count);
return $this->render('ISLabBundlesBlogBundle:Post:last_post.html.twig', array(
'entity' => $entity
));
}
Problem is in this file in block sidebar. I try to include other file where i fetch only 1 last post.
{% extends 'ISLabBundlesBlogBundle::layout.html.twig' %}
{% block body %}
{# Fetch all post#}
{% if posts %}
{% for post in posts %}
<article class="blog">
<div class="date"><time datetime="{{ post.created|date('c') }}">{{ post.created|date('l, F j, Y') }}</time></div>
<header><h2> {{ post.title }} </h2></header>
<p> {{ post.body }} </p>
</article>
{% endfor %}
{% endif %}
{% endblock %}
{% block sidebar %}
{% include 'ISLabBundlesBlogBundle:Post:last_post.html.twig'%}
{% endblock %}
And here is file what i try to include:
<h2>Last Posts</h2>
<div class="blog">
<ul>
{% for item in entity %}
<li>{{item.title}}</li>
{% endfor %}
</ul>
</div>
What i do wrong? And how to slove this?

You need to pass entity to your index template:
public function indexAction()
{
$posts = $this->getDoctrine()->getRepository('ISLabBundlesBlogBundle:Post')->getAllPublishedPosts();
$entity = $this->getDoctrine()->getRepository('ISLabBundlesBlogBundle:Post')->getLastPosts(1);
return $this->render('ISLabBundlesBlogBundle:Page:index.html.twig', array(
'posts' => $posts,
'entity' => $entity,
));
}
It's also possible (and probably better) to do this with an embedded controller:
{% block sidebar %}
{{ render(controller('ISLabBundlesBlogBundle:Post:lastPost', {
'count': 1
})) }}
{% endblock %}
http://symfony.com/doc/current/book/templating.html (search for Embedding Controllers)

Related

Using Nested Include Twig

in my header.twig :
<ul class="nav list-unstyled">
{% for item in data %}
{% include 'partials/item/header/item-nav.twig' %}
{% endfor %}
</ul>
in my item-nav.twig
<li>{{ data.menu_name }}</li>
header.twig is included in base.twig. I rendered base.twig in base.php file. Where I can add data arrayto process data.url and data.name? in base.php ? or i rendered file php again ? Thank you.
base.php
include __DIR__ . '/../vendor/autoload.php';
$renderer = new \Resilient\TwigRenderer(__DIR__ . '/../vemale-beta-desktop/templates/', ['debug' => true]);
$renderer->addExtension(new Twig_Extension_Debug());
$faker = Faker\Factory::create();
$data = [
'assets_url' => 'http://devel.merdeka.com/ui/2017/april/Vemale/',
'meta_title' => 'Vemale Beta',
'meta_description' => 'Vemale Beta Desktop',
'data' => ['menu_name' => 'PARENTING']
];
/*foreach ( range(0, 10) as $k ) {
$data['data'][] = [ 'title' => $faker->sentence() ];
}*/
$response = $renderer->render(new \Zend\Diactoros\Response(),'base.twig', $data);
$emitter = new Zend\Diactoros\Response\SapiEmitter();
$emitter->emit($response);
header.twig
<ul>
{% for item in data %}
{{ include('partials/item-nav.twig') }}
{% endfor %}
</ul>
item-nav.twig
<li>{{ item.<other-property> }}</li>

symfony, can't I access to entity on another controller?

DefaultController.php
public function indexAction(Request $request) {
if ($request->get ( 'email' )) {
$email = $request->get ( 'email' );
$em = $this->getDoctrine ();
$mst_USERS = $em->getRepository ( 'AppBundle:mst_USERS' );
$mst_USERS->findAll ();
return $this->render ( 'default/main.html.twig', array (
'email' => $email,
'mst_USERS' => $mst_USERS
) );
}
main.html.twig
{% block styleSheet %}
<style>
</style>
{% endblock %}
{% block body %}
<div id="container">
THIS IS
{{email}}
<ul>
{% for mst_USERS in mst_USERS %}
<li>{{mst_USERS.email}}</li>
{% endfor %}
</ul>
</div>
{% endblock %}
{% block styleSheet %}
<style>
</style>
{% endblock %}
I tried to use AppBundle:mst_USERS entity for DefaultController but It doesn't work at all.
It was working on another controller, named mst_USERSController.php
Can't I using it on another controller or is there something wrong?
Try this at home
{% for user in mst_USERS %}
<li>{{user.email}}</li>
{% endfor %}
And in the controller add
return $this->render ( 'default/main.html.twig', array (
'email' => $email,
'mst_USERS' => $mst_USERS->findAll()
));

Key "createdAt" for array with keys "0, 1" does not exist in note/show.html.twig at line 7

I can show my createdAt field of all other tables, except this one in my show view. The code is
{% block body %}
<div class="row">
<div class="col-md-12">
<h1>{{ title }}</h1>
<small>Criado {{ notes.createdAt | date('d/m/Y') }}</small>
{% if notes.updatedAt != notes.createdAt %}
<small>Editado {{ notes.updatedAt | date('d/m/Y') }}</small>
{% endif %}
</div>
</div>
...
showAction
public function showAction($id)
{
return $this->render('note/show.html.twig', array(
'notes' => $this->getDoctrine()->getRepository('CDGBundle:Note')->findAllByBudget($id),
'title' => 'Notas do cliente ' . $id
));
}
The findAllByBudget method was created inside of the repository:
public function findAllByBudget($id)
{
$qb = $this->createQueryBuilder('n');
return $qb
->orderBy('n.id', 'DESC')
->where(
$qb->expr()->eq('n.budget', '?1')
)
->setParameter(1, $id)
->getQuery()
->getResult();
}
Somehow I have problems on displaying from this specific entity only.
You get an array of notes, so in twig template you have to use some loop to display each note. For example:
<div class="col-md-12">
<h1>{{ title }}</h1>
{% for note in notes %}
<small>Criado {{ note.createdAt | date('d/m/Y') }}</small>
{% if note.updatedAt != note.createdAt %}
<small>Editado {{ note.updatedAt | date('d/m/Y') }}</small>
{% endif %}
{% endfor %}
</div>

Form with a collection same entity type

I would want a form for my entity « X ». This entity own a relationship OneToMany with many entities of type « X ». It's a relationship parent <-> children.
When I create my form simply, it works.
class XType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add("name", "text", array("label" => "Nom"))
->add("children", "collection", array(
"type" => new XType(),
"by_reference" => false));
}
}
Then, I would like add easily new entity in my collection with the option « allow_add », and used the prototype to add in javascript. This is my form with the « allow_add » option.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add("name", "text", array("label" => "Nom"))
->add("children", "collection", array(
"type" => new XType(),
"allow_add" => true,
"by_reference" => false));
}
When I execute with or without called the prototype, I have an webserver error. It's XDebug which kick my request because the recursive call is too big. There are cascade call.
What's the best solution to resolve my problem ?
I can't really say where your problem is, but should be somewhere around javascript and the collection prototype. Also, when you allow items to be added, you usually allow to allow_delete too.
Take a look at my example:
$builder->add('book', 'collection', array(
'type' => new BookType(),
'allow_add' => true,
'allow_delete' => true,
'prototype_name' => '__prototype__',
'by_reference' => false,
'error_bubbling' => false
);
To the template where you render form, include this:
{% block javascript %}
{{ parent() }}
{% javascripts
'#ProjectSomeBundle/Resources/public/js/form/collection.js'
%}
<script type="text/javascript" src="{{ asset_url }}"></script>
{% endjavascripts %}
{% endblock %}
And the collection.js file holds this:
$(function($) {
$addButton = $('button.add');
$collection = $addButton.parent().children().first();
$addButton.click(function () {
var prototype = $($collection.data('prototype').replace(/__prototype__/g, function() { return (new Date()).getTime(); }));
prototype.appendTo($collection.children('ul'));
});
$('body').on('click', 'button.remove', function () {
$(this).parent().remove();
});
});
Also, you should be using those customised collection widgets, which you pass to twig. Nothing fancy, it will be rendered as unordered list with items, to make items easily accessible.
config.yml:
twig:
form:
resources:
- 'ProjectSomeBundle:Form:fields.html.twig'
fields.html.twig:
{% extends 'form_div_layout.html.twig' %}
{% block collection_widget %}
{% import "ProjectSomeBundle:Macro:macro.html.twig" as macro %}
{% spaceless %}
<div class="collection">
{% if prototype is defined %}
{% set attr = attr|merge({'data-prototype': block('prototype_widget') }) %}
{% endif %}
<div {{ block('widget_container_attributes') }}>
<ul>
{% for row in form %}
{{ macro.collection_item_widget(row) }}
{% endfor %}
</ul>
{{ form_rest(form) }}
</div>
<div class="clear"></div>
<button type="button" class="add">{% trans %}Add{% endtrans %}</button>
</div>
<div class="clear"></div>
{% endspaceless %}
{% endblock collection_widget %}
{% block prototype_widget %}
{% spaceless %}
{{ macro.collection_item_widget(prototype) }}
{% endspaceless %}
{% endblock prototype_widget %}
You can notice it uses macro, so here it is:
macro.html.twig
{% macro collection_item_widget(fields) %}
<li>
{% set fieldNum = 1 %}
{% for field in fields %}
<div class="field_{{ fieldNum }}">
{{ form_label(field) }}
{{ form_errors(field) }}
{{ form_widget(field) }}
</div>
{% set fieldNum = fieldNum + 1 %}
{% endfor %}
<button type="button" class="remove">{% trans %}Delete{% endtrans %}</button>
<div class="clear"></div>
</li>
{% endmacro %}
This is a full example, I hope you find it useful and works for you.
I ran into the same issue (my web server crashes, as well, due to too many recursive calls). My quick workaround was to simply create a dummy (cloned) type that doesn't contain the recursive field (this works for me since I was interested only into the 1st level children).
So, if this scenario is applicable to you, as well, you could change your code as follows:
class XType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add("name", "text", array("label" => "Nom"))
->add("children", "collection", array(
"type" => new XTypeWithoutChildren(),
"by_reference" => false));
}
}
class XTypeWithoutChildren extends XType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add("name", "text", array("label" => "Nom"));
}
}

Access collection field in twig

How can I access a field in collection in twig
$builder
->add('name', 'text', array('required' => false))
->add('email', 'collection', array(
'type' => new UsersEmailAddressesType(),
'allow_add' => true
))
UserEmailAddressesType has two fields name and email, how can I access email field in twig ?
In the symfony cookbook there is an example on how to embed collections in forms. The solution there looks like this (adapted to your form example):
<ul>
{% for email in form.email %}
<li>{{ form_row(email.address) }}</li>
{% endfor %}
</ul>
Since you want to place the inputs next to each other you might want to check whether the loop.index is odd, even or divisibleby() for example like this:
{% for email in form.email %}
{% if loop.index is odd %}
<li class="float-left">
{% else %}
<li class="float-right">
{% endif %}
{{ form_row(email.address) }}</li>
{% endfor %}

Resources