doctrine / DoctrineModule

Doctrine Module for Laminas
http://www.doctrine-project.org/projects/doctrine-module.html
MIT License
398 stars 269 forks source link

persisting does not occur when ObjectMultiCheckbox value is not set #652

Closed cbichis closed 2 years ago

cbichis commented 6 years ago

Hi,

I am using Annotations with ZF3 and Doctrine 2.5.

For a ManyToMany (or other types of associations) if the POST value sent for a ObjectMultiCheckbox is unset (as no value been selected) there is no persistence.

Of course, I can manually set the value to empty array, but it looks like a hack...

driehle commented 3 years ago

When no object from an ObjectMultiCheckbox is selected, that key is not present in the POST data at all. For example, if the name of your element was mySelectCheckboxes, then there would be no such key in $_POST. This, btw, is an general issue of an HTML checkbox. If it is not selected, no data is sent.

If there is no data, the hydrator doesn't do anything. This is because otherwise you wouldn't be able to hydrate partial objects, i.e. you would always need to have all fields of the entity in your form.

Fortunatly, Laminas provides an option use_hidden_element which automatically renders a hidden element before the checkbox, ensuring that data also if the checkbox is not selected. See the docs of Laminas Checkbox. This is, however, not documented in Laminas' MultiCheckbox, but since it extends from Checkbox, it has the same feature.

The following works for me:

$this->add([
    'type' => ObjectMultiCheckbox::class,
    'name' => 'roles',
    'options' => [
        'label' => '',
        'object_manager' => $this->getObjectManager(),
        'target_class' => UserRole::class,
        'find_method' => [
            'name' => 'findAll',
        ],
        'label_generator' => function (UserRole $role) {
            if ($role->getLdapId()) {
                return sprintf(
                    '%s<br><small>LDAP group: %s</small>',
                    htmlspecialchars($role->getTitle()),
                    htmlspecialchars($role->getLdapId())
                );
            }

            return htmlspecialchars($role->getTitle());
        },
        'option_attributes' => [
            'id' => function (UserRole $role) {
                return 'option-role-' . $role->getId();
            },
        ],
        'use_hidden_element' => true,
        'label_options' => [
            'disable_html_escape' => true,
        ],
    ],
]);

Let me know if that works for you as well.