Update two tables from one form with ZF2 and Doctrine

三世轮回 提交于 2019-12-08 10:34:38

问题


I am looking for a tutorial or example module that uses ZF2 and Doctrine to join two or more tables, creates a form, and updates all tables with form input/changes. (It would be an added bonus to find something that includes a method to add records in associated tables when the query doesn’t find records to join.)

The pattern I’m trying to replicate in ZF2/Doctrine is something like this: perhaps there is a members table and a personal_info table. While there is a one-to-one relationship between the tables, we’ll only need to log personal information for a fraction of the members, so to avoid burdening the system we will only add matching records to the personal_info table as needed. Our form will include boxes to update data from both tables: a phone input would update a record from the members table and a spouse input would update a record from the personal_info table.

A php version might follow these steps to construct the form: 1) query the personal_info table to determine whether a record exists for a user-supplied member id; 2) if it doesn’t exist, add a new record to personal_info; 3) create a query joining the tables; and 4) create a form populated with data from the query. The action triggered by a user’s update of the form would have two steps: 1) update the members table, and 2) update the personal_info table.

In searching for tutorials and examples, I haven’t come across anything that updates two tables from one form or that adds a missing record to a joined table when needed.

EDIT:

Following Sam's suggestion, I have followed the examples in the DoctrineModule but I can’t make it work. I’ve set up the Entities, Fieldsets, Forms, Views and Controller, but data doesn’t get passed from the database to the rendered form and back. Neither the update form nor the create form will update the database; and database data is not fed to the value attributes of the update form elements.

I know that data is extracted from the database because putting a non-existent id in the url router gives an error. I can't isolate whether there is a problem between the entities and the fieldsets, between the fieldsets and the forms, in the controller or in the view(s). Here are my files:

Member Entity:

<?php

namespace Members\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Members\Entity\PersonalInfo;

/**
 * Members
 *
 * @ORM\Entity
 * @ORM\Table(name="members")
 * @property string $memberFirstName
 * @property string $memberLastName
 * @property int $memberID
 */
class Member
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer");
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $memberID;

    /**
     * @ORM\Column(type="string")
     */
    protected $memberFirstName;

    /**
     * @ORM\Column(type="string")
     */
    protected $memberLastName;

    /**
     * @ORM\OneToMany(targetEntity="Members\Entity\PersonalInfo", mappedBy="member", cascade={"persist"})
     */
    protected $personalInfo;

    /**
     * initialize collections
     */
    public function __construct()
    {
        $this->personalInfo = new ArrayCollection();
    }

     /**
     * Get MemberID
     *
     * @return integer
     */
    public function getMemberID()
    {
        return $this->memberID;
    }

    /**
     * Get MemberLastName
     *
     * @return string
     */
    public function getMemberLastName()
    {
        return $this->memberLastName;
    }

    /**
     * Set MemberLastName
     *
     * @param string $memberLastName
     */
    public function setMemberLastName($memberLastName)
    {
        $this->memberLastName = $memberLastName;

        return $this;
    }

    /**
     * Get MemberFirstName
     *
     * @return string
     */
    public function getMemberFirstName()
    {
        return $this->memberFirstName;
    }

    /**
     * Set MemberFirstName
     *
     * @param string $memberFirstName
     */
    public function setMemberFirstName($memberFirstName)
    {
        $this->memberFirstName = $memberFirstName;

        return $this;
    }

    /**
     * @param Collection $personalInfo
     */
    public function addPersonalInfo(Collection $personalInfo)
    {
        foreach ($personalInfo as $memberPersonalInfo) {
            $memberPersonalInfo->setMember($this);
            $this->personalInfo->add($memberPersonalInfo);
        }
    }

    /**
     * @param Collection $personalInfo
     */
    public function removePersonalInfo(Collection $personalInfo)
    {
        foreach ($personalInfo as $memberPersonalInfo) {
            $memberPersonalInfo->setMember(null);
            $this->personalInfo->removeElement($memberPersonalInfo);
        }
    }

    /**
     * @return Collection
     */
    public function getPersonalInfo()
    {
        return $this->personalInfo;
    }

}

PersonalInfo Entity:

<?php

namespace Members\Entity;

use Doctrine\ORM\Mapping as ORM;
use Members\Entity\Member;

