Symfony 2 Create a Entity in another Entiy Form - php

Hi I think there would be a very simple solution for this but I got a little bit stuck here.
I have two entities. An Author and a Poem. As expected one author can write a lot of poems but one poem can only have one author.
Now I have my poem form:
class PoemType extends AbstractType
{
/**
*
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm (FormBuilderInterface $builder, array $options)
{
$builder->add('title')
->add('authorId')
->add('text', 'textarea',
array(
'attr' => array(
'class' => 'tinymce'
)
)
);
}
/**
*
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions (OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'Galerie\PictureBundle\Entity\Poem'
));
}
/**
*
* #return string
*/
public function getName ()
{
return 'galerie_picturebundle_poem';
}
}
So the user can choose an author for the poem. But I want the possibility that the user can add an author from here. So if he enters a new poem and the author doesn't exist he can add it here.
I already found this Allowing new tags with the prototype but in my case there is no collection.
Is this possible ?
thanks for your help in advance ;)

you can embed the author form in your poem form. see the documentation for details
http://symfony.com/doc/master/book/forms.html#embedded-forms

Related

Symfony 2.7 choice callback not working in form

I have a class with a multiple choice property:
...
/**
* #ORM\Column(type="array", name="majority_types")
* #Constraints\Choice(callback="getAvailableMajorityTypes", multiple="true")
*/
private $majorityTypes;
...
public static function getAvailableMajorityTypes()
{
return array(
self::SIMPLE_MAJORITY,
self::UNANIMITY_MAJORITY,
self::THREE_FIFTHS_MAJORITY,
self::ONE_THIRD_MAJORITY,
self::FOUR_FIFTHS_MAJORITY
);
}
...
I also have a form class for this class:
...
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
...
->add('majorityTypes', ChoiceType::class, array(
'multiple' => true,
))
...
->getForm();
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'MyClass',
));
}
But the choices from getAvailableMajorityTypes are not rendered.
I simply followed these steps: http://symfony.com/doc/master/reference/constraints/Choice.html#supplying-the-choices-with-a-callback-function, but for some reason it doesn't work.
Edit:
I see that using static choices as annotations neither works (choices={"foo1", "foo2"}). The only way it works is passing the choices directly in the add method when creating the form. I've not found out the problem yet.
If I refer to your words:
But the choices from getAvailableMajorityTypes are not rendered.
It seems you're confused between rendering of options in your form's select field and the Choice constraint.
You've only implemented the constraint in your code, but you also need to add the options to your select. Like this:
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
...
->add('majorityTypes', ChoiceType::class, array(
'multiple' => true,
'choices' => YourEntity::getAvailableMajorityTypes()
))
I've never used this annotation, however in the documentation the callback is public static:
// src/AppBundle/Entity/Author.php
namespace AppBundle\Entity;
class Author
{
public static function getGenders()
{
return array('male', 'female');
}
}
If you follow the documentation and make your method static as well the annotation should work.

Symfony ManyToMany in Form

