How can I remove an individual parameter from a Symfony2 request object - symfony

I have the following request object and would like to remove 'email_suffix' from a controller before binding to a form. Is this possible?
public 'request' =>
object(Symfony\Component\HttpFoundation\ParameterBag)[8]
protected 'parameters' =>
array
'registration' =>
array
'email' => string 's' (length=1)
'email_suffix' => string 'y.com' (length=5)
'password' => string '1234' (length=4)
'_token' => string '967d99ba9f955aa67eb9eb004bd331151d816d06' (length=40)
'product_id' => string '2' (length=1)
'product_description' => string '12 month membership' (length=19)
'product_price' => string '6.99' (length=4)
I have tried $request->request->remove("registration[email_suffix]");
I can do $request->request->remove("registration") - this works.
For now, I am doing this:
$requestReg = $request->request->get('registration');
$requestReg['email'] = $requestReg['email'].'#'.$requestReg['email_suffix'];
unset($requestReg['email_suffix']);
$request->request->set('registration',$requestReg);

There's the possibility to add and to remove the parameters from the request object in symfony2.
You have to look at ParameterBag Component, there's such the method called remove($key), that's what you need.
So the solution for your request would be like this, if you call it from controller object:
$this->get('request')->query->remove('email_suffix');

I am not sure, if your call $request->request is typo.
You should operate with $request->attributes which represents ParameterBag class.
If you'll go through methods in ParameterBag you'll see that there is no way to unset variable inside array.

Related

Symfony 5.2 error validations on field password. Why don't work NotBlank?

I am maintaining a large project. We recently updated the framework to version 5.2 and got an error:
Argument 1 passed to Symfony\Component\Security\Core\Encoder\MigratingPasswordEncoder::encodePassword() must be of the type string, null given, called in ...
This is how the buildForm() method looks like:
$builder
->setMethod('POST')
// ....
->add('pass', PasswordType::class, [
'label' => 'Password',
'constraints' => [new NotBlank(), new Length(['min' => 6, 'max' => 20])],
])
I can't figure out what the error is. Why don't work NotBlank? Something has changed in the framework, why does the code that used to work now throw an error?
Look at the configureOptions() method of your 'FormType' class. At data_class option you should have set an entity name.
In this entity you have to allow null value in the $pass property. Look at the $pass property type hint. It should be something like :
...
private ?string $pass = null;
...
That's because the form as to handle the data even though those could be invalid.
That's why most of the time you'll prefer to use a DTO (Data Transfer Object) in your data_class option for the FormType so you can have nullable properties.

How to validate array of arrays in Symfony 4

I want to know how can I validate array of arrays in symfony.
My validation rules are:
User - NotBlank
Date - Date and NotBlank
Present - NotBlank
So far I have done this:
$validator = Validation::createValidator();
$constraint = new Assert\Collection(array(
'user' => new Assert\NotBlank(),
'date' => new Assert\Date(),
'present' => new Assert\NotBlank()
));
$violations = $validator->validate($request->request->get('absences')[0], $constraint);
But the problem is that it only allows to validate single array eg.
$request->request->get('absences')[0].
Here is how the array looks like:
You have to put the Collection constraint inside All constraint:
When applied to an array (or Traversable object), this constraint allows you to apply a collection of constraints to each element of the array.
So, your code will probably look like this:
$constraint = new Assert\All(['constraints' => [
new Assert\Collection([
'user' => new Assert\NotBlank(),
'date' => new Assert\Date(),
'present' => new Assert\NotBlank()
])
]]);
Update: if you want to use annotations for this, it'll look something like this:
#Assert\All(
constraints={
#Assert\Collection(
fields={
"user"=#Assert\NotBlank(),
"date"=#Assert\Date(),
"present"=#Assert\NotBlank()
}
)
}
)

How can I obtain the values of an Entity in Laravel-Backpack?

While I was trying to show pictures I made this pleasant discovery in backpack:
$this->crud->addFields([
[ // Upload
'name' => 'pictures', //<-- this is an Entity
'label' => 'Photos',
'type' => 'upload_multiple',
'upload' => true,
'disk' => 'uploads'
]
]);
This fragment of code gives me this:
My questions is:
What am I doing wrong?
How can get the value 'file' of this two vectors? I need this for display the images.
You probably forgot to add 'photos' to the cast array.
Based on the documentation:
Step 3. Since the filenames are stored in the database as a JSON array, we're going to use attribute casting on your model, so every time we get the filenames array from the database it's converted from a JSON array to a PHP array:
protected $casts = [
'photos' => 'array'
];
https://laravel-backpack.readme.io/docs/crud-fields#upload_multiple

How to access the fields from the form data in symfony 3

I want to use how to access the username and password fields from the below code.
AppBundle\Entity\MasterUserAccount Object
(
[id:AppBundle\Entity\MasterUserAccount:private] =>
[firstName:AppBundle\Entity\MasterUserAccount:private] =>
[lastName:AppBundle\Entity\MasterUserAccount:private] =>
[username:AppBundle\Entity\MasterUserAccount:private] => test
[password:AppBundle\Entity\MasterUserAccount:private] => 123456
[createdBy:AppBundle\Entity\MasterUserAccount:private] =>
[updatedBy:AppBundle\Entity\MasterUserAccount:private] =>
[createdAt:AppBundle\Entity\MasterUserAccount:private] =>
[updatedAt:AppBundle\Entity\MasterUserAccount:private] =>
[status:AppBundle\Entity\MasterUserAccount:private] =>
)
$data = $form->getData();
$username = $data['username'];
I'm getting the below error the following error
Cannot use object of type AppBundle\Entity\classname as array
The data that you get out of a symfony form is an Entity. You can't access an attribute of this entity, as you do for arrays.
Instead you should be using getter method defined inside class MasterUserAccount.
So. It should be:
$username = $data -> getUserName();
This is assuming that getter method is already defined inside MasterUserAccount class. If not, create a getter method first.

