Update entities fields with data from other entity symfony2 - php

I have two tables in database - orders and trucks. They have relation ManyToOne. When I receive order - truck field is null by default. Trucks table have preconfig data. So my task: for every order entity which I restore with findAll() method and send to twig (render as table) make checkbox, so I can appoint truck to every order.
Here is form which appoint truck to order:
class TruckType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'entity', array(
'class' => 'AppBundle:Trucks',
'choice_label' => 'name',
'label' => false,
'multiple' => false,
'required' => false,
));
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Orders',
));
}
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName()
{
return 'TruckType';
}
}
And twig:
{% for order in orders %}
<tr>
<td width="30%">{{ order.name }}</td>
<td width="30%">{{ order.delivery }}</td>
<td width="15%">{{ order.stock }}</td>
<td width="15%">{{ form_widget(truckform) }}</td>
</tr>
{% endfor %}
But this render checkbox only for first entity in table. Where I am wrong?

You did not show the code for how you generate your truckform variable but I guess you just instantiate a form using your TruckType form type. The problem with this approach is that Symfony will not render a form or a form field more than once, so that your {{ form_widget(truckform) }} fragment is only rendered the first loop iteration. If you think about it, it makes sense, otherwise you will have a number of form fields all with the same name and id and when you submitted your form, there will be no way to differentiate them. You need to take a different approach, using embedded forms. Take a look at this Symfony doc page which will point you in the right direction: How to Embed a Collection of Forms

Related

simple_array handling with SonataAdminBundle

My entity has a property from type simple_array, storing a list of strings which are generated by the user (so choice does not apply).
The relevant part from the entity:
/**
* #var array
*
* #ORM\Column(type="simple_array")
*/
private $tags;
I would like to use the SonataAdminBundle to show, create and edit the entity with the tags present:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('tags', 'collection');
}
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->add('tags', 'array');
}
The list works, but shows [0 => Tag1, 1 => Tag2] where I'd rather show Tag1, Tag2. The create and edit does not work at all, showing nothing where the input field for the tags should be.
To be clear: Tags are not a related entity, they are simply an array of strings!
For add/edit your tags I recommend this general solution How to add an array (customisable) to a symfony2 form (with sonata Admin)?
For customization of array values (by defaults) in list mode as you need, just overwrites the list_array.html.twig template from SonataAdminBundle, to something like this:
{% extends admin.getTemplate('base_list_field') %}
{% block field %}
{{ value|join(', ') }}
{% endblock %}

Assign filtered list of entities to Entity field in Symfony2 form

I have a little problem in my Symfony form.
This is my code:
class ProfileFormType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('adress',null,array('label' => 'form.adress', 'translation_domain' => 'FOSUserBundle'))
->add('niveau','entity',array(
'class'=>'EnsajAdministrationBundle:Niveau',
'property'=>'libelle'
,'multiple'=>false)
)
The problem is that normally it returns all rows for the named Entity, but I want to return just the 2 first rows from the "niveau" ("level") table, to be used as the choices for my form.
What is the solution for this problem?
You have (at least) a couple of options here, but the obvious one is to supply a QueryBuilder to the field which provides the required rows (see Symfony docs on EntityType Field)
E.g.
//Create function which accepts EntityRepository and returns required QueryBuilder
$qbFunction = function(EntityRepository $er) {
return $er->createQueryBuilder('n')
//->orderBy() //If you need to, to get the correct 2 rows!
->setMaxResults(2); //Just two rows
};
$builder->add('adress',null,array('label' => 'form.adress', 'translation_domain' => 'FOSUserBundle'))
->add('niveau','entity',array(
'class'=>'EnsajAdministrationBundle:Niveau',
'property'=>'libelle'
,'multiple'=>false
,'query_builder' => $qbFunction) //give function to field
)
You can make the query more complex if you need to, e.g. add joins

symfony custom form field type error when adding child field

I have an entity Nace that holds hierarchical data. It is mapped as a many-to one association to an entity Organisation.
class Organisation
{
/**
* #ORM\ManyToOne(targetEntity="Pftp\UserBundle\Entity\Nace")
* #ORM\JoinColumn(name="nace_id", referencedColumnName="id")
*/
private $nace;
}
The following form renders the nace property as a drop-down with all records in Nace as expected (showing my starting point).
class OrganisationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('nace')
;
}
}
As Nace contains several hundreds of records, I want to implement a custom FieldType
which adds a second entity choice field with higher level options from the same table (categories)
which populates the main choice field via ajax when the user selects a category
When I add the naceCategory child field and try to render the form, I get the an error related to data mapping.
In order to figure the data flow, I added a ModelTransformer but the methods transform and reverseTransform are never called. Here is my code:
Template
{% block nace_widget %}
{{ form_widget(form) }}
{{ form_widget(form.naceCategory) }}
{% endblock %}
NaceType
class NaceType extends AbstractType
{
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'compound' => true,
'mapped' => true,
'required' => true,
'class' => 'Pftp\UserBundle\Entity\Nace',
'query_builder' => function(NaceRepository $er) {
return $er->createQueryBuilder('node')->where('1=0');
},
));
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add($builder->create('naceCategory', 'entity', array(
'mapped' => false,
'required' => false,
'class' => 'Pftp\UserBundle\Entity\Nace',
'query_builder' => function(NaceRepository $er) {
return $er->getCategoriesQueryBuilder();
}
)))
->addModelTransformer(new NaceTransformer())
;
}
public function getParent()
{
return 'entity';
}
public function getName()
{
return 'nace';
}
}
Error
Expected argument of type "object, array or empty", "string" given
at PropertyPathMapper ->mapDataToForms ('', object(RecursiveIteratorIterator))
in W:\Symfony2\Sources\pftpprod\vendor\symfony\symfony\src\Symfony\Component\Form\Form.php at line 385 +
at Form ->setData (null)
in W:\Symfony2\Sources\pftpprod\vendor\symfony\symfony\src\Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper.php at line 57 +
at PropertyPathMapper ->mapDataToF...
Analogy
Let me try and give you a better idea of what I'm trying to achieve as this Nace thing is pretty unknown.
Basically, I need 2 cascading drop-downs. Imagine you have a list of all the cities of the world in one table and you want the user to choose only 1. As the list is too long, you would want the user to first choose a country from another drop-down (not mapped with your target entity), which should populate your city drop-down with a limited list of cities.
Well, in my case nace corresponds to the city drop-down (initially empty), and naceCategory corresponds to the country drop-down (always populated with the repo method getCategoriesQueryBuilder()). The only difference to the city/country exmaple is, that both drop-downs are hydrated from the same table/entity (Nace), just with values from different hierachy levels.
Does anybody know what I'm missing here?

Filtering which items to show up in collection field

I have a form using this class type:
class DespesasContainerType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('despesas', 'collection', array(
'type' => new DespesasFamiliasType(),
'by_reference' => false,
))
;
}
// ...
}
This way it shows all items in the despesas attribute of the object.
Is there a way to filter which items to use? Something similar to the query_builder option on the entity field type.
No way from FormTypeInterface, but you can filter this collection before passing it to the Form.
Another tricky tip :
Define a public getter like getFilteredDespeas on your Entity that returns the filtered list of despeas. In your Form, just call the field filteredDespeas instead of despeas. This involves that you specifically manage the form binding, by adding a public setFilteredDespeas to your entity, or any other way...

Symfony 2 Form with select list

How can i create a select list with values from a database table in Symfony 2?
I have 2 entities: Student and Classroom with a ManyToOne relationship and i need to create a form with the folowing fields: name, surname, age, classroom(select list from available classes).
In my Student Form i have
$builder
->add('name')
->add('surname')
->add('age')
->add('classroom', new ClassroomType())
;
In my Classroom Form i have this:
$classrooms =$this->getDoctrine()->getRepository('UdoCatalogBundle:Classroom')->findAll();
$builder
->add('clasa','choice',array('choices' => array($classrooms->getId() => $classrooms->getName())));
I get this following error:
Fatal error: Call to undefined method Udo\CatalogBundle\Form\ClassroomType::getDoctrine() in /var/www/html/pos/src/Udo/CatalogBundle/Form/ClassroomType.php on line 13
Kind Regards,
Cearnau Dan
Not sure if you found an answer yet but I just had to do some digging around to figure this out for my own project.
The form class isn't set up to use Doctrine like the controller is so you can't reference the Entity the same way. What you want to do is use the entity Field Type which is a special choice Field Type allowing you to load options from a Doctrine entity as you are trying to do.
Ok so long story short. Instead of doing what you are doing to create the choice field, do this:
->add('category', 'entity', array(
'class' => 'VendorWhateverBundle:Category',
'query_builder' => function($repository) { return $repository->createQueryBuilder('p')->orderBy('p.id', 'ASC'); },
'property' => 'name',
))
I'm not sure if you could place the query_builder function into a repository or what, I'm kind of swinging wildly as I go. Up to this point the documentation I linked to above is pretty clear on what to do. I guess the next step is to read up on Doctrine's QueryBuilder.
While you're in there I think you want to drop the bit where you are embedding the Classroom form,
->add('classroom', new ClassroomType())
You probably don't want people creating their own classrooms. Unless you do, then yeah.
If the entities are mapped, this is a clean solution for Symfony 2.8+ or 3+
<?php
namespace My\AppBundle\Form\Type;
use My\AppBundle\Entity\Student;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class StudentType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('surname')
->add('age')
/*
* It will be resolved to EntityType, which acts depending on your doctrine configuration
*/
->add('classroom');
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(['data_class' => Student::class]);
}
}

Categories