How to populate a form with a populated Entity in symfony - php

I have an EntityType with an embedded EntityType collection. When I create a form and pass an empty instance of the related object everything works as expected.
However if I populate an object using Doctrine and pass this to the form I get a viewData error.
I have put alot more detail in a previous question and the answer given to this put me on the right path - almost.
It seems using #parameter annotation will fill the blanks in for me.
I would like to understand how I can do this myself in code e.g sudo code:
populatedEntity = Doctrine->getEntity
form = (entityType,populatedEntity)
Doing it this way throws an viewData error. I have set the class_data in the EntityType to that of the Entity
This works:
emptyEntity = new Entity
form = (entityType,emptyEntity)

Related

Symfony4 stop handleRequest() from removing values of my object

I am submitting a form and in my controller I use handleRequest to validate the form.
Lets say I try to update my object name 'object' - It has an id, name and color field.
On the same page I also show a lost with the names of all my objects that I fetch from the database
Here is my code:
$object = self::getObjectById($objectId);
$objects = self::getAllObjects();
$objectForm = self::CreateObjectForm($object);
$objectFormForm->handleRequest($request);
dd($objects);
When I submit the form and I leave the name field open,
It throws an error that the field is required when it reloads the page, the name field of the form is still empty which is normal.
But here is the problem, in the list of objects that is also showing on this page the name of the object I tried to update has no name showing anymore in this list.
I don't know why this is happening since I fetched this list of objects completely separately from the form object. When I dd() the objects after the handleRequest() I cans see in the dumped vars that indeed the name field is empty. When I check the database, the name field is not empty and still holds the old name. Which makes sense because the object is not persisted and flushed to de db.
When I dd() the same list before the handleRequest() everything is normal.
How can I prevent this behavior? And why is this happening?
I don't know why this is happening since i fetched this list of objects completely seperatly from the form object.
It's referencing the same entity which get's dumped in it's current, live, dirty state as submitted by the form.
If you need to render the clean, persisted values then you just need to store them in a variable as a string instead of as the object, and before handling the request.
Try something like this:
$object = self::getObjectById($objectId);
$objects = self::getAllObjects();
$persistedObjects = [];
foreach($objects as $obj){
$persistedObjects[$obj->getId()] = $obj->getName();
}
$objectForm = self::CreateObjectForm($object);
$objectFormForm->handleRequest($request);
dd($persistedObjects);

Symfony2 Validating submitted data against Model class

I'm trying to validate submitted data against existing Model/Entity/POPO, however I can't get it to work in any simple way.
All of this is takes place inside a controller action.
So, I can do like this:
$constraints = new Assert\Collection([
'username' => [new Assert\NotBlank()],
'email' => [new Assert\Email()],
]);
$violationList = $this->get('validator')->validate($request->request->all(), $constraints);
However to do that in every action makes no sense, as having all constraints in a class would be a lot better. So, Validation component allows to do like this:
// All constraints are defined inside Customer class
$customer = new Customer();
$violationList = $this->get('validator')->validate($customer);
Violation list is full of errors now, as $customer is an empty object, but the problem is I can't find a way to use data from POST AND validate it against constraints that are defined in the class.
It is possible to write extra component/helper that would take POST data and then will call bunch of ->setUsername(), ->setEmail(), etc., but that doesn't seem right considering you can easily map Model to POST data, if:
Form component is involved;
OR using ConstraintsCollection manually;
Am I missing something obvious here or there is no out-of-the-box possibility? Thanks!
AFAIK the form component is the one responsible for mapping post data to your entity. So you have two choices
Use a form, like that you will have your data mapped and your model validated
Skip the form but then you have to map request params to your entity manually. then validate your model with $this->get('validator')->validate($customer);
Edit :
The form role is to map data coming from request ( html form , api .... ) to a model. Validation could be done with from or without it as its the validator component who does the job , it should be noted that the validation is done on the model and not the form.
If you want to skip the form check this question: Populate entity from data array without form/request although the form component is very useful specially if you are using the same logic in many places ( create / edit .. )

Symfony2 REST API - Partial update

