How to modify certain fields in entity using only associative array? - php

I'm implementing editing user profile via API. The page where user edits its data contains a lot of fields, but when user submits the form, only edited fields are sent to my API endpoint. Also I'm not using form mapping.
Only way I see is to write something like this:
public function editProfile(FormInterface $form, User $user): User
{
$args = $form->getData();
if ($args['email']) {
$user->setEmail($args['email']);
}
if ($args['phone']) {
$user->setPhone($args['phone']);
}
// ...
$this->em->persist($user);
$this->em->flush();
return $user;
}
But it looks terrible and my form may contain up to several tens of fields.
Does anybody know good solution for this case?

Use form mapping and submit form with disabled clear missing fields option:
In form builder:
$options->setDefaults([
'data_class' => MyEntity:class
]);
In controller:
$data = $request->request->all();
$form->submit($data, false);`
instead of $form->handleRequest($request);

Related

how to add data to validated request input bag

I need to add custom data to the request input array from my customRequest class
I tried this way
request()->request->add(['cool' => request()->get('var1').request()->get('var2')]);
It's do the trick with request()->all() but when I returned $request->validated() it's not exist.
how can I do it?
$request->validated() is returning only validated data (data in the request validator class).
After validating the data you can add additional data in the request using
$request->merge(['cool' => request()->get('var1')]);
Laravel documentation: https://laravel.com/docs/8.x/requests#merging-additional-input
I had the same problem and this is what I did, and it worked for me.
You can store the validated data in a variable as shown below.
$validated_data = $request->validated();
And then make your changes on the $validated_data variable as shown below.
$validated_data['cool'] = $request->input('var1').$request->input('var2');
This should add the extra data to the validated data.
I have done this way
protected function passedValidation()
{
$bar = 'test';
$validated = $this->validated();
$validated['foo'] = $bar;
$this->merge([
'mergedValidated' => $validated
]);
}
Then in Controller I did this
$request->mergedValidated
You can merge with new array
array_merge(request()->all(), ['cool' => request()->get('var1').request()->get('var2')]);

Save elements when using the session Symfony

I am trying to use the session with Symfony. In fact, I want to complete a form before login.
For this reason, I would like this scheme:
Save the different fields in the session
Login/register
Save in the database
My controller:
public function customMadeAction(Request $request)
{
$session = $this->container->get('session');
$user = $this->container->get('security.context')->getToken()->getUser();
$CustomMade = new CustomMade();
$form = $this->createForm(new CustomMadeType(), $CustomMade);
$form->handleRequest($request);
if ($user === 'anon.') {
if($form->isValid()) {
# 1-Save in session
var_dump($CustomMade); #I have an array with all I need
$session->set('infos', $CustomMade); #It does not save my informations
# 2-Redirect to login/register
$securityContext = $this->container->get('security.context');
if (!$securityContext->isGranted('ROLE_USER')) {
throw new AccessDeniedException('Accès refusé');
} else {
# 3-Save in database
$em = $this->getDoctrine()->getManager();
$em->persist($CustomMade);
$em->flush();
}
}
}else{
if($form->isValid()) {
$CustomMade->setIdUser($user->getId());
$em = $this->getDoctrine()->getManager();
$em->persist($CustomMade);
$em->flush();
}
}
return $this->render('FrontBundle:Forms:customMade.html.twig', array(
'form' => $form->createView()
));
}
I do not think you can store an object in a session.
Here are a few solutions :
store manually each field of your object in the session
serialize your object and save it in the session
store it in the database with a flag saying it is not yet attached to a user, and save the id in session
As I see it, 1 is the fastest to implement, but it will be a pain to maintain if you later add fields to your entity. Solution 2 is better, but the deserialization is not so easy. I think solution 3 is the best, it is not that complicated to implement and will not cause any maintainance issue.
If you want to save the data, save only the input data from the form (after validation) and not the entirely entity (with possibly a lot of... shit, unless that is what you want).
You can just set the object/array into the session and Symfony will take care of serializing and unserializing it for you
If this is the case, replace
$session->set('infos', $CustomMade);
by
$session->set('infos', $form->getData());
This way you'll be later simply do:
$data = $session->get('infos');
The solution of Antoine is right,
You will have to serialize the object in order to be able to store it in the session.
The easiest way should be using the JMSSerializerBundle and decode your object as json:
$serializer = $this->container->get('serializer');
$jsonDecoded = $serializer->serialize($doctrineobject, 'json');
Btw. as stated in the comments this will serialize the whole doctrine structure connected to the entity.
However a toArray() function could be implemented into the entity in order to serialize an array structure only, but this approach becomes very complex when dealing with oneToOne oneToMany and manyToMany relationships

Symfony2 - using entity value as default when form is submitted with empty fields

I'm building a web application in Symfony 2 where I have a User entity class for holding registered users.
Every user should have at least a username and a password of course, hence, I use the #Assert\NotBlank validation rule for both fields in the entity. The username is static, however, being able to change the password is desirable.
Thus, I'm building a form where signed in users can change their password (among other things). This form utilizes the repeated field type in Symfony for password confirmation purposes.
Now, in most cases I guess users are not looking to change their password, but rather update other fields in their profile. Therefore, I would want it to be possible for them to leave the password field blank. However, that will interfere with the NotBlank validation rule.
Removing the NotBlank validation rule is of course an option. Although, hardly the solution I'm looking for since that incures the problem of users ending up with a blank password.
Finally, As I understand it the symfony Request object autofills the form data back into the User entity on form submission.
Now, my question is: Is there any way to, upon empty password-field, make Symfony refill the User entity with the existing password from the database rather than a blank value? This would allow validation to follow through and won't cause any undesired changes to the password upon saving.
This is the code for the password field in the entity
/**
* #var string
*
* #ORM\Column(name="password",type="string",length=255)
* #Assert\NotBlank()
* #Assert\Type(type="string")
* #Assert\Length(max="255")
* #Assert\NotEqualTo(value="password")
*/
private $password;
This is the code for generating the form
private function initForm($user) {
return $this->createFormBuilder($user)
->add('name', 'text')
->add('mail', 'email')
->add('password', 'repeated', [
'type' => 'password',
'invalid_message' => 'The password fields must match.',
'first_options' => ['label' => false],
'second_options' => ['label' => false] //set to false to hide label in view
])
->add('save', 'submit')->getForm();
}
This is the Action-code for the /profile/edit page:
/**
* #ParamConverter("user",class="MyBundle:User")
*/
public function editAction(User $user, Request $request) {
$form = $this->initForm($user);
$form->handleRequest($request);
if ($form->isValid()) {
//update to database and redirect user back to profile_view
$this->getDoctrine()->getManager()->flush();
return $this->redirect($this->generateUrl('profile_view'));
}
return $this->render('MyBundle:User:edit.html.twig',
array('form' => $form->createView()));
}
Thanks in advance for any help!
EDIT
I did try the "obvious" approach, i.e. temporarilly storing the original password in a variable and "putting" it back if it was blank after the form was submitted:
/**
* #ParamConverter("user",
class="MyBundle:User")
*/
public function editAction(User $user, Request $request) {
$password = $user->getPassword();
$form = $this->initForm($user)->getForm();
$form->handleRequest($request);
if ( $user->getPassword() == NULL ) {
$user->setPassword($password);
$form = $this->initForm($user)->getForm(); //this is the problem
}
if ( $form->isValid() ) {
//update to database and redirect user back to profile view
$this->getDoctrine()->getManager()->flush();
return $this->redirect($this->generateUrl('profile_view'));
}
return $this->render('MyBundle:User:edit.html.twig',
array('form' => $form->createView()));
}
However, this did not work for apparent reasons. When the form is reinitialised within the if statement, Symfony finds the form has never been submitted in the first place, i.e. no validation is performed. And adding the $form->handleRequest($request) leaves us back with the first problem where the password field might be blank.
What I do find peculiar though. Symfony validates the Entity and not the form. But removing the problem row $form->initForm($user)->getForm() still didn't work, although the entity should be valid.
I think this is not a good idea. The right way is create a separate form for changing user password. Examples: twitter, facebook, google
I think the solution reside with a EVENT on the form it self.
Will keep your validation intact when creating a new user
Will put back the model data on the request data for a existing user
with the password field empty
Will trigger validation for a existing user with a password field empty
in the model data(DB)
->addEventListener(FormEvents::PRE_SUBMIT,function(FormEvent $event) {
/** #var array $requestData */
$requestData = $event->getData();
/** #var \AppBundle\Entity\User $user */
$user = $event->getForm()->getData();
if ($user && !$requestData['password']){
$requestData['password'] = $user->getPassword();
}
$event->setData($requestData);
})
The FormEvents::PRE_SUBMIT will gave you access to 2 data type , who i commented with they respective type in the code.
$requestData is the normalized data from the user input this data is going to be apply on the model in this case $user , this will happen after the event PRE_SUBMIT.
Validation will happen on the $requestData but only after PRE_SUBMIT.
A solution is to use an extra class member $rawPassword, not stored in database, to be only used on your form. You will, of course, have keep your $password variable for database storage as defined in your question.
On your edit action, you just have to test after $form->bind($request); if your user as a $rawPassword password defined. If it's the case, update $password with the encoding value of $rawPassword, and flush.
EDIT : $form->bind($request); below 2.3, $form->handleRequest($request); otherwise.

Zend framework 2 edit album not working

I am getting PDOException in edit album "SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'artist' cannot be null". I debugged the code and found that after edit form action runs all the column(id,title,artist) values change to the null value in the insert statement, whereas it should be POST values of the edit form. I am using the same code as of ZF2 tutorial.
$request->getPost() has correct edited values but $form->getData() returns empty form post values for (id,title,artist).
can anybody please help.
My code is:
public function editAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('album', array(
'action' => 'add'
));
}
$album = $this->getAlbumTable()->getAlbum($id);
$form = new AlbumForm();
$form->bind($album);
$form->get('submit')->setAttribute('value', 'Edit');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($album->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getAlbumTable()->saveAlbum($form->getData());
// Redirect to list of albums
return $this->redirect()->toRoute('album');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
According to the ZF2 example, shouldn't it be
$this->getAlbumTable()->saveAlbum($album);
instead of
$this->getAlbumTable()->saveAlbum($form->getData());
Because you have already bind the $album which attaches the model to the form. This basically does two things
Displays the initial values fetched from that Album with unique ID
After validation of the form the data is put back into the model.
Just try what I have suggested
Perhaps you were experiencing the same issue as I did when creating an Entity (Model object) that was to be bound to the Form object.
The mistake I made was that I was providing always a new instance of the InputFilter from the entity's method
getInputFilter();
And after calling $form->isValid(), Zend Form was actually looking to see if there is an entity object bound to it...if so, then it would call the $entity->getInputFilter(), inside the form's $this->bindValues() method and after receiving the filter object the code would return $filter->getValues() to populate the bound model. Since the entity was always returning new InputFilter instance, naturally the values were empty/null.
For me, the mistake was writing something like this in the entity(Model):
public function getInputFilter()
{
return new SomeInputFilter();
}
But actually, I needed to write the method like this:
public function getInputFilter()
{
if(empty($this->inputFilter)){
$this->inputFilter = new SomeInputFilter();
}
return $this->inputFilter;
}
As you can see, the solution was to set a protected property $inputFilter, and populate it with a new instance of the InputFilter object only if it's empty. Didn't pay attention to the docs thoroughly while I was coding, and was having the same issue as you did (empty data in the bound model), while trying to insert a record.
Hopefully, you'll find this useful, if not however, I'm sorry to waste your time reading this. :)
P.S.: Thank you for reading my answer and I know I am a little late with the response to the topic, but I've recently started working with Zend 2 Framework, and I've experienced a similar issue, so I tried to share my 2 cents in the hope of helping somehow if possible.

How to link my controller and values from the user?

I am new to practicing CakePHP, I want to get value from the webuser and my controller will search that value from the DB. I am just wondering how I insert my $_post value add it to following code?
class DataviewsController extends AppController {
public $components = array('RequestHandler');
public function customer($id = null) {
$this->loadModel('Customer','Stock');
if (!$this->Customer->exists($id)) {
throw new NotFoundException(__('Invalid customer'));
}
$options = array('conditions' => array('Customer.' . $this->Customer->primaryKey => $id));
// Send the customer to the view
$this->set('customer', $this->Customer->find('first', $options));
$this->set('_serialize',array('customer'));
}
You can access post data in $this->request->data and get data in $this->request->query. As for your second question, I'm not sure what you are asking when it refers to the code you posted.
yes you can do with cakephp request handler object
here is very good example to create form and taking user data input and search from particular table. from that you can have very good idea how to implement in your application
just go throw this link Or this one for cakephp 2.0 and let me know if you need any more help

Categories