How to retrieve an array of entities from the reques object? - php

I have an entity field type in my form, but then when I try to get the values from the controller I get an error.
This is my form builder
$builder
->add('recursos', 'entity', array(
'class' => 'SIGIConvocatoriasBundle:Recurso',
'property' => 'nombre',
'multiple' => true,
'mapped' => false
))
->add('requisitos', 'entity', array(
'class' => 'SIGIConvocatoriasBundle:Requisito',
'property' => 'nombre',
'multiple' => true,
'mapped' => false
))
;
and this is my controller
$entity = new Convocatoria();
$form = $this->createForm(new ConvocatoriaType(), $entity);
$form->bind($request);
$recursos = $request->request->get('recursos');
foreach ($recursos as $recurso)
{
//Do something ...
}
But I get an error here
Invalid argument in foreach ...
Like if the $recursos variable is empty or something, and I get a 'recursos' => null in the symfony exception.
I'd really appreciate some help here :D

The request itself contains raw data (scalars).
When you bind the request to the form, it will transform this raw data to normalized data.
The array of ids will be transformed to an array of entities, and then be passed to $entity->setRecursos(); // or each one to $entity->addRecurso();
$form = $this->createForm(new ConvocatoriaType(), $entity)
$form->bind($request);
$formData = $request->request->get($form->getName());
$formData['recursos']; // should be an array of ids
$entity->getRecursos(); // array of entities

Try
$entity = new Convocatoria();
$form = $this->createForm(new ConvocatoriaType(), $entity);
$form->bind($request);
foreach ($entity->getRecursos() as $recurse) {
//do something
}
$em = $this->getDoctrine()->getEntityManager();
$em->persist($entity);
$em->flush();

Related

Form sending OneToMany to Database fails (Symfony2 / Doctrine)

I have a form that uploads a file and I am trying to "attach" the correct job id/entity to it, but it seems I don't fully understand the concept of table relations:
My File class
/**
* #ORM\ManyToOne(targetEntity="Job", inversedBy="file")
*/
protected $job;
My Job class:
/**
* #ORM\OneToMany(targetEntity="File", mappedBy="job")
*/
protected $file;
public function __construct()
{
$this->file = new ArrayCollection();
}
I am submitting the form and entering everything into a database:
$em = $this->getDoctrine()->getManager();
$file = new File();
$form = $this->createFormBuilder($file)
->add('file')
->add('job','text')
->add('save', 'submit', array('label' => 'Create Task'))
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
$job = $em->getRepository("AppBundle:Job")->find($form->getData()->getJob());
$file->setFile($form->getData()->getFile());
$file->setPath($form->getData()->getPath());
$file->setJob($job);
$em->persist($file);
$em->flush();
return $this->redirectToRoute("pendingJobs");
}
Submitting the form ends in a fatal error:
Catchable Fatal Error: Argument 1 passed to AppBundle\Entity\File::setJob() must be an instance of AppBundle\Entity\Job, string given, called in /var/www/html/web2gdv/vendor/symfony/symfony/src/Symfony/Component/PropertyAccess/PropertyAccessor.php on line 410 and defined
I tried debugging what was send with
if ($form->isValid()) {
dump($form->getData());
die();
}
but it does even get to the point?!
What am I doing wrong?
Any hint appreciated!
UPDATE
Thanks to #julien-bourdic I updated my form like this:
/**
* #Route("/job/pending", name="pendingJobs")
*/
public function jobAction(Request $request)
{
$this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!');
$em = $this->getDoctrine()->getManager();
$file = new File();
$form = $this->createFormBuilder($file)
->add('file')
->add('job','entity',array(
'class' => 'AppBundle:Job',
'choice_label' => 'id',
))
->add('save', 'submit', array('label' => 'Create Task'))
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
$job = $em->getRepository("AppBundle:Job")->find($form->getData()->getJob());
$file->setFile($form->getData()->getFile());
$file->setPath($form->getData()->getPath());
$file->setJob($job);
$em->persist($file);
$em->flush();
return $this->redirectToRoute("pendingJobs");
}
$jobs = $em->getRepository("AppBundle:Job")->findBy(array(
'receipt' => true,
'receiptStatus' => true,
));
return $this->render(
'default/pending.html.twig',
array(
'jobs' => $jobs,
'form' => $form->createView(),
)
);
}
The whole purpose of this class is to have a table where the last button each row is an upload form. How can I populate multiple forms from one class, is that even possible? What yould I have to send to the renderfunction?
Try to explicitely define your field job in your form :
->add('job','entity',array(
'class'=>'AppBundle:Job',
'property'=>'id',
)
The problem is that find() returns array, not a Job. Use findOne().
$job = $em->getRepository("AppBundle:Job")->find($form->getData()->getJob());
// $job is and Array
do instead
$job = $em->getRepository("AppBundle:Job")->findOne($form->getData()->getJob());
// $job is Job
You have add('job', 'text') and must have a entity type, not text
First you need have a 'jobs' in the DB. Then you can change to
$form = $this->createFormBuilder($file)
->add('file')
->add('job','entity', array('class' => 'YourBundle:Job'))
->add('save', 'submit', array('label' => 'Create Task'))
->getForm();
or short
$form = $this->createFormBuilder($file)
->add('file')
->add('job')
->add('save', 'submit', array('label' => 'Create Task'))
->getForm();
you will receive select box on the job-field

Symfony 2.3 handleRequest($request) doesn't set entity

I have contact Entity, making post call using:
postContactAction(Request $request)
Generated form using app/console generate:doctrine:form BundleName:Contact
In post function trying to get request and set entity to request parameters like name, email and etc:
$contact = new Contact();
$form = $this->createForm(new ContactType(), $contact, array(
'method' => 'POST'));
$form->handleRequest($request);
And while checking, var_dump($contact); returns fields with null value.
What can be the problem?
Using postman to send post request and it worked without form.
In ContactType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text')
->add('email', 'text', array('required' => false))
->add('phone', 'integer', array('required' => false))
->add('text', 'textarea')
->add('subject', 'text')
->add('createdAt', 'datetime', array('required' => false))
;
}
In ContactController:
public function postContactAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$this->initErrorContainer();
$validator = $this->get('validator');
$contactDetails = $this->getRequest()->request->all();
// check if email and phone exists or not. One is enough
if (!array_key_exists('email', $contactDetails) && !array_key_exists('phone', $contactDetails)) {
$this->errorContainer->createAndAdd('email', $this->errorContainer->MESSAGE_REQUIRED);
$this->errorContainer->createAndAdd('phone', $this->errorContainer->MESSAGE_REQUIRED);
return $this->getView();
}
$contact = new Contact();
// handle form
$form = $this->createForm(new ContactType(), $contact, array(
'method' => 'POST'));
$form->handleRequest($request);
// set default values
var_dump($contact);
die;
Solved. As Entity uses different types than request, you need to create simply model of this entity, set request fields to that entity type using handleRequest, and then you can use it.
Is weird, but can you try to get the form after call createForm to see if that has something related, namely:
you have:
$form = $this->createForm(new ContactType(), $contact, array('method' => 'POST'));
Then just add:
$form = $this->createForm(new ContactType(), $contact, array('method' => 'POST'))->getForm();

Form page after Form page