I'm building a REST API with FOSRestBundle in Symfony2. I'm using forms to create and update entities with Doctrine2. Everything works fine if I send all form fields. Example:
{"first_name":"Pi","last_name":"Wi"}
The person is inserted fine but now I want to update only the last name.
{"last_name":"Wi"}
The problem is that the first name is empty after the update because the form updates the entity with an "null" value (because it isn't given). Is it possible to just update the last name and ignore the first name?
Sure, it's possible.
First, in terms of RESTful that would be a PATCH request, so if you're using the ClassResourceInterface based controller approach, you'll have to add a patchAction method in your controller.
Then, when processing a submitted form, you'll need to pass a false $clearMissing option to your form's submit method call in the controller, like this:
<?php
// in your controller's patchAction:
/** #var \Symfony\Component\Form\FormInterface $form */
/** #var \Symfony\Component\HttpFoundation\Request $request */
$form->submit($request, false);
This will tell the form component to only update the fields passed from the form, without clearing the missing fields (as the parameter's name says). See the source code for reference.
Note though, that passing a Request to a FormInterface::submit() method will be deprecated as of Symfony 3.0, so this answer is for Symfony 2.x.

How can I get the form data from the FOSUserBundle registration form?

I am using the FOSUserBundle and have overwritten the RegistrationController. When the form is submitted and valid, I want to get the email address the user entered in the registration form.
But I don't see any way to get it. As taken from the Symfony2 forms documentation, you can get form data like this:
$this->get('request')->request->get('name');
But the RegistrationController does not know the get() method (as it's not inherited from the Symfony2 controller entity). So I could go like this:
// Note the ...->container->...
$this->container->get('request')->request->get('name');
But this returns NULL. Now I try to get it from the $form.
// Does contain a lot of stuff, but not the entered email address
$form->get('email');
// Does also contain a lot of stuff, but not the desired content
$request->get('email');
$request->request('email');
// Throws error message: No method getData()
$request->getData();
Any idea?
It's really, really simple. You create a form with related entity. In FOSUserBundle you should have a RegistrationFormHandler, and in process method you've got:
$user = $this->createUser();
$this->form->setData($user);
if ('POST' === $this->request->getMethod()) {
$this->form->bind($this->request);
if ($this->form->isValid()) /**(...)**/
After the line $this->form->bind($this->request) every value in $user object is overwritten by data from form. So you can use $user->getEmail().
On the other hand you are able to get data directly from request, but not by the property name, but by form name. In FOSUserBundle registration form it is called fos_user_registration - you can find it in FOS/UserBundle/Form/Type/RegistrationFormType.php in getName method.
You get it by:
$registrationArray = $request->get('fos_user_registration');
$email = $registrationArray['email'];
If you were to use Controller as a Service (which should work with this), you could pass the RequestStack (sf >=2.4) in the constructor and do $this->request_stack->getCurrentRequest()->get();
My guess is that you are trying to get the POST data. You are trying to put the data in a form object I presume. I would recommend you to take a look at: http://symfony.com/doc/current/book/forms.html if you have a custom form.
As regarding to your question, the form is probably containing a name. If you want to have direct access to it instead of doing things in your form, you need to fetch it multilevel if directly via the true at $deep, get('registration_form_name[email]', null, true); You can also do $email = $request->get('registration_form_name')['email']; (if you have php 5.4+)

Processing Zend_Form dynamically generated elements

I need to create a form where the elements (texbox, select, ..) will be dynamically inserted. Right now I have created a empty Form file with just a hidden element and them in my controller I go inserting elements according to certain conditions.
My form file:
class Form_Questions extends Zend_Form {
public function __construct() {
parent::__construct($options);
$this->setName('Questions');
// Hidden Label for error output
$hiddenlabel = new Zend_Form_Element_Hidden('hiddenlabel');
$hiddenlabel->addDecorator(new Form_Decorator_HiddenLabel());
$this->addElements( array($hiddenlabel) );
}
}
In the controller I have something like:
...
$form = new Form_Questions();
$request = $this->getRequest();
if ($request->isPost())
{
$formData = $request->getPost();
if ($form->isValid($request->getPost()))
{
die(var_dump($form->getValues()));
}
}
else
{
//... add textbox, checkbox, ...
// add final submit button
$btn_submit = new Zend_Form_Element_Submit('submit');
$btn_submit->setAttrib('id', 'submitbutton');
$form->addElement($btn_submit);
$this->view->form = $form;
}
The form displays fine but the validation is giving me big trouble. My var_dump() only shows the hidden element that is staticly defined in the Form file. It does not save the dinamic elements so altought I can get them reading what's coming via POST, I can not do something like
$form->getValue('question1');
It behaves like if Zend uses the Form file to store the values when the submit happend, but since the elements are created dinamically they do not persist (either their values) after the post so I can not process them using the standar getValue() way.
I would appreciate any ideas on how to make them "live" til after the post so I can read them as in a normal form.
The form which you are calling isValid() and getValues() methods on is actually your "empty" form - you have instantiated it only a few lines up and haven't added any elements to it at that point.
Remember that POST only sends an array of fieldName => fieldValue type, it doesn't actually send a Zend_Form object.
It is difficult to suggest a new solution without knowing what you are trying to achieve. It is generally better to add all possible elements to your Zend_Form right away, and then only use the ones you need in the view scripts, i.e. echo $this->form->myField;. This will allow isValid() to process all the elements of the form.
It sounds like the form is dynamic in the sense that the questions come from a db, not in then sense that the user modifies the form itself to add new questions.
Assuming this is the case, then I wouldn't add the question fields in the controller. Rather, I'd pass the questions to the form in the constructor and then add the question fields and the validators in the form's init() method. Then in the controller, just standard isPost() and isValid() processing after that.
Or, if you are saying that the questions to be added to the form are somehow a consequence of the hidden label posted, then perhaps you need two forms and two actions: one for the hidden field form and another for the questions.
Ok, the simplest solution I came up with - to my case and considering the really of the code I am currently playing with was to load all the questions I need from the database using a method from my Model (something like fetchQuestions()), them in my controller I go throught the recordset and create the form elements according to the current question of the recordset.
The elements are stacked in an array that is passed to my Form constructor. In the form constructor I read the array and generate all the dynamic elements. I them just echoed the form to the view.
I have not seem why it would be a bad idea to override the Form constructor as I also could not use any of the set/get methods to pass this to my form.

Categories