/**
 * Personal Info
 *
 * @ORM\Entity
 * @ORM\Table(name="members_personal")
 * @property string $spouse
 * @property string $hobbies
 * @property int $memberID
 * @property int $personalInfoID
 */
class PersonalInfo
{
    /**
     * @ORM\Column(type="integer");
     */
    protected $memberID;

    /**
     * @ORM\Id
     * @ORM\Column(type="integer");
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $personalInfoID;

    /**
     * @ORM\ManyToOne(targetEntity="Members\Entity\Member", inversedBy="personalInfo")
     * @ORM\JoinColumn(name="memberID", referencedColumnName="memberID")
     */
    protected $member;

    /**
     * @ORM\Column(type="string")
     */
    protected $spouse;

    /**
     * @ORM\Column(type="string")
     */
    protected $hobbies;


     /**
     * Get PersonalInfoID
     *
     * @return integer
     */
    public function getPersonalInfoID()
    {
        return $this->personalInfoID;
    }

    /**
     * Allow null to remove association
     *
     * @param Member $member
     */
    public function setMember(Member $member = null)
    {
        $this->member = $member;
    }

    /**
     * @return Member
     */
    public function getMember()
    {
        return $this->member;
    }

    /**
     * Set Spouse
     *
     * @param string $spouse
     */
    public function setSpouse($spouse)
    {
        $this->spouse = $spouse;
    }

    /**
     * Get Spouse
     *
     * @return string
     */
    public function getSpouse()
    {
        return $this->spouse;
    }

    /**
     * Set Hobbies
     *
     * @param  string  $hobbies
     */
    public function setHobbies($hobbies)
    {
        $this->hobbies = $hobbies;
    }

    /**
     * Get Hobbies
     *
     * @return string
     */
    public function getHobbies()
    {
        return $this->hobbies;
    }

}

MemberFieldset:

<?php

namespace Members\Form;

use Members\Entity\Member;
use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use Zend\Form\Fieldset;
use Zend\InputFilter\InputFilterProviderInterface;

class MemberFieldset extends Fieldset implements InputFilterProviderInterface
{
    public function __construct(ObjectManager $objectManager)
    {
        parent::__construct('member');

        $this->setHydrator(new DoctrineHydrator($objectManager, 'Members\Entity\Member'))
             ->setObject(new Member());

        $this->add(array(
            'type' => 'Zend\Form\Element\Text',
            'name' => 'memberID',
            'attributes' => array(
                'type'  => 'hidden',
            ),
        ));

        $this->add(array(
            'type' => 'Zend\Form\Element\Text',
            'name' => 'memberLastName',
            'attributes' => array(
                'required' => 'required',
                'type'  => 'text',
            ),
            'options' => array(
                'label' => 'Last Name',
            ),
        ));

        $this->add(array(
            'type' => 'Zend\Form\Element\Text',
            'name' => 'memberFirstName',
            'attributes' => array(
                'required' => 'required',
                'type'  => 'text',
            ),
            'options' => array(
                'label' => 'First Name',
            ),
        ));

        $personalInfoFieldset = new PersonalInfoFieldset($objectManager);
        $this->add(array(
            'type'    => 'Zend\Form\Element\Collection',
            'name'    => 'personalInfo',
            'options' => array(
                'count'           => 1,
                'target_element' => $personalInfoFieldset
            )
        ));

    }

    public function getInputFilterSpecification()
    {
        return array(
            'memberID' => array(
                'required' => true
            ),
        );
        return array(
            'memberLastName' => array(
                'required' => true
            ),
        );
        return array(
            'memberFirstName' => array(
                'required' => true
            ),
        );
    }

}

PersonalInfoFieldset:

<?php

namespace Members\Form;

use Members\Entity\PersonalInfo;
use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use Zend\Form\Fieldset;
use Zend\InputFilter\InputFilterProviderInterface;