How to convert an integer based entity field into a human readable name in Twig

In a Symfony 2.4+ project, what is the best way to register an array of values for a field that saves as an integer but needs to display human readable values in a template?
I have an entity with a property that is populated with integer values that represent different constant values:
/**
* The repetition frequency for billing cycle:
* #ORM\Column(type="smallint")
*/
protected $repetition = 0;
I would like to store the names of these values somewhere, so initially I put them in my entity with a getter:
protected $repetitionName = array(
0 => 'Setup',
1 => 'Second',
2 => 'Minute',
3 => 'Hour',
4 => 'Day',
5 => 'Week',
6 => 'Month',
7 => 'Year'
);
public function getRepetitionName() {
return $this->repetitionName;
}
This seems like a great central repository for the values.
Then in my twig template I don't want to display the integer, I want the corresponding name value. So I translate them like this:
<div class="billingCycle">{{ entity.repetitionName[entity.repetition] }}</div>
And in my form builder I make a field that references that array like this:
$builder->add('repetition', 'choice', array(
'label' => 'Billing Cycle',
'help' => 'The repetition frequency when this service is billed.',
'choices' => $builder->getData()->getRepetitionNamePer(),
// default to monthly (the most common)
'empty_data' => 6,
'required' => TRUE
));
The Problems With This Approach
1. Translation: If I want to translate this at any point, it's hard coded in one place.
2. Reusability: If I have other entities that have repetition (e.g. event calendar) it would be nice to reuse this.
3. Configurability: Ideally these would be editable in a config file instead of the entity code.
Alternative Solution: Custom Form Type as Global Service with Config Parameters
The better option seems to set some default parameters in the config file:
parameters:
gutensite_component.options.status:
0: Inactive
1: Active
gutensite_component.options.repetition:
0: Setup
1: Second
2: Minute
3: Hour
4: Day
5: Week
6: Month
7: Year
Then create a custom form type Gutensite\ComponentBundle\FormType\RepetitionType that loads the options from the config parameters. See the Documentation for a great example of this. Then just refer to that field type like this:
$builder->add('repetition', 'repetition', array(
'label' => 'Billing Cycle',
'help' => 'The repetition frequency when this service is billed.',
// default to monthly (the most common)
'empty_data' => 6,
'required' => TRUE
));
The inconvenient part of this solution, is that you have to either parameter to twig in your config (which is bloat for every template even if you don't need it), or always remember to manually pass the parameters to twig from your controller.
// I add to the standard object `$controller->view` which gets passed to Twig
$controller->view->options['repetition'] = $this->container->getParameter('gutensite_component.options.repetition');
To be accessed like:
<div class="priceValue label label-primary">${{ entity.price }}/<span class="billingCycle">{{ view.options.repetition[entity.repetition] }}</span></div>
This is more clunky than I would like but it is reusable. Maybe others have better solutions to pass the configuration to twig than what is represented here.
Other Suggestions?
Do you have any other suggestions, best practices or lessons learned? Please share.
What I would do is to save those values as objects of a new entity and set a manyToOne relation from your main entity (or any other entity as your calendar event entity) to the repetition entity
If so, you can easily add new repetitions every time you want or get all objects of the main entity using any specific repetition.
Also you can build a nice form for a new object of the main entity with an input (human readable) of repetition values:
$builder->add('repetition', 'entity', array(
'class' => 'AcmeDefaultBundle:Repetition', // This is your new 'repetition entity'
'property' => 'repetitionName', // The field of your 'repetition entity' that stores the name (the one that will show a human readable value instead of the id)
'expanded' => true, // True if you prefer checkbox instead of a dropdown list
'label' => 'Billing Cycle',
'help' => 'The repetition frequency when this service is billed.',
'required' => true,
));
Now when you want to show the name of the repetition in twig you will use:
<div class="billingCycle">{{ entity.Repetition.repetitionName }}</div> (you can also translate that value later)
A cleaner way (if you use it only for this entity) is to define a public method in your entity that returns you that array:
public function getRepetitionNames() {
return array(
0 => 'Setup',
1 => 'Second',
2 => 'Minute',
3 => 'Hour',
4 => 'Day',
5 => 'Week',
6 => 'Month',
7 => 'Year'
);
}
Another method to retrieve the label based by your "repetition" field value:
/**
* #param $key
* #return null
*/
function getRepetitionLabel(){
$repetitions = $this->getRepetitionNames();
return isset($repetitions[$this->repetition]) ? $repetitions[$this->repetition] : 0;
}
Will be much easier to access it in twig now:
<div class="billingCycle">{{ entity.repetitionLabel }}</div>
Last, in your form use your entity to retrieve the values:
$object = $builder->getData();
$repetitionChoices = $object->getRepetitionNames();
$builder->add('repetition', 'choice', array(
'label' => 'Billing Cycle',
'help' => 'The repetition frequency when this service is billed.',
'choices' => $repetitionChoices
'empty_data' => 6,
'required' => TRUE
));
If you plan to use it in more entities, you could use a interface.

Resources