I am having a problem in my symfony 2 project regarding the use of form (forms without classes). The idea is to develop a sequence of forms (each one in an independent page). Similar to multistep form or wizard but exactly not the same. In each form, partial sent results are saved and a new form is called.
Currently I have a controller with a form like this:
public function form1Action(Request $request, $parameter){
//Get relevant data using the $parameter...
$defaultData = array('message' => 'Type your message here');
$formBuilder = $this->createFormBuilder($defaultData);
$formBuilder->add('sendreport', 'choice', array(
'choices' => array('yes' => 'Yes', 'no' => 'No'),
'expanded' => true,
'label' => 'You will receive a full report from administrator',
'multiple' => false,
));
$formBuilder->add('start', 'submit', array('label' => 'form.labels.start'));
$form = $formBuilder->getForm();
$form->handleRequest($request);
if ($request->getMethod() == 'POST') {
if ($form->isSubmitted() && $form->isValid()){
$data = $form->getData();
return $this->redirect($this->generateUrl('task_form2', array('data' => $data)));
}
return $this->render('MyBundle:Default:showform1.html.twig', array('ourform' => $form->createView()));
}
Then, the redirected page contains a new form with similar structure to the previous one:
public function form2Action(Request $request, $data){
$datasource = $data;
$defaultData = array('message' => 'Type your message here');
$formBuilder = $this->createFormBuilder($defaultData)
->add('name', 'text')
->add('email', 'text')
->add('message', 'textarea')
->add('send', 'submit');
$form = $formBuilder->getForm();
$form->handleRequest($request);
//WHY IS NOT SUBMMITED???
if ($request->getMethod() == 'POST') {
if ($form->isSubmitted() /*&& $form2->isValid()*/) {
$data2 = $form->getData();
$data = //$data = $data2 array + $datasource array...
return $this->redirect($this->generateUrl('task_form3'), array('data' => $data));
}
}
return $this->render('MyBundle:Default:showform2.html.twig', array('ourform' => $form->createView()));
}
But here is the problem, the second form called in 'task_form2' path is not submitted!¿?. When you press the send button nothing happens!.
Any idea?
What is the best way to do this? (I think it is simpler and I would not like to use multistep bundle or something like that).
Thank you in advance.

PUT request not working with Symfony forms and FosRest

I'm trying to write a simple restful controller for user management in Symfony using FosRest and Symfony forms. My application is backed by Amazon DynamoDB, although I don't think it matters.
I have DELETE, GET and POST (new user) all working perfectly.
I've now come to writing the PUT action (edit user) which doesn't seem to work. I've spent ages banging my head against a brick wall and I just can't work it out.
In order to create the PUT, I essentially copied the POST action but modified it to load the old object first.
In the POST, the User object automatically gets populated by the line $form->handleRequest($request);
This doesn't seem to be working in the PUT action, the user object doesn't get populated/modified. I've checked the $_REQUEST array and the data is being submitted. Because of the lack of browser support for PUT, I'm calling the action by doing a POST of the data with the query parameter _method=PUT (which works fine for DELETE, and it is routing to the correct place).
Here is my POST action that works:
public function postUsersAction(Request $request)
{
$user = new User();
$user->setTable($this->getTable());
$formBuilder = $this->createFormBuilder($user, array(
'validation_groups' => array('registration', '')))
->add('username', 'text')
->add('password', 'password')
->setAction($this->generateUrl('post_users'))
->setMethod('POST')
->setAttribute('validation_groups', array('registration'));
$roles = $this->getFlattenedRoles($this->getRoles());
$formBuilder->add('roles', 'choice', array(
'choices' => $roles,
'multiple' => true,
'expanded' => true
));
$form = $formBuilder->add('save', 'submit')->getForm();
$form->handleRequest($request);
if ($form->isValid())
{
$user->save();
$params = array('user' => $user);
$view = $this->view($params, 200)
->setTemplate("MyRestBundle:User:newconfirm.html.twig");
return $this->handleView($view);
}
$params = array('form' => $form, 'user' => $user);
$view = $this->view($params, 400)
->setTemplate("MyRestBundle:User:new.html.twig");
return $this->handleView($view);
}
Here is my PUT controller that doesn't:
public function putUserAction($slug, Request $request)
{
$table = $this->getTable();
$user = $table->load($slug);
$formBuilder = $this->createFormBuilder($user)
->add('password', 'password')
->setAction($this->generateUrl('put_user', array('slug' => $slug, '_method' => 'PUT')))
->setMethod('POST');
$roles = $this->getFlattenedRoles($this->getRoles());
$formBuilder->add('roles', 'choice', array(
'choices' => $roles,
'multiple' => true,
'expanded' => true
));
$form = $formBuilder->add('save', 'submit')->getForm();
$form->handleRequest($request);
if ($form->isValid())
{
$user->save();
$params = array('user' => $user);
$view = $this->view($params, 200)
->setTemplate("MyRestBundle:User:newconfirm.html.twig");
return $this->handleView($view);
}
$params = array('form' => $form, 'user' => $user);
$view = $this->view($params, 400)
->setTemplate("MyRestBundle:User:new.html.twig");
return $this->handleView($view);
}
Any help would be greatly appreciated.
Okay, after some help in the Symfony IRC channel, it turns out the reason this isn't working is this part of the code:
$formBuilder = $this->createFormBuilder($user)
->add('password', 'password')
->setAction($this->generateUrl('put_user', array('slug' => $slug, '_method' => 'PUT')))
->setMethod('POST');
Since PUT doesn't work in many browsers, I was trying to set the method as POST and pass _method=PUT as a query parameter to override the real HTTP method. It turns out there is no need to do this, and Symfony will handle it all for you. The above code is now just:
$formBuilder = $this->createFormBuilder($user)
->add('password', 'password')
->setAction($this->generateUrl('put_user', array('slug' => $slug))
->setMethod('PUT');
By doing this, Symfony actually renders a POST form with a hidden _method field - there's no need to do anything manually.

Symfony2 Extra fields FormError on validating form with hidden field

Here is listing of my form:
$builder = $this->createFormBuilder($project)
->add('name','text')
->add('type','choice', array(
'choices' => $enumtype
))
->add('begindate','date')
->add('expecteddate','date')
->add('events', 'collection', array(
'type' => new EventType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
))
->add('financial', 'file', array(
'property_path' => false,
'required' => false
))
->add('investition', 'file', array(
'property_path' => false,
'required' => false
));
if ($defaults) {
$builder->add('id','hidden',array('data' => $defaults['id'], 'property_path' => false));
$form = $builder->getForm();
$form->setData($defaults);
}
else
$form = $builder->getForm();
When i try to validate this form, i receive FormError object:
Array (
[0] => Symfony\Component\Form\FormError Object (
[messageTemplate:protected] => This form should not contain extra fields.
[messageParameters:protected] => Array (
[{{ extra_fields }}] => id
)
[messagePluralization:protected] =>
)
)
If i exclude "id" field - all works ok.
How can i use hidden type and make validation?
This issue comes from the fact that the hidden parameter is optionnal.
A common mistake is not to set the associated type when submitting the form.
Example of mistake:
public function addOrEditAction($id=null)
{
$request = $this->getRequest();
if (!$id) {
$model = new Actu();
$type = new ActuType(); /* I do not set the default id on submit */
} else {
$em = $this->getDoctrine()->getEntityManager();
$model = $em->getRepository("MyBundle:Actu")
->find($id);
if (!$model) {
return $this->redirect($this->generateUrl('admAddNew'));
} else {
$type = new ActuType($model->getId());
}
}
$form = $this->createForm($type,$model);
if ('POST' == $request->getMethod()) {
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$em->persist($model);
$em->flush();
return $this->redirect($this->generateUrl('admNews'));
}
}
$data = array('form'=>$form->createView());
return $this->render('MyBundle:Page:news-add.html.twig',$data);
}
When calling the controller
ActuType() contains:
'name', 'content', 'date', 'id'
When Submitting the form
ActuType() contains:
'name', 'content', 'date'
They do not match.
This actually returns an error because there's an extra field with hidden id containing the row to edit when submitting the form.
All you need to do is to check the request before initializing FormType
if (!$id && null === $id = $request->request->get('newsType[id]',null,true)) {
With this, you can set the same FormType that you did when asking for the page

Categories