Symfony2 & Twig : display all fields and keys - symfony

I have a problem with Symfony2 and Twig: I don't know how to display all fields of my entity which is loaded dynamically. Here is my code (displays nothing!!)
Controller :
public function detailAction($id)
{
$em = $this->container->get('doctrine')->getEntityManager();
$node = 'testEntity'
$Attributes = $em->getRepository('TestBetaBundle:'.$node)->findOneById($id);
return $this->container->get('templating')->renderResponse('TestBetaBundle:test:detail.html.twig',
array(
'attributes' => $Attributes
));
}
detail.html.twig :
{% for key in attributes %}
<p>{{ value }} : {{ key }}</p>
{% endfor %}

Don't settle for just the public properties! Get the private/protected as well!
public function detailAction($id){
$em = $this->container->get('doctrine')->getEntityManager();
$node = 'testEntity'
$Attributes = $em->getRepository('TestBetaBundle:'.$node)->findOneById($id);
// Must be a (FQCN) Fully Qualified ClassName !!!
$MetaData = $em->getClassMetadata('Test\Beta\Bundle\Entity\'. $node);
$fields = array();
foreach ($MetaData->fieldNames as $value) {
$fields[$value] = $Attributes->{'get'.ucfirst($value)}();
}
return $this->container
->get('templating')
->renderResponse('TestBetaBundle:test:detail.html.twig',
array(
'attributes' => $fields
));
}

OK. What you are trying to do cannot be done with a Twig for loop over your attributes object. Let me try to explain:
The Twig for loop iterates over an ARRAY of objects, running the inside of the loop for each of the objects in the array. In your case, $attributes is NOT an array, it is an OBJECT which you retrived with your findOneById call. So the for loop finds that this is not an array and does not run the inside of the loop, not even once, that is why you get no output.
The solution proposed by #thecatontheflat does not work either, as it is just the same iteration over an array, only that you have access to both the keys and values of the array, but since $attributes is not an array, nothing is accomplished.
What you need to do is pass the template an array with the properties of the $Attributes object. You can use the php get_object_vars() function for this. Do something like:
$properties = get_object_vars ($Attributes);
return $this->container->get('templating')->renderResponse('TestBetaBundle:test:detail.html.twig',
array(
'attributes' => $Attributes
'properties' => $properties
));
And in the Twig template:
{% for key, value in properties %}
<p>{{ value }} : {{ key }}</p>
{% endfor %}
Take into account that this will only show the public properties of your object.

For Symfony3
$em = $this->getDoctrine()->getEntityManager();
$MetaData = $em->getClassMetadata('TestBetaBundle:Node');
$fields = $MetaData->getFieldNames();
return $this->render('test/detail.html.twig', array('fields'=>fields));

You should change it to
{% for key, value in attributes %}
<p>{{ value }} : {{ key }}</p>
{% endfor %}

Related

Get subfield in flexible content layout

Seems that I can't get the value out off the field “overview_title” on line 29. which is a subfield of the “overview_layout”.
JSON: https://pastebin.com/BLBb6cjx.
I can get the “overview_layout” field. but its subfields won't return anything. anyone?
What I'm trying to do is to get the values of those 3 custom fields. But I get nothing.
This is what i'm trying in Timber:
$post = new Timber\Post();
$context['post'] = $post;
$context['layout'] = get_field('cancer_type_layout');
$context['overview'] = array (
'title' => get_field('overview_title'),
'text' => get_field('overview_text'),
'image' => get_field('overview_picture')
);
Timber::render('templates/pages/template-cancer.twig', $context);```
When you work with Flexible Content fields in Timber, you mustn’t access subfields by more calls to get_field(). All data of the subfields is already there when you get the data with the name of the Flexible Content field.
$post = new Timber\Post();
$context['post'] = $post;
// Everything you need will be in block.
$context['block'] = $post->meta( 'cancer_type_layout' );
Timber::render( 'templates/pages/template-cancer.twig', $context );
In Twig, you can then access your data directly from the block variable:
{% if 'overview_layout' === block.acf_fc_layout %}
{{ block.overview_title }}
{{ block.overview_text }}
{{ block.overview_picture }}
{% endif %}

How to pass another entity info into form in Symfony2?

What is best practice to include another info in form from another entity?
I have Student Entity, Group Entity, StudentsGroup and Attendance Entity.
Student have id, code, and name.
Group have id and name.
StudentsGroup have id, group_id, and student_id.
Attendance have id, students_group_id, date and status.
Group can have many Student which saved in StudentsGroup. Why I make StudentsGroup? Because actually 1 Group can have some sub groups like SubjectsGroup etc. And Attendance save student information by StudentsGroup Id which same student can have different students_group_id.
Now, the problem is : How to show Student information in collection form of attendance?
All Entity relationship is declared as object, so actually we can access em freely from any entity. But I don't know how to do that in form. Here my form :
<?php
/* Collection Form */
$tanggal = new \DateTime($request->request->get('sifo_adminbundle_studentsgrouping')['tanggal']);
$attendances = new StudentsGrouping();
foreach ($entities as $temp) {
$entity = new Attendance();
$entity = $em->getRepository('SifoAdminBundle:Attendance')->findOneBy(array('studentsGrouping' => $temp, 'date' => $tanggal));
if ($entity){
$attendances->getAttendances()->add($entity);
}
}
$form = $this->createCollectionForm($attendances, $id, $tanggal);
return $this->render('SifoAdminBundle:DftAbsensi:manage.html.twig', array(
'form' => $form->createView(),
));
This is how I render it in twig :
{{ form_start(form_collection) }}
{{ form_row(form_collection.tanggal) }}
{% for attendance in form_collection.attendances %}
{{ form_row(attendance.status) }}
{% endfor %}
{{ form_end(form_collection) }}
## Concept ##
I'm thinking about creating entity and pass it into form like this :
foreach ($entities as $temp) {
$entity = new Student();
$entity = $em->getRepository('SifoAdminBundle:Student')->find($temp->getId());
if ($entity){
$entities[i] = $entity;
}
$i++
}
and then in twig show it like this :
{{ form_start(form_collection) }}
{{ form_row(form_collection.tanggal) }}
{% for key, attendance in form_collection.attendances %}
{{ entities[key].code }}
{{ entities[key].name }}
{{ form_row(attendance.status) }}
{% endfor %}
{{ form_end(form_collection) }}
But I feel not comfort with this. Am I really need to make new entity just for showing name and code from Student Entity? Is there a best practice to do this?
You can use entity field.
$builder->add('users', 'entity', array(
'class' => 'AcmeHelloBundle:User',
'multiple' => true, /* you can choose more than one */
'mapped' => false, /* if you are using the form with an entity */
'query_builder' => function(EntityRepository $er) {
/* use query builder to get correct results */
return $er->createQueryBuilder('u')->orderBy('u.username', 'ASC');
},
));
There are two important keys in above.
'multiple' => true ----- you can able to choose more than one
'mapped' => false ----- if you are using form with an entity, your form will automatically looks for a connection between these entities and if can not found, throws exception. to avoid of that problem you should set this option to false
http://symfony.com/doc/current/reference/forms/types/entity.html

How to display with datetime condition in controller symfony2

i need to display the list of users where they registred after fixed date for example i need to replay the list of users after 2014-03-01 17:34:04 and the the custom 's type in my table User is datetime.
$user = $em->getRepository('UserUserBundle:user')->findBy();
Here is an example of query to get the users after a chosen datetime (assuming that the field containing the datetime is named datetime):
public function yourControllerAction()
{
$dt = new \Datetime('2014-03-01 17:34:04');
$qb = $this->getDoctrine()
->getRepository('UserUserBundle:user')
->createQueryBuilder('u');
$users = $qb
->where(
$qb->expr()->gte('u.datetime',
$qb->expr()->literal($dt->format('Y-m-d H:i:s'))
)
)
->getQuery()
->getResult()
;
return $this->render(
'UserUserBundle:Default:index.html.twig',
array(
'users' => $users
)
);
}
I don't know if it's the best way by calling literal() but it works for me.
Then you'll have to display the users in your Twig template:
{% for user in users %}
{% user.id %}
...
{% endfor %}

How to get the defined field in sonataadmin query builder?

There is the following code
$form->with('Item')->add('parent', null, array(
'label' => 'Category',
'required' => true,
'query_builder' =>
function($er) use ($id) {
$qb = $er->createQueryBuilder('p');
if ($id){
$qb->where('p.id <> :id')
->setParameter('id', $id);
}
$qb->orderBy('p.root, p.lft', 'ASC');
return $qb;
}
.........
Result is the entity-objects collection which is given to the string (__toString method).
It return name-field.
But I need get the another field - url.
How to get url value instead the name in the select-list form?
The query_builder type return object => how to change this form that it works likewise query_builder?
I didn't work with SonataAdminBundle forms, but I think that it works absolutely like symfony forms. All that you need here is to add 'class' and 'property' values to your options list:
$form->with('Item')->add('parent', null, array(
'class' => 'Acme\DemoBundle\Entity\Category',
'property' => 'url',
'label' => 'Category',
'required' => true,
'query_builder' =>
function($er) use ($id) {
$qb = $er->createQueryBuilder('p');
if ($id){
$qb->where('p.id <> :id')
->setParameter('id', $id);
}
$qb->orderBy('p.root, p.lft', 'ASC');
return $qb;
}
property - is the name of the field in your entity that will represent your Entity's value instead of calling __toString().
But also... If you need always represent your Entity as URL you can simply override __toString() method in the Entity class to something like that:
public function __toString() {
return $this->url;
}
In my case, ->orderBy() used in query_builder worked, but was overwritten for unknown reasons "somewhere" later. Fun fact: when I used extended => true, everything was rendered like sorted in the query_builder. But by using extended => false my <option>s are re-sorted before select2 touched it.
As a workaround I did this:
config/packages/twig.yaml
twig:
paths:
'%kernel.project_dir%/templates': '%kernel.project_dir%/templates'
# This is to prevent a infinite loop when extending the parent template
'vendor/sonata-project/admin-bundle/src/Resources/views': SonataAdminBundleOriginal
And then I done the sorting I wanted again in twig for the project entity:
templates/bundles/SonataAdminBundle/Form/form_admin_fields.html.twig:
{% extends '#SonataAdminBundleOriginal/Form/form_admin_fields.html.twig' %}
{%- block choice_widget_options -%}
{% if name == 'project' %}
{% set options = options|sort((a, b) => a.data.numberSortable <=> b.data.numberSortable)|reverse %}
{% endif %}
{{ parent() }}
{%- endblock choice_widget_options -%}
Just in case if someone needs to "filter" an entity by a FK (foreign key) just like i needed (and searched for 3 days), here is the solution:
In the __construct you can set/find what you need. In my case i work this "sessions" (year). So i find the session->status=true:
$this->sessionActive = $this->sessionRepository->findOneBy(['status'=>true]);
Then in the QueryBuilder:
protected function configureQuery(ProxyQueryInterface $query): ProxyQueryInterface
{
$rootAlias = current($query->getRootAliases());
$query
->select($rootAlias)
->where($rootAlias.'.session = :id')
->addOrderBy($rootAlias.'.dateStart', 'ASC')
->setParameter('id', $this->sessionActive->getId());
return $query;
}
Note: I have always one Session->status set to "true". If you might have null values don't forget to make a condition so that it doesn't give you an error!
Regards.

Symfony QueryBuilder count request returns "array"

I'm trying to make a count request on an id field.
I have the following code in my controller:
$qb = $em->createQueryBuilder();
$qb->select('count(c.id)')
->from('MyBundle:Category', 'c')
->where('c.author = :aut')
->setParameter('aut', $author);
$result = $qb->getQuery()->getResult();
return $this->render('MyCategoryBundle:Category:categories.html.twig', array(
'categories' => $categories,
'result' => $result
));
And in my view.html.twig :
{% for category in categories %}
<li>
{{ category.title }}
{% for total in result %}
{{ total }}
{% endfor %}
</li>
{% endfor %}
It returns the category title and the string "Array" just besides. What am I doing wrong ?
The getResult() returns an array (collection) of objects. You have to use the getSingleScalarResult() function in order to get the result as a simple number.
Anyway, what is the goal of your code? If you want to display the number of categories for each author, your code may not work since you display a list of categories but you only count the categories from one author.
Try this:
$qb = $em->createQueryBuilder();
$qb->select('count(c.id) AS cnt')
->from('MyBundle:Category', 'c')
->where('c.author = :aut')
->setParameter('aut', $author);
$result = $qb->getQuery()->getResult();
and then in twig {{result.cnt}}

Resources