Zend Framework 2 Doctrine 2 one-to-many checkbox hydration

2.9k Views Asked by At

I have a ManyToMany that I broke into OneToMany and ManyToOne relationship. I want to build a form that has checkboxes instead of collection, and I am using the 'DoctrineObject' hydrator, but it does not work and I don't know what is going wrong.

I removed from my code below all of the other not related fields.

Role Entity:

/**
 * @orm\Entity
 * @orm\Table(name="roles")
 */
class RolesEntity extends HemisEntity {
    /**
     * @orm\Id
     * @orm\Column(type="integer");
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    protected $id;
    
    /**
     * @orm\Column(name="role_code",type="string")
     */
    protected $roleCode;

    /**
     * @orm\OneToMany(targetEntity="RolesPermissionsEntity", mappedBy="role", cascade={"persist"})
     */
    protected $rolePermissions;

    public function __construct()
    {
        $this->rolePermissions = new ArrayCollection();
    }

    public function setRolePermissions($rolePermissions)
    {
        $this->rolePermissions = $rolePermissions;
        return $this;
    }
    
    public function addRolePermissions(Collection $rolePermissions)
    {
        foreach ($rolePermissions as $rolePermission) {
            $rolePermission->setRole($this);
            $this->rolePermissions->add($rolePermission);
        }
    }
    
    public function removeRolePermissions(Collection $rolePermissions)
    {
        foreach ($rolePermissions as $rolePermission) {
            $rolePermission->setRole(null);
            $this->rolePermissions->removeElement($rolePermission);
        }
    }
    
    public function getRolePermissions()
    {
        return $this->rolePermissions;
    }
}

The ManyToMany table entity (it has more fields and so I broke it):

    /**
 * @orm\Entity
 * @orm\Table(name="roles_permissions")
 */
class RolesPermissionsEntity extends HemisEntity {
    /**
     * @orm\Id
     * @orm\Column(type="integer");
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    protected $id;
    
    /**
     * @orm\ManyToOne(targetEntity="RolesEntity", inversedBy="rolePermissions")
     * @orm\JoinColumn(name="role_id", referencedColumnName="id")
     **/
    protected $role;
    
    /**
     * @orm\ManyToOne(targetEntity="PermissionsEntity", inversedBy="permissionRoles")
     * @orm\JoinColumn(name="permission_id", referencedColumnName="id")
     **/
    protected $permission;
    
    public function setRole($role)
    {
        $this->role = $role;
        return $this;
    }
    
    public function getRole()
    {
        return $this->role;
    }

    public function setPermission($permission)
    {
        $this->permission = $permission;
        return $this;
    }

    public function getPermission()
    {
        return $this->permission;
    }
}

My form look like this:

class RoleForm extends Form implements InputFilterProviderInterface
{
    public function __construct(ObjectManager $objectManager)
    {
        parent::__construct('role');

        $this->setHydrator(new DoctrineHydrator($objectManager))
             ->setObject(new RolesEntity());

        $this->add(array(
            'type' => 'Zend\Form\Element\Hidden',
            'name' => 'id'
        ));

        $this->add(array(
            'type'    => 'Zend\Form\Element\Text',
            'name'    => 'roleCode',
            'options' => array(
                'label' => 'Role Code'
            ),
        ));

        $this->add(array(
            'name' => 'rolePermissions',
            'type' => 'DoctrineModule\Form\Element\ObjectMultiCheckbox',
            'options' => array(
                'label' => 'Permissions',
                'object_manager' => $objectManager,
                'target_class'   => 'Hemis\Fnd\PermissionsEntity',
                'property'       => 'permissionDesc'
            ),
        ));
        
        $this->add(array(
            'name' => 'submit',
            'type'  => 'Submit',
            'attributes' => array(
                'value' => 'Submit',
            ),
        ));
    }

    public function getInputFilterSpecification()
    {
        return array(
            'roleCode' => array(
                'required' => false
            ),
            'rolePermissions' => array(
                'required' => true
            )
        );
    }
}

The problem is that when I dump the $role it does not contain any rolePermissions and even though they are passed from the form they are just not hydrated into the object.

What is wrong with my code? Is there a better way to do that using checkboxes?

2

There are 2 best solutions below

0
On
class RoleForm extends Form implements InputFilterProviderInterface
{
    public function __construct(ObjectManager $objectManager)
    {
        // ...

        $this->add(array(
            'name' => 'rolePermissions',
            'type' => 'Zend\Form\Element\Collection',
            'options' => array(
                'label' => 'Role Permissions',
                'count' => 0,
                'should_create_template' => true,
                'allow_add' => true,
                'target_element' => array(
                    'type' => 'Zend\Form\Fieldset',
                    'options' => array(
                        'use_as_base_fieldset' => true
                    ),
                    'elements' => array(
                        // add form fields for the properties of the RolesPermissionsEntity class here
                        array(
                            'name' => 'id',
                            'type' => 'Zend\Form\Element\Hidden',
                        ),
                        array(
                            'name' => 'role',
                            'type' => 'Zend\Form\Element\Checkbox',
                            // other options
                        ),
                        // ...
                    ),
                ),
            ),
        ));

        // ...
    }

    // ...
}
0
On

you're incorrectly handling rolePermissions. when using the DoctrineHydrator, you need to make sure that the field is property configured to handle the association with RolesPermissionsEntity

class RoleForm extends Form implements InputFilterProviderInterface
{
    public function __construct(ObjectManager $objectManager)
    {
        parent::__construct('role');

        $this->setHydrator(new DoctrineHydrator($objectManager))
             ->setObject(new RolesEntity());

        $this->add(array(
            'type' => 'Zend\Form\Element\Hidden',
            'name' => 'id'
        ));

        $this->add(array(
            'type'    => 'Zend\Form\Element\Text',
            'name'    => 'roleCode',
            'options' => array(
                'label' => 'Role Code'
            ),
        ));

        $this->add(array(
            'name' => 'rolePermissions',
            'type' => 'DoctrineModule\Form\Element\ObjectMultiCheckbox',
            'options' => array(
                'label' => 'Permissions',
                'object_manager' => $objectManager,
                'target_class'   => 'Hemis\Fnd\RolesPermissionsEntity', // Update the target class to RolesPermissionsEntity
                'property'       => 'permission', // Update the property to permission
                'is_method'      => true, // Add this line
                'find_method'    => array( // Add this line
                    'name'   => 'findPermissionsForRole', // Replace with your custom method name
                    'params' => array(
                        'criteria' => array('role' => $this->getObject()), // Use the getObject() method to get the current RolesEntity object
                    ),
                ),
            ),
        ));

        $this->add(array(
            'name' => 'submit',
            'type'  => 'Submit',
            'attributes' => array(
                'value' => 'Submit',
            ),
        ));
    }

    public function getInputFilterSpecification()
    {
        return array(
            'roleCode' => array(
                'required' => false
            ),
            'rolePermissions' => array(
                'required' => true
            )
        );
    }
}