I have entity developer and entity skill, skill have ManyToMany with Platforms, Language and Speciality and I need create form for developer, developer can selected skills and when selected some skill developer can selected Platforms, Language and Speciality for this skill. If developer selected two skill or more so have more Platforms, Language and Speciality for selected. And I don't know how this is create in Symfony. Now I create form only selected skills
class DeveloperProfessionalSkillsType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name');
$builder->add('skills','entity',
array(
'class'=>'Artel\ProfileBundle\Entity\Skill',
'property'=>'skill',
'multiple'=>true,
)
);
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Artel\ProfileBundle\Entity\Developer',
'validation_groups' => array('professional_skills')
));
}
/**
* #return string
*/
public function getName()
{
return 'developer_professional_skills';
}
but now I have error form is not valid, interesting when I add 'expanded' => true, all work fine, but I don't need expanded I need simple selected field:
this is my entity
class Skill
{
/**
* #ORM\ManyToMany(targetEntity="Artel\ProfileBundle\Entity\Skill", mappedBy="skills", cascade={"persist"})
*/
protected $developers;
/**
* #var \Artel\ProfileBundle\Entity\CodeDirectoryProgramLanguages
*
* #ORM\ManyToMany(targetEntity="CodeDirectoryProgramLanguages", inversedBy="skills", cascade={"persist"})
*/
protected $language;
/**
* #var \Artel\ProfileBundle\Entity\CodeDirectoryPlatforms
*
* #ORM\ManyToMany(targetEntity="CodeDirectoryPlatforms", inversedBy="skills", cascade={"persist"})
*/
protected $platforms;
/**
* #var \Artel\ProfileBundle\Entity\CodeDirectorySpecialities
*
* #ORM\ManyToMany(targetEntity="CodeDirectorySpecialities", inversedBy="skills", cascade={"persist"})
*/
protected $specialities;
and my action
public function submitProfessionalSkillsAction($securitytoken)
{
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(new DeveloperProfessionalSkillsType(), $user->getDeveloper());
$form->handleRequest($request);
if ($form->isValid()) {
$em->flush();
Recommend, please, how best to solve this problem
Instead of
$builder->add('skills','entity',
array(
'class'=>'Artel\ProfileBundle\Entity\Skill',
'property'=>'skill',
'multiple'=>true,
)
);
You can create new form and add it to your current form like this:
$builder->add('skills', new SkillsType()
);
And in new form you can define all your fields like:
$builder->add('language','entity',
array(
'class'=>'Artel\ProfileBundle\Entity\Language',
'property'=>'some_property',
'multiple'=>true,
)
);
if you need many skills you can use collection form type:
->add('skills', 'collection', array('type' => new SkillsType(),
'allow_add' => true,'by_reference' => false))

Symfony form - how to add some logic while validating

I have a form, used for a course subscription, in which I have 2 entity fields, activite and etudiant. I would like NOT to validate this form IF the trainer i already booked (information that i can find in the DB through the entity activite).
How (where...) can i add some logic instructions to control the validation of this form?
Is anybody has an idea? A lead? It would be so simple WITHOUT Symfony (for me)!...
Thanks
class InscriptionType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('activiteId', 'entity',
array('label'=>'Activité',
'attr'=>array('class'=>'form-control'),
'class'=>'AssoFranceRussie\MainBundle\Entity\Activite',
'property'=>'nomEtNiveauEtJour',
))
->add('etudiantId', 'entity',array('label'=>'Etudiant',
'attr'=>array('class'=>'form-control'),
'class'=>'AssoFranceRussie\MainBundle\Entity\Etudiant',
'property'=>'NomEtPrenom',
))
;
}
You can write your own constraints and validators by extending the Symfony validation classes.
You need to extend Symfony\Component\Validator\Constraint to define the constraint and Symfony\Component\Validator\ConstraintValidator to define the validation code.
There are probably other ways to do this as well, but this gives you complete control of the validation.
You could do what you want in this way:
1- You need a variable to store the EntityManager in your InscriptionType class:
protected $em;
public function __construct($em) {
$this->em = $em;
}
2- Pass the entity manager to the FormType class from your controller as below:
new InscriptionType( $this->getDoctrine()->getManager() );
3- Add the logic what you want in the setDefaultOptions function to specify the validation_groups what you want for the form:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$p = $this->em->getRepository('YourBundle:YourEntity')->find(1);
if($p){
$resolver->setDefaults(array(
'data_class' => 'YourBundle\Entity\YourEntity',
'validation_groups' => array('myValidation1'),
'translation_domain'=>'custom'
));
}
else{
$resolver->setDefaults(array(
'data_class' => 'YourBundle\Entity\YourEntity',
'validation_groups' => array('myValidation2'),
'translation_domain'=>'custom'
));
}
}
4- In your entity, you need to specify the validation groups for the fields of the entity:
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
* #Assert\NotNull(groups={"myValidation1"})
*/
private $name;
/**
* #var date
*
* #ORM\Column(name="start", type="date")
* #Assert\NotNull(groups={"myValidation1", "myValidation2"})
* #Assert\Date()
*/
private $start;
In this case, the field 'start' would be validated in both cases, but the first only with the myValidation1 is the group to be validated.
In this way, you could control which fields you want to validate.

Entity not found on Symfony 2 form

I generated with the smyfony2 cli tool a CRUD for a entity. Now i want to use the edit function from the CRUD.
First, the code
/**
* Displays a form to edit an existing Poi entity.
*
* #Route("/poi/{id}/edit", name="poi_edit", requirements={"id" = "\d+"})
* #Method("GET")
* #Template()
*/
public function editAction($id){
$em = $this->getDoctrine()->getManager('default')->getRepository('Project\Bundle\ProjectBundle\Entity\Poi');
$entity = $em->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Poi entity.');
}
$editForm = $this->createEditForm($entity);
return array(
'entity' => $entity,
'edit_form' => $editForm->createView()
);
}
/**
* Creates a form to edit a Poi entity.
*
* #param Poi $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createEditForm(Poi $entity)
{
$form = $this->createForm(new PoiType(), $entity, array(
'action' => $this->generateUrl('poi_update', array('id' => $entity->getId())),
'method' => 'PUT',
));
$form->add('submit', 'submit', array('label' => 'Update'));
return $form;
}
But i receive a "Entity not found" error. Of course i first of all i thought about the throw of the NotFoundException, so i commented it out, but still i get the error.
Then i debugged the code and the entity will be found. It's also existing in the database.
I debugged further and found out that the error is thrown somewhere in the Symfony2 Form stack which generates the form, which is called in the createEditForm action.
Do i clearly miss something? What is my error?
My Symfony2 dev log also just says that a NotFoundException was thrown, no further information there to be found.
I have another entity with a generated CRUD, but there i build the form in the createEditForm by myself because of certain fields that shouldn't be displayed. Do i need to create the form by myself or am i doing something obviously wrong?
Also the PoiType code
class PoiType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('date')
->add('situation')
->add('description')
->add('isPrivate')
->add('image')
->add('audio')
->add('country')
->add('category')
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Project\Bundle\ProjectBundle\Entity\Poi'
));
}
/**
* #return string
*/
public function getName()
{
return 'project_bundle_projectbundle_poi';
}
}
This is the Error i get:
CRITICAL - Uncaught PHP Exception Doctrine\ORM\EntityNotFoundException: "Entity was not found." at /var/www/project-symfony/vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/ProxyFactory.php line 177
Try adding a backslash prefix to your data_class in your FormType as such:
'data_class' => '\Project\Bundle\ProjectBundle\Entity\Poi',
Thanks for this post.

