Checkbox type with nullable option - php

I'm using symfony forms to transfer API request in to DTO object. In my PATCH request i want to have bool field which can be null as well (for bool values there need to be done some action, for null just skip that action)
CheckboxType works only for boolean values so i decided to use ChoiceType like this
$builder
->add('is_active', ChoiceType::class, [
'choices' => [
null => null,
true => true,
false => false,
],
])
;
but it does not accept correctly false values, for false i get null and for null i get null value too. My goal is to accept all 3 values.
In configureOptions functions i have only this option:
$resolver->setDefault('data_class', TargetClass::class);
and in TargetClass this field is defined as:
private mixed $active = null;
There is any way in symfony forms how to handle correctly these 3 values: null, false, true
They must be as bool|null values

Related

Update mongodb collection with a object via eloquent

I would like to save the following object to a field on a mongodb collection via eloquent
"project_settings" : {
"resource" : true,
"zone" : true,
"contractor" : true,
"responsible_person" : false
}
this is my php code:
return ProjectModel::where($project_id)->first()->update($project_data);
dont worry about the model it works fine i need to make a query that updates the project collection
and $project_data =
project_settings:array(4)
resource:true
zone:true
contractor:true
responsible_person:true
Right now i get no error back. It returns successful but nothing is updated in reality. Can someone help?
The issue is probably with your inputs.
The method signature of update looks like below:
public function update(array $attributes = [], array $options = [])
So the attributes you pass in must be an array, not an object.
The where() method also need two inputs like where('column_name', $value).
So try something like below:
ProjectModel::find($project_id)->update([
"project_settings" => [
"resource" => true,
"zone" => true,
"contractor" => true,
"responsible_person" => false
],
]);

CakePHP: Unable to save data to parent entity via belongsTo associated child

Problem description
I'm trying to configure a CakePHP 3.7 API to save associated data in a child-first manner. The entities - for the sake of example, lets call them Users and Persons - and their relationships are as follows:
UsersTable.php
...
$this->belongsTo('Persons', [
'foreignKey' => 'person_id',
'joinType' => 'LEFT',
'className' => 'MyPlugin.Persons',
]);
...
PersonsTable.php
$this->hasOne('Users', [
'foreignKey' => 'person_id',
'className' => 'MyPlugin.Users'
]);
In their respective entities, they each have one another's property visibility set to true. What I'm trying to do is POST to the /users/ route (UsersController.php) and have it also save the Persons object included. The payload is as such:
{
"username": "foo",
"password": "bar",
"persons": {
"dob": "1982-07-03",
}
}
The relevant part of the saving method is below, from UsersController.php:
if ($this->request->is('post') && !empty($this->request->getData())) {
$data = $this->request->getData();
$newEntity = $this->Users->newEntity($data, ['associated' => 'Persons']);
$savedEntity = $this->Users->save($newEntity);
...
The error
This produces the following SQL error.
PDOException: SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column 'person_id' violates not-null constraint
DETAIL: Failing row contains (1, null, foo, bar)
I understand this is because Cake is attempting to save to Users without having a person_id to satisfy the foreign key constraint. It's not possible to reverse this FK relationship in my application domain as we desire leftward one-to-many relationship (User -> 1 Person).
I suspect sending an id in the persons object of the JSON payload will allow this to save correctly. However, for various reasons, this isn't possible at runtime. For example, this is how it's shown in the "Saving Data" CakePHP Book page...
$data = [
'title' => 'First Post',
'user' => [
'id' => 1,
'username' => 'mark'
]
];
...
$article = $articles->newEntity($data, [
'associated' => ['Users']
]);
$articles->save($article);
I know the following would also likely work as suggested by xPfqHZ for a similar issue, as Persons can save to Users, but it feels less suitable as compared to what I'm trying to do and feels as if there is a way via the associations on Users.
if ($this->request->is('post') && !empty($this->request->getData())) {
$data = $this->request->getData();
$newEntity = $this->Users->Persons->newEntity($data, ['associated' => 'Persons']);
$savedEntity = $this->Users->Persons->save($newEntity);
...
Workings
Now I believe this used to be possible in CakePHP 2.X, as stated in this answer by ndm on a similar question where a person is attempting to save the belongsTo associated entity and it's parent hasOne entity in one request via the belongsTo entity.
That's the expected behavior, saveAssociated() is not meant to save only the associated records, it will save the main record as well, so you should use saveAssociated() only, no need to manually set the foreign key, etc, CakePHP will do that automatically.
Controller
public function create() {
if ($this->request->is('post') && !empty($this->request->data)):
$this->CandidatesProblemReport->create();
if ($this->CandidatesProblemReport->saveAssociated($this->request->data)):
// ...
endif;
endif;
}
However, I'm not able to find or use the saveAssociated() method upon the Cake\ORM\Table object which the Users entity inherits from, in the documentation. Calling it produces a method not found error. This method only appears to exist on the Cake\ORM\Association object as detailed in the documentation. Unless I'm missing the obvious, is there a way to use this or is it used internally by BelongsTo() and its sibling methods?
Logging / Dumping entity
Using Cake\Log\Log::error($newEntity); or die(var_dump($newEntity)); shows the Users data of the payload hydrated into an object, but I don't see the Persons object attached (see below).
object(MyPlugin\Model\Entity\User)[299]
public 'username' => string 'foo' (length=3)
public 'password' => string 'bar' (length=3)
public '[new]' => boolean true
public '[accessible]' =>
array (size=5)
'*' => boolean false
'person_id' => boolean true
'username' => boolean true
'password' => boolean true
'person' => boolean true
public '[dirty]' =>
array (size=2)
'username' => boolean true
'password' => boolean true
public '[original]' =>
array (size=0)
empty
public '[virtual]' =>
array (size=0)
empty
public '[hasErrors]' => boolean false
public '[errors]' =>
array (size=0)
empty
public '[invalid]' =>
array (size=0)
empty
public '[repository]' => string 'MyPlugin.Users' (length=17)
Attempting to \Cake\Log\Log::error($savedEntity); shows nothing in the log file.
save() associations arguments
Another solution I considered was using the $options['associated] of save() as shown in the documentation (extract below). With this set to true as below, the error still occurred.
save( Cake\Datasource\EntityInterface $entity , array $options [] )
... associated: If true it will save 1st level associated entities as they are found in the passed $entity whenever the property defined for the association is marked as dirty. If an array, it will be interpreted as the list of associations to be saved. It is possible to provide different options for saving on associated table objects using this key by making the custom options the array value. If false no associated records will be saved. (default: true) ...
UsersController.php:
if ($this->request->is('post') && !empty($this->request->getData())) {
$data = $this->request->getData();
$newEntity = $this->Users->newEntity($data, ['associated' => 'Persons']);
$savedEntity = $this->Users->save($newEntity, ['associated' => true]);
...
Summary
Without going through the PersonsController.php and utilising its hasOne relationship, I'm not having much luck getting my Users and Persons data to save through the UsersController.php.
If I've missed any important information, or you have questions/need more, please ask! I might have missed something obvious, but I'd appreciate any suggestions/solutions possible.
As #ndm identified, the error lay in the posted data. As per the "Saving Data: Saving BelongsTo Associations" page of the documentation:
When saving belongsTo associations, the ORM expects a single nested entity named with the singular, underscored version of the association name.
The posted key persons should have been person. Equally, if the entity were named PersonSnapshots, the relevant key in the payload hydrated into the entities would need to have been person_snapshot.

Yii2 Validating an empty array (null array)

I have this scenario where I have a form as follows:
public $selling_price;
public $numbers;
public $inventory_factor;
public function rules() {
return [
['selling_price'], 'integer'],
[['inventory_factor'], 'safe'],
['numbers', 'each', 'rule' => ['integer']],
}
I have this last validation rule to make sure that I get an array of integers. This works fine when the input is a string for example. IT does not work though if an array [null] is sent. This for example does not throw errors
{
"selling_price": 2200,
"numbers": [null]
}
Using vardumper, gives the numbers array to be
[
0 => null
]
Is there way in Yii2 through which I can either remove(filter) the null values from the array before starting, or validating those as well?
Having looked at the special topic for the core validators, I see that under the each validator it shows:
rule: an array specifying a validation rule. The first element in the array specifies the class name or the alias of the validator. The rest of the name-value pairs in the array are used to configure the validator object.
Also, for the yii\validators\EachValidator, which extends yii\validators\Validator it has a property $skipOnEmpty, which defaults to true:
$skipOnEmpty public property
- Whether this validation rule should be skipped if the attribute value is null or an empty string.
public boolean $skipOnEmpty = true
So, accordingly, you need to tweak your rule as follows.
['numbers', 'each', 'rule' => ['integer', 'skipOnEmpty' => false]],
Now your validator for numbers will not turn a blind eye to the values in the array that are empty - if it finds any empty or non-integer values, the validation will fail.
['numbers', 'integer', 'min' => 0]
This will Validate that the value is an integer greater than 0 if it is not empty. Normal validators have $skipOnEmpty set to true.
Reference : https://www.yiiframework.com/doc/guide/2.0/en/input-validation
in this Data Filtering topic you can refer for these

Getting empty_data to work in a Symfony 2 application

I am adding fields to a project based on a project based on Symfony 2 and Sonata. I am trying to follow the instructions from this answer. In one of my admin classes, I have inserted the following code:
$default = 'Germany';
if (!$this->getUser()->hasRole(User::CONTENT_SUPPLIER)) {
$formMapper
->tab('Distribution')
->with('Distribution')
->add(
'module',
null,
[
'empty_data' => $default,
]
)
->add(
'distributions',
'distribution_list',
[
'label' => false,
'required' => 'false',
'disabled' => true
]
)
->add('plannedDistributions')
->end()
->end()
;
}
... and while I expect to see a reference to the "Germany" object by default in my form, I instead see an empty field. Should I be passing in an object rather than a string? Is what I'm trying to do even possible? What am I doing incorrectly here?
I think you missed a crucial bit in the documentation regarding empty_data:
This option determines what value the field will return when the submitted value is empty (or missing). It does not set an initial value if none is provided when the form is rendered in a view.
This means it helps you handling form submission with blank fields.
That means empty_data will populate your model with the data when the form was submitted without a default value.
I'm not familiar with the $formMapper used in your snippet, but in a typical Symfony-Controller you could create your form like this:
$form = $this->createForm(MyForm::class, $initialData);
In this case $initialData contains a property Distribution with the value Germany. Alternatively you could try providing the value in your frontend.
To set default data use option 'data'.
Sample:
//Use block
use Symfony\Component\Form\Extension\Core\Type\TextType;
//...
$formMapper
->add('module', TextType::class,[
'data' => 'Gearmany',
]);

preferred_choices entity field form never run

I want to set a form with a "preferred_choices" on top of my select field HTML corresponding to previous submitted datas selected by the user. I want to construct an entity field with a constant list AND a preferred_choices top element if the form is previously submitted.
I never ran correctly this function in symfony2.
Can you help me to construct correctly my field form.
Why my preferred_choices options select nothing when the form is construct ?
I setting this with correct object setted previously in the code.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$defaultCQSsearch = new CqsProSansMarque();
$defaultCQSsearch->setRayLibelle((!array_key_exists('ray_libelle', $options['attr'])) ? null : $options['attr']['ray_libelle']);
$defaultCQSsearch->setFamLibelle((!array_key_exists('fam_libelle', $options['attr'])) ? null : $options['attr']['fam_libelle']);
$defaultCQSsearch->setCaeLibelle((!array_key_exists('cae_libelle', $options['attr'])) ? null : $options['attr']['cae_libelle']);
$builder
->add('ray_libelle', 'entity', array(
'class' => 'ApplicationDriveBundle:CqsProSansMarque',
'data_class' => 'Application\DriveBundle\Entity\CqsProSansMarque',
'property' => 'ray_libelle',
'query_builder' => function(CqsProSansMarqueRepository $er){
return $er->createQueryBuilder('a')
->select('a')
->groupBy('a.ray_libelle');
},
'preferred_choices' => array($defaultCQSsearch),
'label' => 'rayon',
'required' => false,
))
preferred_choices option expects an array of values but you are passing an array of object (i.e. $defaultCQSsearch)

Categories