class PersonalInfoFieldset extends Fieldset implements InputFilterProviderInterface
{
    public function __construct(ObjectManager $objectManager)
    {
        parent::__construct('personal-info');

        $this->setHydrator(new DoctrineHydrator($objectManager, 'Members\Entity\PersonalInfo'))
             ->setObject(new PersonalInfo());

        $this->add(array(
            'type' => 'Zend\Form\Element\Text',
            'name' => 'personalInfoID',
            'attributes' => array(
                'type'  => 'hidden',
            ),
        ));

        $this->add(array(
            'name' => 'spouse',
            'type' => 'Zend\Form\Element\Text',
            'attributes' => array(
                'required' => 'required',
                'type'  => 'text',
            ),
            'options' => array(
                'label' => 'Page Title',
            ),
        ));

        $this->add(array(
            'name' => 'hobbies',
            'type' => 'Zend\Form\Element\Text',
            'attributes' => array(
                'required' => 'required',
                'type'  => 'text',
            ),
            'options' => array(
                'label' => 'Page Name',
            ),
        ));

    }
    public function getInputFilterSpecification()
    {
        return array(
            'personalInfoID' => array(
                'required' => true
            ),
        );
        return array(
            'spouse' => array(
                'required' => true
            ),
        );
        return array(
            'hobbies' => array(
                'required' => true
            ),
        );
    }

}

CreateMemberForm:

<?php

namespace Members\Form;

use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use Zend\Form\Form;

class CreateMemberForm extends Form
{
    public function __construct(ObjectManager $objectManager)
    {
        parent::__construct('update-member-form');

        // The form will hydrate an object of type "Member"
        $this->setHydrator(new DoctrineHydrator($objectManager, 'Members\Entity\Member'));

        // Add the user fieldset, and set it as the base fieldset
        $memberFieldset = new MemberFieldset($objectManager);
        $memberFieldset->setUseAsBaseFieldset(true);
        $this->add($memberFieldset);

        // submit elements
        $this->setAttribute('method', 'post');

        $this->add(array(
            'name' => 'memberID',
            'attributes' => array(
                'type'  => 'hidden',
            ),
        ));
        $this->add(array(
            'name' => 'memberLastName',
            'attributes' => array(
                'id'  => 'memberLastName',
                'type'  => 'text',
                'class' => 'col-lg-10',
            ),
            'options' => array(
                'label' => 'Last Name',
                'label_attributes' => array(
                    'class'  => 'col-lg-2 control-col-label'
                ),
            ),
        ));

        $this->add(array(
            'name' => 'memberFirstName',
            'attributes' => array(
                'id'  => 'memberFirstName',
                'type'  => 'text',
                'class' => 'col-lg-10',
            ),
            'options' => array(
                'label' => 'First Name',
                'label_attributes' => array(
                    'class'  => 'col-lg-2 control-col-label'
                ),
            ),
        ));

        $this->add(array(
            'name' => 'spouse',
            'attributes' => array(
                'id'  => 'spouse',
                'type'  => 'text',
                'class' => 'col-lg-10',
            ),
            'options' => array(
                'label' => 'Spouse',
                'label_attributes' => array(
                    'class'  => 'col-lg-2 control-col-label'
                ),
            ),
        ));

        $this->add(array(
            'name' => 'submit',
            'attributes' => array(
                'id'  => 'submit',
                'type'  => 'submit',
                'value' => 'Go',
                'id' => 'submitbutton',
            ),
        ));

        // Optionally set your validation group here
    }

}

UpdateMemberForm:

<?php

namespace Members\Form;

use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use Zend\Form\Form;