Symfony2 Form FormType Itself collection

I'm trying to create a symfony 2 form 'PersonType', which has a PersonType collection field that should map a given person's children.
And I'm getting this error,
{"message":"unable to save order","code":400,"errors":["This form should not contain extra fields."]}
Here is my Person entity,
class Person
{
private $id;
/**
* #ORM\OneToMany(targetEntity="Person", mappedBy="parent", cascade={"persist"})
*/
private $children;
/**
* #ORM\ManyToOne(targetEntity="Person", inversedBy="children")
* #ORM\JoinColumn(name="orderitem_id", referencedColumnName="id", nullable=true)
*/
private $parent;
}
And my Type,
class PersonType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id')
->add('children', 'collection', array(
'type' => new PersonType()
))
;
}
UPDATE :
I've seen that the problem was because the option :
'allow_add' => true,
'by_reference' => false
wasn't in the Type, I've deleted it because when i insert them, the form don't appear and the page crash with no error.
I'm very confused because with this error, people can't have children :/
Does anyone already faced the same problem? (A formType nested over itself)
ACUTALLY :
I've duplicate my personType to PersonchildrenType to insert this last in the first...
I was having the same problem except that the error message was :
FatalErrorException: Error: Maximum function nesting level of 'MAX' reached, aborting!
Which is normal because "PersonType" is trying to build a form with a new "PersonType" field that is also trying to build a form with a new "PersonType" field and so on...
So the only way I managed to solve this problem, for the moment, is to proceed in two different steps :
Create the parent
Create a child and "link" it to the parent
You can simply do this in your controller
public function addAction(Person $parent=null){
$person = new Person();
$person->setParent($parent);
$request = $this->getRequest();
$form = $this->createForm(new PersonType(), $person);
if($this->getRequest()->getMethod() == 'POST'){
$form->bind($request);
if ($form->isValid()) {
// some code here
return $this->redirect($this->generateUrl('path_to_person_add', array(
'id' => $person->getId()
); //this redirect allows you to directly add a child to the new created person
}
}
//some code here
return $this->render('YourBundle::yourform.html.twig', array(
'form' => $form->createView()
));
}
I hope this can help you to solve your problem.
Tell me if you don't understand something or if I'm completly wrong ;)
Try to register your form as a service, like described here: http://symfony.com/doc/current/book/forms.html#defining-your-forms-as-services, and modify your form like this:
class PersonType extends AbstractType
{
public function getName()
{
return 'person_form';
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id')
->add('children', 'collection', array(
'type' => 'person_form',
'allow_add' => true,
'by_reference' => false
))
;
}
}

Categories