Doctrine, ignore some fields to persist and null - symfony

given a user:
id, name, password
so I want to modify him, and set a name to it. But then if I persists, his password will be rewritten (set to empty), even though I didnt set it. But here is the nullable=true annotation! Right now it seems to work - but this way its impossible to persist if I want to set it null itself. Then how?

in the password field in form add the argument mapped => false do the Doctrine will not be considered as an entity field in the moment of form validation.
->add('password', 'password', array(
'mapped' => false
))

Related

How to have Symfony Sonata FormMapper show 0 (zero) default for NULL or empty varchar data (MySQL)?

This is driving me crazy. I've been all over documentation and StackOverflow and other places trying to figure out how to just get Symfony or Sonata to behave sensibly with a form field empty value default or override.
OK, say you have a form that relates to an ORM entity that saves to its own MySQL database table, and that form has a field that when empty you want to default to 0 (integer or string, it doesn't matter).
On a New form, setting FormMapper ->add 'empty_data' => '0' works fine (I use string zero because the value saves as VARCHAR), however, on an Update (or Edit) form, the existing record's value always shows as empty (nothing in the field), whether that saved value is NULL or '' (empty string). If the value is already 0, it shows 0.
Example:
TheThing.orm.yml:
theThing:
nullable: false # originally true
options: # originally not specified because NULL was default
default: 0 # saves as string in VARCHAR column
With this config, running bin/console doctrine:schema:update --force updates table the_thing, changing the NULL values to empty string. Not good database practice, but I'll do what I have to to make this work with Symfony/Sonata/Doctrine/whatever.
Entity TheThing:
private $theThing = '0';
Normal getter and setter. Everything works as expected on a New form, the value defaults to 0.
The FormMatter field definition:
->add('theThing', 'text', [
'label' => 'The Thing Field',
// TODO: If database value is NULL or empty, set value to 0.
'empty_data' => '0', // this doesn't work on the Update form if the saved value is NULL or empty string
//'empty_value' => '0', // suggested but apparently deprecated and invalid
//'data' => '0', // hard-sets the value; overrides existing value no matter what
])
So, my solution is to either figure out how to get Symfony to understand that I want empty values (NULL, empty string) to show a default/override that I specify (like 0), or I modify the existing records to convert empty values to 0.
Do I need to do the bad database practice thing, or is there a Symfony/Sonata/Doctrine solution that get the form Update/Edit field to behave sensibly?
PS I'm using Symfony 3, Sonata 3, and Doctrine 1. Sorry, I have to until we can upgrade. Your solution may still be viable however, or a good hint.

Symfony EntityType - access choice_label after submitting

I have an EntityType field:
->add('topic', null, [
'required' => false,
'class' => Category::class
])
And for new Category 's my js tool creates a new select option marked with __new_option__:
So the value to read is not the value. It is the label.
How can I read this value after submission.
I tried addViewTransformer, addEventListener with preSetData and postSetData.
But when I get the value - it shows everytime just __new_option__ but not the value to persist into the database.
Is there a way to do that?
How can I read this value after submission. I tried
addViewTransformer, addEventListener with preSetData and postSetData.
By reason of the post-data containing the topic-field eq 'new_option'. "It doesn't know anything about the selected value`s label".
I don`t know your implementation, but -> just change-modify the js-behaviour on submitting like:
let topicSelection = document.getElementById('SELECTOR');
topicSelection.options[el.selectedIndex].value = topicSelection.options[el.selectedIndex].innerHTML;
//... submitting

Non-mapped form, EntityType and data attribute

I use an EntityType to create a form, but not mapped on an entity. The form is long and the user re-use the same options many times, then when he valid the form, if it's valid, I store the $form->getData() in session.
When I generate the form I inject the $data. It works well for all options, except the EntityType, I don't understand why...
In the $data, I've an ArrayCollection with the objects selected in the EntityType, but the form doesn't select it. I've used mapped = false, because if I remove it I've an error:
Entities passed to the choice field must be managed. Maybe persist them in the entity manager?
Someone I've an idea how to do ?
Settings mapped = false shouldn't be the solution in this case, because you need to write the stored data into this field, right? so mapped = false avoid it (see more about mapped option here)
The problem here is that the EntityType need to get the id value from each item and it requires that these items are managed actually by EntityManager:
Entities passed to the choice field must be managed. Maybe persist them in the entity manager?
An entity is in MANAGED state when its persistence is managed by an EntityManager. In other words, an entity is managed if its fetched from the database or registered as new through EntityManager#persist.
In you case, these entities comes from session, so you have two option:
Re-query the stored entities from database:
if (isset($data['foo']) && $data['foo'] instanceof Collection) {
$data['foo'] = $this->getDoctrine()->getRepository(Foo::class)->findBy([
'id' => $data['foo']->toArray(),
]);
}
Or, set a custom choice_value option to avoid the default one:
$form->add('foo', EntityType::class, [
'class' => Foo::class,
'choice_value' => 'id', // <--- default IdReader::getIdValue()
]);

In symfony2 how do I add nullable boolean

I'm using FOSRestBundle and am trying to setup a POST that will allow null to ba saved for a few fields defined as checkbox in the FormType.
My entity has the annotation nullable=true
/**
* #ORM\Column(type="boolean", nullable=true)
*/
protected $foo_bar;
The FormType (which will only ever be used through the API so it's mostly left to the deaults) has required set to false
$builder->add('foo_bar', 'checkbox', array(
'required' => false
));
When I save and foo_bar is null, it saves as 0 in the database
$entityData = $request->request->all();
$entityData['foo_bar'] = null;
$entity = $this->container->get('acme.entity.handler')->post($entityData);
I need to save foo_bar as null (not answered), rather than 0 (answered false)
(the handler is from here http://williamdurand.fr/2012/08/02/rest-apis-with-symfony2-the-right-way/ it's just validating the data POSTed against the formtype then persisting)
edit:
I'm not sure that FormTypes can handle a nullable boolean. Tests based on the responses to this question either save false as null or null as false. For now I've decided to stop using the handlers as described in the linked post and instead validate manually then persist directly with the entity manager.
A checkbox by it's nature can only have 2 states, true or false. So not selecting it would only ever be seen as false as opposed to not answered.
I would say the easiest way to achieve what you are after is to use a choice field with true and false as options and an empty value added.
$builder->add('foo_bar', ChoiceType::class, array(
'required' => false,
'choices' => array(
'Yes' => true,
'No' => false,
),
'empty_value' => 'Not Answered',
));
The text can be what ever you want as you are using it in an API rather than a direct form but I guess it makes the values more explicit when you look at it.
Perhaps a checkbox is not the the form field type you need, maybe you need to use a drop-down with 'yes', 'no', 'no answer'
a checkbox by definition can hold one of two values either true or false, you could do some weird stuff in the controller by setting the field to null and then not displaying the checkbox field to the user, but that would break the 'separation of concerns' guideline, but if you absolutely have to use a checkbox, then its gona get messy

Validate a Collection Field Type in Symfony 2 with allowExtraFields=true

I'm trying to validate a collection form field:
$builder->add(
'autor',
'collection',
array(
'type' => 'text',
'options' => array('required' => false),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'error_bubbling' => false
)
);
I use JavaScript, as suggested in the Cookbook, to dynamically add more text fields to the collection. My problem is, that I don't know, how to validate these fields. The collection validator lets me validate specific fields of a collection by their name but not simply every field of it. How can I manage that?
Even cooler would be, if I could check, if at least one of the fields is notBlank instead of forcing it to every field.
Best regards
You can use the "constraints" option defined in form Field Type that are available on all fields.(http://symfony.com/doc/master/reference/forms/types/form.html#constraints).
In your case, you can add your constraint like this:
$builder->add('autor', 'collection', array(
'constraints' => new NotBlank()),
));
(in this case dont forget to include the constraints provided by the Validation component:
use Symfony\Component\Validator\Constraints\NotBlank; ...)
i didnt test but i think with this every input will be validate againts the constraint you assigned to the field, and as you have the option "error_bubbling" as false, an error message should be attached to the invalid element.
--EDIT--
Since you even use the 2.0 version of Symfony i think this solution solves your problem, however I strongly advise you to update to the 2.3 version.
You can create a Form Event Subscriber(http://symfony.com/doc/2.0/cookbook/form/dynamic_form_modification.html) that will be listening the POST_BIND event.(note that Post Bind event is Deprecated since version 2.3 and will be removed in 3.0);
In your subscriber class, you will validate each of your submited authors as you want and add an error to the form if something is wrong.
Your postBind method could be something like this:
public function postBind(DataEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
if (null === $data) {
return;
}
// get the submited values for author
// author is an array
$author = $form['autor']->getData();
// now iterate over the authors and validate what you want
// if you find any error, you can add a error to the form like this:
$form->addError(new FormError('your error message'));
// now as the form have errors it wont pass on the isValid() method
// on your controller. However i think this error wont appear
// next to your invalid author input but as a form error, but with
// this you can unsure that non of the fields will be blank for example.
}
you can check the Symfony2 Form Component API if you have any doubt about a core method.
http://api.symfony.com/2.0/index.html

Resources