Symfony-Disabling specific field validations from controller - symfony

I am using Symfony 2.7.6. I have created an entity called employee and its interactive forms are generated using doctrine crud generator. Entity have the following fields
1. id
2. firstname
3. lastname
4. email
5. username
6. password
validations are working as expected from user registration form for all the fields.
ISSUE: I have created a login form and i want to suppress validation for the fields firstname, lastname and email and exclude these elements from rendering on my page
I have modified my controller like this for rendering my form
$entity = $em->getRepository('XXXEmployeeBundle:Employee');
$form = $this->createForm(new \XXX\EmployeeBundle\Form\EmployeeType(), $entity, array(
'action' => $this->generateUrl('user_login'),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Update'));
$form->remove('firstname');
$form->remove('lastname');
$form->remove('email');
$form->handleRequest($request);
This works fine when the from is rendering as the fields are excluded from the form. But my $form->isvalid() is returning false. As I have printed the errors using $form->getErrorsAsString() method, its showing like:
firstname: ERROR: First name cannot be empty. lastname: ERROR: Last name code cannot be empty. employeeFirstName: ERROR: Employee first name cannot be empty. email: ERROR: Email cannot be empty.
Is this the right method to achieve this functionality?? Please help me in solving the issue. Thanks

In your entity you mush include nullable=true like this
/**
* #ORM\Column(type="string", nullable=true)
*
* #var string
*/
protected $nombre;
And telling doctrine that is nullable, neither backend/frontend check the value.
Greetings !

I think problem in logic.
When you create registration form - you want to create and save new
entity.
When you create login form - you want to compare login and
password between form and entity.
So. You should create special form class for login (not from registration) and don't set data-enitity (second parameter in createForm function)
And, please check if you have the same form object in controller action that handles this form.

You can make a work around
Get all form's errors within your controller by
$form->getErrors()
and then loop over them, if it's the error you know it would happen, just bypass it on purpose and process further.
if ($form->isSubmitted()) { // remove $form->isValid() check
foreach($form->getErrors() as $error) {
// check if it's expected error, then do nothing and proceed further for user
// if it's unexpected throw an exception, catch them below and add error message to session flashbag. or something similar
}
}

Related

How to properply update an entity which contains an Image path?

I have a form that I use both for registration and edition of the user informations. This form contains a profile picture property on which I put #Assert\Image.
I succeed in creating a new user through my registration form but when I try to edit the user informations (with a PATCH method, just to update what need to be updated) I encounter an error with a 'File could not be found' message.
I suppose it's because the path stored in the database is a string and my #Assert\Image want an image.
I'm not sure about how I should manage this kind of update.
When I dd() the $user right after the submission, I see that the profilePicture property still contains the path saved in the database.
Here is my function regarding the form handling:
public function myProfile(Request $request)
{
$user = $this->getUser();
$form = $this->createForm(UserFormType::class, $user, ['method' => 'PATCH']);
if ($request->isMethod('PATCH')){
$form->submit($request->request->get($form->getName()), false);
if ($form->isSubmitted() && $form->isValid()) {
//...
}
}
//if no request just display the page
return $this->render('connected/myProfile.html.twig', [
'user' => $user,
'userProfileForm' => $form->createView()
]);
}
The Validator will check if your object contains a image and that seems not the case when you’re updating your object.
A workaround is to use group validation you define a specific group to the property that have the assert Image and in the method getGroupSequence you return the group if you’re in creation (id == null) or if the property is setted.

Require a field in symfony2 server side

I have a form in Symfony2 which I am building with buildForm
I add constraints like so,
$builder
->add('firstName', 'text', [
'required' => true,
'constraints' => [
new NotBlank(),
],
]
)
Everything works fine until I delete the input from my html and submit it without the firstName. I don't get any errors and it submits normally. Is there a way to absolutely require the firstName, even if is not present in the submit data
You must use an assert with your entity as explained in the symfony documentation here
like this:
class User
{
/**
* #orm:Column(type="string", nullable=false)
* #assert:NotBlank
*/
private $firstname;
}
You did not submit any data, the form is not submitted hence no validation is triggered.
Instead of:
$this->handleRequest($request);
Try to always submit the form even if the data is missing:
$form->submit($request->request->all());
I cannot guarantee this code is valid in your context since you did not provide your controller code.

Ignore Password when user updates profile with FOSUserBundle

I am using FOSUserBundle and I am trying to create a page that allows a user to update their user profile. The problem I am facing is that my form does not require that the user reenter their password if they don't want to change/update their password. So when a user submits the form with an empty password the database will be updated with an empty string, and the user will not be able to log in.
How can I get my form to ignore updating the password field if it is not set? Below is the code I am using.
$user = $this->get('security.context')->getToken()->getUser();
//user form has email and repeating password fields
$userForm = $this->createForm(new UserFormType(), $user);
if ($request->getMethod() == 'POST') {
$userForm->bindRequest($request);
if($userForm->isValid()){
//this will be be empty string in the database if the user does not enter a password
$user->setPlainPassword($userForm->getData()->getPassword());
$em->flush();
}
}
I have tried a few things such as the following, but this is still empty because the bindRequest sets the empty password to the user
if($userForm->getData()->getPassword())
$user->setPlainPassword($userForm->getData()->getPassword());
I have also tried, but this results in a similar situation and causes an unneeded query
if($userForm->getData()->getPassword())
$user->setPlainPassword($userForm->getData()->getPassword());
else
$user->setPlainPassword($user->getPlainPassword());
Are there any elegant ways to handle this use case?
The problem is that you bind a form to a User Object before controls upon password.
Let's analyze your snippet of code.
Do the following
$user = $this->get('security.context')->getToken()->getUser();
will load an existing user into a User Object. Now you "build" a form with that data and if receive a post, you'll take the posted data into the previous object
$userForm = $this->createForm(new UserFormType(), $user);
if ($request->getMethod() == 'POST') {
$userForm->bindRequest($request);
So, onto bindRequest you have alredy lost previous password into the object (obviously not into database yet) if that was leave empty. Every control from now on is useless.
A solution in that case is to manually verify value of form's field directly into $request object before binding it to the underlying object.
You can do this with this simple snippet of code
$postedValues = $request->request->get('formName');
Now you have to verify that password value is filled
if($postedValues['plainPassword']) { ... }
where plainPassword I suppose to be the name of the field we're interesting in.
If you find that this field contain a value (else branch) you haven't to do anything.
Otherwise you have to retrieve original password from User Object and set it into $request corrisponding value.
(update) Otherwise you may retrieve password from User Object but since that password is stored with an hased valued, you can't put it into the $request object because it will suffer from hashing again.
What you could do - i suppose - is an array_pop directly into $request object and put away the field that messes all the things up (plainPassword)
Now that you had done those things, you can bind posted data to underlying object.
Another solution (maybe better because you move some business logic away from controller) is to use prePersist hook, but is more conceptually advanced. If you want to explore that solution, you can read this about form events
I think you should reconsider if this is in fact a good use case. Should users be able to edit other users passwords? At our institution we do not allow even the highest level admin to perform this task.
If a user needs their password changed we let them handle that themselves. If they have forgotten their password we allow them to retrieve it via email. If they need assistance with adjusting their email we allow our admins to assist users then. But all password updating and creation is done soley by the user.
I think it is great that FOSUserBundle makes it so difficult to do otherwise but if you must DonCallisto seems to have a good solution.
<?php
class User
{
public function setPassword($password)
{
if (false == empty($password)) {
$this->password = $password;
}
}
}
This will only update the password on the user if it isn't empty.
I have found a simple hack to get rid of the "Enter a password" form error.
Manualy set a dummy plainPassword in the user entity. After form validation just reset it before you flush the entity.
<?php
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AppBundle:User')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Customer entity.');
}
$deleteForm = $this->createDeleteForm($id);
$editForm = $this->createEditForm($entity);
$postedValues = $request->request->get('appbundle_user');
/* HERE */ $entity->setPlainPassword('dummy'); // hack to avoid the "enter password" error
$editForm->handleRequest($request);
if ($editForm->isValid()) {
/* AND HERE */ $entity->setPlainPassword(''); // hack to avoid the "enter password" error
$em->flush();
return $this->redirect($this->generateUrl('customer_edit', array('id' => $id)));
}
return array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
);
}

Unset a form field value in symfony2 controller

In a typical Symfony2 form, when a field is invalid, the form is presented again to the user with all fields repopulated and an error on the specific field that has an issue.
In my form, I want to force the user to reenter the values of one field (for security reasons), but keep the rest of the fields populated. Is there any way to unset/clear a fields value from the controller in SF2?
Just set it to null — or whatever an empty value is — on the model object itself.
if ($form->isValid()) {
// ...
} else {
$object->setSomeField(null);
}
After you change the value on the object as shown in the answer below, you need to create the form again and pass the object to the form when you do...
$form = $this->createForm(new YourFormType(), $object);
return $this->render('YourBundle:YourEntityName:yourTemplate.html.twig, (array(
'entity'=>$entity,
'form'=>$form->createView()
));

How I can do a confirmation window?

I want to create a confirmation window when I fill in a form.
Right now, I fill in the form and if the form is valid, the entity is persisted and returned a view with my entity as a parameter. But this isn't what I want.
If the form is valid I don't want to persist the entity. If it's valid, would have to show a view using my parameter(entity) and then if my user clicks the button to confirm, persist the entity and redirect to other view. If my user clicks the button to return, I use the JavaScript function: javascript:history.back(1).
How I can do this?
An easy way is to store your bound entity in session (a flash) and retrieve it after confirmation for persistence.
In your "saveForm" action:
if ($form->isValid()) {
$myEntity = $form->getData();
$this->get('session')->setFlash('my_entity', $myEntity);
return $this->render('MyBundle:Controller:confirmation.html.twig', array(
'entity' => $myEntity
));
}
And in your "confirmSave" action:
$myEntity = $this->get('session')->getFlash('my_entity');
$this->em->persist($myEntity);
$this->em->flush();
It's just a basic example an it needs to be adaped to your project.

Resources