class UpdateMemberForm extends Form
{
    public function __construct(ObjectManager $objectManager)
    {
        parent::__construct('update-member-form');

        // The form will hydrate an object of type "Member"
        $this->setHydrator(new DoctrineHydrator($objectManager, 'Members\Entity\Member'));

        // Add the user fieldset, and set it as the base fieldset
        $memberFieldset = new MemberFieldset($objectManager);
        $memberFieldset->setUseAsBaseFieldset(true);
        $this->add($memberFieldset);

        // submit elements
        $this->setAttribute('method', 'post');

        $this->add(array(
            'name' => 'memberID',
            'attributes' => array(
                'type'  => 'hidden',
            ),
        ));
        $this->add(array(
            'name' => 'memberLastName',
            'attributes' => array(
                'id'  => 'memberLastName',
                'type'  => 'text',
                'class' => 'col-lg-9',
            ),
            'options' => array(
                'label' => 'Last Name',
                'label_attributes' => array(
                    'class'  => 'col-lg-2 control-col-label'
                ),
            ),
        ));

        $this->add(array(
            'name' => 'memberFirstName',
            'attributes' => array(
                'id'  => 'memberFirstName',
                'type'  => 'text',
                'class' => 'col-lg-9',
            ),
            'options' => array(
                'label' => 'First Name',
                'label_attributes' => array(
                    'class'  => 'col-lg-2 control-col-label'
                ),
            ),
        ));

        $this->add(array(
            'name' => 'spouse',
            'attributes' => array(
                'id'  => 'spouse',
                'type'  => 'text',
                'class' => 'col-lg-9',
            ),
            'options' => array(
                'label' => 'Spouse',
                'label_attributes' => array(
                    'class'  => 'col-lg-2 control-col-label'
                ),
            ),
        ));

        $this->add(array(
            'name' => 'submit',
            'attributes' => array(
                'id'  => 'submit',
                'type'  => 'submit',
                'value' => 'Go',
                'id' => 'submitbutton',
            ),
        ));

        // Optionally set your validation group here
    }



}

MemberController:

<?php

namespace Members\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Members\Entity\Member;
use Members\Form\CreateMemberForm;
use Members\Form\UpdateMemberForm;
use Doctrine\ORM\EntityManager;

class MemberController extends AbstractActionController
{
    /**
     * @var Doctrine\ORM\EntityManager
     */
    protected $em;

    public function setEntityManager(EntityManager $em)
    {
        $this->em = $em;
    }

    public function getEntityManager()
    {
        if (null === $this->em) {
            $this->em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
        }
        return $this->em;
    }

    // ... //

    public function createAction()
    {
        // Get ObjectManager from the ServiceManager
        $objectManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');

        // Create the form and inject the ObjectManager
        $form = new CreateMemberForm($objectManager);

        // Create a new, empty entity and bind it to the form
        $member = new Member();
        $form->bind($member);

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

            if ($form->isValid()) {
                $objectManager->persist($member);
                $objectManager->flush();
            }
        }

        return array('form' => $form);
    }

    public function updateAction()
    {
        $memberID = (int)$this->getEvent()->getRouteMatch()->getParam('memberID');
        if (!$memberID) {
            return $this->redirect()->toRoute('members', array('action'=>'create'));
        }
        $member = $this->getEntityManager()->find('Members\Entity\Member', $memberID);

        // Get your ObjectManager from the ServiceManager
        $objectManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');

        // Create the form and inject the ObjectManager
        $form = new UpdateMemberForm($objectManager);
        $form->setBindOnValidate(false);
        $form->bind($member);
        $form->get('submit')->setAttribute('label', 'Update');

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

                // Redirect to list of members
                return $this->redirect()->toRoute('members');
            }
        }

        return array(
            'memberID' => $memberID,
            'form' => $form,
        );
    }

    // ... //

}

update.phtml:

<?php
$title = 'Update Member';
$this->headTitle($title);
?>
<h1><?php echo $this->escapeHtml($title); ?></h1>

<?php
$form = $this->form;
$form->setAttribute('action', 
    $this->url('members', array('action' => 'update', 'memberID'=>$this->memberID)));
$form->prepare();

echo $this->form()->openTag($form);
echo $this->formHidden($form->get('memberID'));
echo $this->formRow($form->get('memberFirstName')) . "<br clear='both'/>";
echo $this->formRow($form->get('memberLastName')) . "<br clear='both'/>";
echo $this->formRow($form->get('spouse')) . "<br clear='both'/>";
echo $this->formInput($form->get('submit'));
echo $this->form()->closeTag($form);

回答1:


The two tables have a relationship so the parent object is still member I assume. With this in mind you still have to create two Fieldset elements. One that matches the structure for a member and the other one that matches the data for personal_info. The later being added as a sub-fieldset onto the MemberFieldset.

That's actually all there is to it, the DoctrineObject (Hydrator) should be able to take care about the ID mapping if it's a new entry. If it's an edit-entry the ID data is there anyways. It's not really that different of a deal than the examples given by the DoctrineModule /docs.



来源:https://stackoverflow.com/questions/22648186/update-two-tables-from-one-form-with-zf2-and-doctrine

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!