Nested CollectionType Save Entity in ArrayCollection - php

i want to store some data
class Offer
{
/**
* #ORM\Column(type="array")
*/
private $meterPoints;
public function __construct()
{
$this->meterPoints = new ArrayCollection();
}
}
for an offer as a CollectionType.
class OfferType extends AbstractType
{
$builder
->add('meterPoints', CollectionType::class, array(
'entry_type' => OfferMeterPointType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'prototype_name' => '__mp_name__',
))
}
In the OfferMeterPointType I also have an EntityType
class OfferMeterPointType extends AbstractType
{
$builder
->add('meterPoint', EntityType::class, array(
'attr' => array(
'class' => 'chosen-select'
),
'class' => 'AppBundle:MeterPoint',
'choice_label' => 'meterPoint',
))
->add('billData', CollectionType::class, array(
'label' => false,
'entry_type' => OfferBillType::class,
'allow_add' => true,
'allow_delete' => true,
'entry_options' => array(
'label' => false
)
));
}
Now when I persist that entity the whole AppBundle:MeterPoint object get serialized and not just the id. I kind of understand why doctrine does that but can I change it such that just the id will be stored?
Also when I want to edit an Offer
$offer = $em->getRepository('AppBundle:Offer')->findOneById(2);
$form = $this->createForm(OfferType::class, $offer);
i get an Exception
Entities passed to the choice field must be managed. Maybe persist them in the entity manager?
I guess a solution would be to create an Entity for the OfferMeterPointType but I don't really want to do that. Because I allmost never need that data.
Update
I tried like martin suggested. now the exception is gone but it still saves the complete object
$meterPoints = $this->em->getRepository('AppBundle:MeterPoint')->findAll();
//dump($meterPoints);
$builder
->add('meterPoint', ChoiceType::class, array(
'label' => 'offerMeterPoint.meterPoint',
'attr' => array(
'class' => 'chosen-selesct',
'placeholder' => 'ob.to'
),
'choices' => $meterPoints,
'choice_label' => function($meterPoint) {
return $meterPoint->getMeterPoint();
},
'choice_value' => function($meterPoint) {
if($meterPoint === null){
return null;
}
dump($meterPoint);
return $meterPoint->getId();
},
'placeholder' => 'global.plz_select'
))
Update 2
Got it working
changed the ChoiceType
$meterPoints = $this->em->getRepository('AppBundle:MeterPoint')->findAll();
$mps = array();
foreach($meterPoints as $mp){
$mps [$mp->getMeterPoint()] = $mp->getId();
}
//dump($meterPoints);
$builder
->add('meterPoint', ChoiceType::class, array(
'label' => 'offerMeterPoint.meterPoint',
'attr' => array(
'class' => 'chosen-selesct',
'placeholder' => 'ob.to'
),
'choices' => $mps,
'placeholder' => 'global.plz_select'
))

You get a object serialized because your column type is array and EntityType automatically replaces choice values with objects.
There's however choice_value that accepts also a callable so I'd try fiddling with it and maybe you can get it to return just the id (maybe force string type?).
If this doesn't help then probably use just ChoiceType and handle the logic yourself.
This happens because Doctrine automatically deserializes the objects from $meterPoints that you try to use as entities with EntityType. These objects are obviously not managed by the Doctrine Entity manager. Thus the error.
I think you'll have to convert the $meterPoints to database entities before using $this->createForm(...) yourselves if you want to avoid creating more relations. Eventually and maybe even easier approach would be writing a custom Doctrine type that could do this for you:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/custom-mapping-types.html

Related

Symfony 4 map disabling not working

I'm trying to put two different entities (employee and contractor) in one selectbox (EntityType). So I created an unmapped entity called Receiver that puts all the loaded entities in one collection.
When debugging everything goes well, but as soon as it creates the form it gives me the following exception:
Class "App\Receiver\Receiver" seems not to be a managed Doctrine entity. Did you forget to map it?
And it indeed is not a managed Doctrine entity because it should only exist in the code. So in my type I've added the mapped => false option, however it still gives me that same exception.
Here is some code:
OrderController.php where the overall form is being built and a collection type is made
->add('orderNotes', CollectionType::class, [
'entry_type' => NotesType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'by_reference' => false,
'required' => false,
'label' => false,
'mapped' => false
])
And here is the NotesType Form
public function buildForm(FormBuilderInterface $builder, array $options)
{
$options['mapped'] = false;
$data = array_merge($data, Receiver::loadData($this->entityManager->getRepository("App:Contractor")->findAll(), "name", "id"));
$data = array_merge($data, Receiver::loadData($this->entityManager->getRepository("App:Employee")->findAll(), "name", "id"));
$builder
->add('body', TextareaType::class, ['attr' => ['class' => 'form-control']])
->add('receiver', EntityType::class, [
'class' => Receiver::class,
'data' => $data,
'choice_label' => 'name',
'choice_value' => "value",
'placeholder' => '- Selecteer -',
'required' => false,
'mapped' => false,
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => WorkorderNote::class,
'mapped' => false,
]);
parent::configureOptions($resolver);
}
So I have changed mapped to false about everywhere I know. So if you could please help me with this weird problem I would be very glad.
Kind regards

Symfony 3 - static CollectionType children not showing up

I am working on a form in Symfony 3.1.3 and want to add a dynamic amount of checkboxes using CollectionType. In the buildForm-method of my Type-class I am using this code to add the Checkboxes:
$builder->add('levels', CollectionType::class, array(
'entry_type' => CheckboxType::class,
'mapped' => false,
));
foreach($levels as $level) {
$name = 'level_cb_'.$level['name'];
$builder->get('levels')->add($name, CheckboxType::class, array(
'label' => $level['name'],
'required' => false,
'mapped' => false,
));
}
If I call var_dump($builder->get('levels')); immediately afterwards the checkboxes show up in the children and unresolvedChildren properties of the CollectionType. Later I call {{ dump(form.levels) }} in the associated template and it shows me that the children property is empty.
Am I missing something obvious?
So it seems that the children of the collection get cleared somewhere between being added in my custom Type and the form being made available in the Controller.
I put the code to add the checkboxes into the controller and suddenly everything worked as expected. Maybe someone knows the reason behind that.
So in my SpecialType.php I just have:
$builder->add('levels', CollectionType::class, array(
'entry_type' => CheckboxType::class,
'required' => false,
'mapped' => false,
));
And in my SpecialFormController.php I have:
$form = $this->createForm(SpecialType::class, $entity);
foreach($levels as $level) {
$name = 'level_cb_'.$level['name'];
$form->get('levels')->add($name, CheckboxType::class, array(
'label' => $level['name'],
'required' => false,
'mapped' => false,
));
}

Symfony2 Form field Entity with 170k of results

I have a form with a field of relationship entity.
The problem is that that entity tien a lot of records, over 170,000 and render the view form the server is saturated and no load.
What solutions are there to this?
This is the form field
->add('stream', 'genemu_jqueryselect2_entity', array(
'class' => 'AcmeBundle:Stream',
'property' => 'name',
'choice_label' => 'name',
'multiple' => false,
'required' => false,
'configs' => array(
'multiple' => false,
)
)
)
IMPORTANT
I found something.
Stream entity is related to another entity under a bidirectional one-to-one.
Doctrine is running a query for each record to grab the data from that relationship.
Is there any way to tell Doctrine to not spread relationships and take "real" data Stream entity?
If I correctly understand you, you shoud look to query_builder options what allow you to fetch Streams what sutisfy some condition. E.g.:
->add('stream', 'genemu_jqueryselect2_entity', array(
'class' => 'AcmeBundle:Stream',
'property' => 'name',
'choice_label' => 'name',
'multiple' => false,
'required' => false,
'configs' => array(
'multiple' => false,
)
'query_builder' => function (StreamRepository $repository) {
return $repository->findStreamsWhatSatisfySomeCondition();
}
)
you can use external parameters like:
'query_builder' => function (StreamRepository $repository) use ($param) {
}
Detailed info you can find in doc. Hope that will help find solution :)

Accessing collection form field from controller in Symfony2

I am building a form that is rendered from two different Type classes in Symfony2 (using the collection type for the second Type) and I am having trouble accessing data from the collection field in the controller. Here is the code for the outer formBuilders method:
// ...
class EmployeeCreateType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// ...
->add('positions', 'collection', array(
'type' => new PositionCreateType(),
'label' => ' ',
'allow_add' => false,
'prototype' => false,
));
}
// ...
and here is the code for the inner buildForm method from PositionCreateType:
// ...
class PositionCreateType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', 'choice', array(
'label' => 'Title: ',
'choices' => array(
'Senior Engineer',
'Staff',
'Engineer',
'Senior Staff',
'Assistant Engineer',
'Technique Leader',
),
'expanded' => true,
'multiple' => false,
))
->add('department', 'choice', array(
'label' => 'Department: ',
'choices' => array(
'd001' => 'Marketing',
'd002' => 'Finance',
'd003' => 'Human Resources',
'd004' => 'Production',
'd005' => 'Development',
'd006' => 'Quality Management',
'd007' => 'Sales',
'd008' => 'Research',
'd009' => 'Customer Service',
),
'expanded' => true,
'multiple' => false,
));
}
// ...
I would like to access the department field from my controller, but I can't figure out how to do it. I've tried doing something like
$form->get('positions')->get('department')->getData();
but it is not working.
I figured out the solution. Because a collection is an ArrayCollection, you have to access the element of the collection that corresponds to the object you want to access by providing the correct index. Because there was only one item in this collection (a separate form type), the following statement did the trick:
$form->get('positions')->getData()->get('0')->getDepartment();
In other words,
$form->get('positions')->getData()->get('0')
returns the entity (Position) corresponding to my separate form type, PositionCreateType().

add more than one property in a form symfony2

I have a form type where I will add an entity and add more than one attribute
$builder ->add('number', 'entity', array(
'class' => 'TelnOperatorBundle:Numberrange',
'property' => 'De'
'multiple' => false,));
In the property I want to add another field ie
$builder ->add('number', 'entity', array(
'class' => 'TelnOperatorBundle:Numberrange',
'property' => 'De','A'
'multiple' => false,));
How could I do it?
->add('subnumbers', 'collection', array('type' => new SubnumberType(),
'allow_add' => true,
'allow_delete' => true))
You can't, property only allows a string as a parameter: http://symfony.com/doc/master/reference/forms/types/entity.html#property
The solution in your case would be to leave the property blank and then implement the __toString() method in your Entity.
First change the way you define your form type (pass a blank value to property):
$builder ->add('number', 'entity', array(
'class' => 'TelnOperatorBundle:Numberrange',
'multiple' => false,));
Second, define the __toString() function in your TelnOperatorBundle:Numberrange entity:
public function __toString()
{
return $this->De . ' : ' . $this->A;
}

Categories