Skip to content

Method for updating Entity not designed for using ManyToMany annotation #30

@webdevilopers

Description

@webdevilopers

I am extending my User entity with an attribute using a ManyToMany association.
In my example I use "costCenters" but you can think of it as the already existing "roles" attribute.

User entity:

    /**
     * @var \Doctrine\Common\Collections\Collection
     * @ORM\ManyToMany(targetEntity="Application\Entity\Role")
     * @ORM\JoinTable(name="user_role_linker",
     *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")}
     * )
     */
    protected $roles;

    /**
     * @var \Doctrine\Common\Collections\Collection
     * @ORM\ManyToMany(targetEntity="Application\Entity\CostCenter")
     * @ORM\JoinTable(name="user_costCenter",
     *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="user_id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="costCenter_id", referencedColumnName="id")}
     * )
     */
    private $costCenters;

    public function getCostCenters() {
        return $this->costCenters;
    }

    public function setCostCenters($costCenters) {
        $this->costCenters = $costCenters;
    }

Extending the form in my _Module.php_:

    public function onBootstrap($e)
    {
        $app = $e->getParam('application');
        // $em is a Zend\EventManager\SharedEventManager
        $em  = $app->getEventManager()->getSharedManager();

        $em->attach('ZfcUserAdmin\Form\EditUser', 'init', function($e) {
            // $form is a ZfcUser\Form\Register
            $form = $e->getTarget();

            $sm = $form->getServiceManager();
            $om = $sm->get('Doctrine\ORM\EntityManager');

            #$form->setHydrator(new \DoctrineORMModule\Stdlib\Hydrator\DoctrineEntity($om, 'Application\Entity\User'));

            $form->add(array(
                'name' => 'costCenters',
                'type' => 'DoctrineModule\Form\Element\ObjectMultiCheckbox',
                'options' => array(
                    'label' => 'Access to costcenters',
                    'object_manager' => $om,
                    'target_class'   => 'Application\Entity\CostCenter',
                    'property'       => 'id',
                ),
            ));
        });
    }

I already inserted some rows in my database and the edit form is populated correctely with these existing costcenters.

When editing and saving I get these warnings / errors:
Warning: spl_object_hash() expects parameter 1 to be object, string given in /vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php on line 1375*

exception 'Doctrine\ORM\ORMException' with message 'Found entity of type on association Application\Entity\User#costCenters, but expecting Application\Entity\CostCenter' in /vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:783

I think the configuration of entities and form are correct. It looks like the method to update the user entity in Service/User.php l. 78 ff. causes a problem:

        // first, process all form fields
        foreach ($data as $key => $value) {
            if ($key == 'password') continue;

            $setter = $this->getAccessorName($key);
            if (method_exists($user, $setter)) call_user_func(array($user, $setter), $value);
        }

My posted value for costCenters will be an array of strings including the IDs.
It looks like the entity manager will ony receive these strings since it doesn't know they have to be "hydrated" to find the related objects / entities.

Normally I would bind the object to Zend_Form and then a hydrator will do this in order to correctely persist the entity, e.g.:

        $id = /*(int)*/ $this->params('id', null);

        $em = $this->getEntityManager();

        $timeDataStatus = $em->find('Application\Entity\TimeDataStatus', $id);

        $formManager = $this->serviceLocator->get('FormElementManager');
        $form    = $formManager->get('CreateTimeDataStatus');
        $form->bind($timeDataStatus);

        $request = $this->getRequest();
        if ($request->isPost()) {
            $form->setData($request->getPost());

            if ($form->isValid()) {
                $em->persist($timeDataStatus);
                $em->flush();
            }
        }

Since saving multiple roles will probably be a use case for future admin forms can we achieve a solution here?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions