Symfony 2 / PHP compare the difference of objects in arrays? - php

I am using Symfony 2.7 I have built a form with an entity, which when submitted returns an array of objects. I need to be able to compare this array of objects with what I have in the that table?
So this is how I have the form setup
$builder
.......
->add('my_options', 'entity', [
'label' => 'Options:',
'class' => 'xxxxBundle:Details',
'choice_label' => 'Title',
'multiple' => true,
'expanded' => true,
'required' => false,
'mapped' => false,
'data' => $data,
'attr' => ['class' => 'AdminList'],
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('de')
->where('de.active = ?1')
->setParameter(1, 1); }
]);
I then do a basic lookup of what my options table has already got,
$EditPanels = $this->getDoctrine()
->getRepository('xxxBundle:Options')
->findBy(['AccountID' => $AcID]);
This gives me two arrays, one of which the user has just selected (the options they now need on this account) and one with what is already in the database table.
How do I compare these tables to update the rows with the new options, by removing whats not needed and adding in the new options?
Thanks.

$newIds = array_map($formData, function (Details $d) {
return $d->id;
});
$oldIds = array_map($EditPanels, function (Details $d) {
return $d->id;
});
$shouldBeRemoved = array_diff($oldIds, $newIds);
$shouldBeAdded = array_diff($newIds, $oldIds);
Now you have all the IDs for the Options that need to change. Hope this helps.

I think you should not even query for existing records. Instead you can:
Persist all new records and update existing:
foreach ($new as $object) {
if ($object->getId() === null) {
$em->persist($object);
}
}
$em->flush();
Delete all other records from database:
$qb = $em->getRepository('xxxxBundle:Details')->createQueryBuilder();
$qb->delete()->where($qb->expr()->notIn('id', array_column('id', $new)));
P.S. Not sure regarding the syntax, but you got the idea.

Related

How to add a new option to select entity

I'm working on a view with lots of invoices.
Users can filter them by 'Customer', 'Date' and also by 'Referent'.
An invoice is linked to a customer, and a customer can have a 'referent' or not.
So in my 'referent' select list, the default value is 'All' to not filter by 'referent', and the rest is the list of all referents got by QueryBuilder.
Now, I need help to know how can I insert an option 'No Referent' in the select list to get all invoices for which the customer has no referent.
Here is my referent field in my 'InvoiceSearchType':
->add('referent', 'genemu_jqueryselect2_entity', array(
'label' => 'Referent',
'class' => 'GeocalUserBundle:User',
'query_builder' => function (UserRepository $ur) {
return $ur->getEmployesQueryBuilder();
},
'empty_value' => '',
'configs' => array(
'placeholder' => 'All',
'width' => '100%',
'allowClear' => true,
),
'required' => false,
))
Here, my QueryBuilder:
public function getEmployesQueryBuilder()
{
$queryBuilder = $this->createQueryBuilder('u')
->leftJoin('u.groups', 'g')
->where('u.enabled = 1')
->andWhere('g.id NOT IN(1)')
->orderBy('u.nom', 'ASC')
;
return $queryBuilder;
}
And I just display the field like that:
<td class="label">Chargé d'affaire</td>
<td colspan="2">{{ form_widget(form.referent) }}</td>
Thanks in advance ! :)
[SOLVED]
First I added a method which get the result (array) of the query, add another referent and return it:
public function getReferentWithNull()
{
// Get the list of referents
$referents = $this->doctrine->getRepository('GeocalUserBundle:User')->getEmployesQueryBuilder()->getQuery()->getResult();
// Create a new instance
$nobody = new User();
$nobody->setName("No Referent");
// Put it in the array result with the key -1
$referents[-1] = $nobody;
return $referents;
}
Then, I modified my form field type to 'choice' type and call my previous function:
->add('referent', 'genemu_jqueryselect2_choice', array(
'label' => 'Referent',
'choices' => $this->getReferentWithNull(),
'empty_value' => '',
'configs' => array(
'placeholder' => 'All',
'width' => '100%',
'allowClear' => true,
),
'required' => false,
))
Finally, I have my last option 'No Referent' with a key of -1.
Hope that it helps someone :)

default data in sonata_type_model

I work with symfony 2.7 , and I use SonataAdminBundle.
I have 2 entities called (Produit) and (Correspondant) with OneToMany relation, One Produit can have Many Correspondant. in the create form for the (Produit) I have correspondants to add Many (Correspondant), and I like by default add all the Correspondants, for that I tried to do this :
ProduitAdmin
$query = $this->modelManager->getEntityManager(new User())->createQuery("SELECT s FROM UserBundle\Entity\User s WHERE s.type LIKE 'Correspondant'" );
$formMapper
->add('correspondants','sonata_type_model', array(
'class'=>'Devagnos\UserBundle\Entity\User',
'multiple'=> true,
'by_reference' => false,
'label'=>'Correspondants associés',
'data' => function() {
$data = new ArrayCollection();
$r= $query->getResult();
foreach($r as $result) {
$data->add($result->getId());
}
return $data;
},
'query' => $query ),
)
But this does not work,
Someone can help me please ? thanks
You need to set data attribute and put the entities you want to be selected as default.
$selected = ... //fetch entities, e.g. from repository
$formMapper
->add('field', 'sonata_type_model', array(
'your_settings' => '...',
'query' => '...',
'data' => $selected
)
);

How can I edit a field of a form in my controller?

I'm having trouble formulating a solution for 'editing' a field of my form in my controller.
Here's what I have:
I have a symfony2 form registered as a service that I call in a function in my controller. I am removing a bunch of fields that aren't necessary for this other form I am directing my users to and then adding a few others.
(I realize I could create another form and create another service and such but for my purpose this would be a bit overkill. I'm doing it this way because the form functions the same, however some fields are not needed and a few new specific ones are.)
I would now like to essentially 'edit' one field in this form... The 'occupation' field. This field is a choice field acting as radio buttons populated by an array of choices. It's required and has no empty_value requirement in its original state.
I would like to edit it in my controller function to have the same exact values however with a required value of false and an empty_value of null.
With the commented out code below the result is a dissapearance of the occupation field in my 'new' form and it is replaced by an empty drop down. I realize it's because I'm overriding the whole field below, but I cannot figure out how to simply edit it.
Code:
/**
* Explanation of addAndRemoveFieldsInRegisterForm function:
* The function gets the 'registration' form and removes any
* fields not needed for the 'in_registration' form
* and then adds the necessary fields to the form.
*/
private function addAndRemoveFieldsInRegisterForm($user)
{
$form = $this->createForm('user_registration', $user);
// http://stackoverflow.com/questions/10920006/pass-custom-options-to-a-symfony2-form ---
// --- use that to help. Look at changing the value of array.
$form->remove('title');
$form->remove('company');
$form->remove('username');
$form->remove('city');
$form->remove('state');
$form->remove('country');
$form->remove('gender');
$form->remove('age');
$form->remove('roles');
// $form->remove('occupation');
// $pr = $form->get('occupation');
// $pr->set('required' => false);
// $form->get('occupation')->add('required'=>false, 'empty_value'=>null);
// $form->add('occupation','choice', array(
// 'required' => false,
// 'empty_value' => null,
// ));
// echo "<pre>";
// var_dump(get_class_methods($form));die;
$form->add('occupation','choice', array(
'required' => false,
'empty_value' => null,
));
$form->add('canEmail', 'checkbox', array(
'label' => 'Can Email?',
'required' => false,
));
$form->add('sendEmail', 'choice', array(
'label' => 'Send Welcome Email? ',
'required' => true,
'mapped' => false,
'expanded' => true,
'choices' => array(
"yes" => "Yes",
"no" => "No"
),
));
return $form;
}
Original Form (the one that's used as a service)
private $requireOccupation;
$this->requireOccupation = true;
->add('occupation','choice', $options['occupation'])
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$occupation = array(
"label" => "Which of these currently describes you best? (Occupation):",
"expanded" => true,
'required'=> $this->requireOccupation,
"choices" => array(
"X" => "X",
"B" => "B",
"C" => "C",
"J" => "J",
),
'constraints' => array(
new NotBlank()
));
$resolver->setDefaults(array(
'occupation' => $occupation,
));
}
I think it is better to create another form. It can herit from your already defined form to change only the field you want
class SomeFormType extends OriginalFormType {
public function buildForm(FormBuilderInterface $builder, array $options) {
parent::buildForm($builder, $options);
$builder
->remove('someField')
->add('someField', 'choice', [
"expanded" => true,
"choices" => $yourArray
]);
}
It has the advantage to be mapped on different object
Firstly, I realize the way I wanted to solve this issue is odd when considering I could have created another form with either the fields I wanted to use or just the one field that needed to change and register the form as a service to use it elsewhere, but I was tasked to complete it this way.
Second, my solution is quite simple. I pass values into my form with a default value set in the form.
In the form:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$requireOccupation = true;
$emptyValue = null;
//whatever other values you want to set here
$resolver->setDefaults(array(
'requireOccupation' => $requireOccupation,
'emptyValue' => $emptyValue,
));
}
and then on the field's properties:
$builder->add('occupation', 'choice', array(
"label" => "Some sort of label",
"required" => $options['requireOccupation'],
"empty_value" => $options['emptyValue'],
...
));
Now in the controller:
$form = $this->createForm('registration', $user, array(
'requireOccupation' => false, 'emptyValue' => null
));
call that where you want to generate your form while passing in the values you want to use for that form.
I am by no means an expert on Symfony and this solution would probably generate some issue with those who are. But it works for me.

Set default value for entity type in Symfony2

I couldn't figure out how to make a default value for an entity type in symfony2. My code looked like this:
$rewardChoice = $this->createFormBuilder($reward)
->add('reward_name', 'entity', array(
'class' => 'FuelFormBundle:Reward',
'property' => 'reward_name',
'data' => 2,
'query_builder' => function(EntityRepository $er){
return $er->createQueryBuilder('r')
->where('r.active = 1')
->groupBy('r.reward_id')
->orderBy('r.reward_name', 'DESC');
},
))
->getForm();
However you need to hand in the object you are working with to make it work. My answer is below.
I found a lot of different answers on this but they all restructured the way the form was built. This was much easier.
So I found a lot of answers to make this work but all of them seemed to restructure the form to be built in another way however I found that setting the object in works best so I figured I would post my solution incase anyone ran into the issue again.
Here is my code in the controller.
// this is setting up a controller and really isn't important
$dbController = $this->get('database_controller');
// this is getting the user id based on the hash passed by the url from the
// database controller
$user_id = $dbController->getUserIdByHash($hash);
// this is getting the Reward Entity. A lot of times you will see it written as
// $reward = new Reward however I am setting info into reward right away in this case
$reward = $dbController->getRewardByUserId($user_id);
$rewardChoice = $this->createFormBuilder($reward)
->add('reward_name', 'entity', array(
'class' => 'FuelFormBundle:Reward',
'property' => 'reward_name',
// I pass $reward to data to set the default data. Whatever you
// assign to $reward will set the default value.
'data' => $reward,
'query_builder' => function(EntityRepository $er){
return $er->createQueryBuilder('r')
->where('r.active = 1')
->groupBy('r.reward_id')
->orderBy('r.reward_name', 'DESC');
},
))
->getForm();
I hope this make things more clear. I saw a lot of the same question but none with this solution.
The best way to do this is to set reward name before creating the form. For example:
$reward->setRewardName('your_relationship_reference_here');
$rewardChoice = $this->createFormBuilder($reward)
Using the data field can cause problems.
For symfony 4 we can use 'placeholder' => 'Choose an option',
->add('reward_name', EntityType::class, array(
'class' => Reward::class,
'choice_label' => 'name',
'placeholder' => 'Choose an option',
))
Initialize value from the form's target object
$article=2/*Id of item that you wont to set as default*/
$stock->setArtigo($this
->getDoctrine()
->getManager()
->getRepository('AppBundle:Artigo')
->find($article));
$form = $this->createForm('AppBundle\Form\StockType', $stock);

Symfony2 and FormBuilder: How to get the elemetns number added in the builder

I have a formbuilder where I am adding some values from an entity:
$builder->add('affiliation', 'entity', array(
'class' => 'SciForumVersion2Bundle:UserAffiliation',
'multiple' => true,
'expanded' => true,
'query_builder' => function(EntityRepository $er) use ($author,$user) {
return $er->createQueryBuilder('ua')
->where("ua.user_id = {$user->getId()}")
->andWhere("ua.affiliation_id not in ( select pa.affiliation_id FROM SciForumVersion2Bundle:PersonAffiliation pa where pa.person_id = {$author->getPersonId()} )");
},
'required' => true,
));
In my controller, I would like to check if there is something in my form. If there is something, I will display one view, if there is nothing, I will display another view.
Is this possible and if so, how?
Thank you.
Simply try it:
$data = $form->getData()
function getData() documentation Book
If you want to get the current data (just after rendering the form) in your form type you can use the builder supplied in each form type by standard.
It works exactly as a normal form response, so you can use:
$builder->getData();
and use if clauses to add different fields depending on what you want to generate.

Categories