使用ZF2和Doctrine从一个表单更新两个表

时间:2014-03-25 23:05:26

标签: forms orm doctrine-orm zend-framework2 one-to-one

我正在寻找一个教程或示例模块,它使用ZF2和Doctrine连接两个或多个表,创建表单,并使用表单输入/更改更新所有表。 (当查询找不到要加入的记录时,找到包含在关联表中添加记录的方法的东西将是一个额外的好处。)

我试图在ZF2 / Doctrine中复制的模式是这样的:可能有一个members表和一个personal_info表。虽然表之间存在一对一的关系,但我们只需记录一小部分成员的个人信息,因此为了避免给系统带来负担,我们只会将匹配的记录添加到personal_info表中如所须。我们的表单将包含用于更新两个表中数据的框:phone输入将更新members表中的记录,spouse输入将更新来自personal_info的记录表

php版本可能会按照以下步骤构建表单:1)查询personal_info表以确定是否存在用户提供的member id的记录; 2)如果它不存在,则向personal_info添加新记录; 3)创建连接表的查询; 4)创建一个填充了查询数据的表单。用户更新表单触发的操作将包含两个步骤:1)更新members表,2)更新personal_info表。

在搜索教程和示例时,我没有遇到任何从一个表单更新两个表或在需要时将缺失记录添加到联接表的任何内容。

修改

根据Sam的建议,我已经按照DoctrineModule中的示例进行了操作,但我无法使其工作。我已经设置了实体,字段集,表单,视图和控制器,但数据不会从数据库传递到渲染表单并返回。更新表单和创建表单都不会更新数据库;并且数据库数据不会被提供给更新表单元素的值属性。

我知道数据是从数据库中提取的,因为在url路由器中放置一个不存在的id会产生错误。我无法隔离实体和字段集之间,字段集和表单之间,控制器或视图中是否存在问题。这是我的文件:

会员实体:

<?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实体:

<?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 个答案:

答案 0 :(得分:0)

这两个表有一个关系,所以我假设父对象仍然是member。考虑到这一点,您仍然需要创建两个Fieldset元素。一个匹配member的结构,另一个匹配personal_info的数据。后者作为子字段集添加到MemberFieldset

实际上它就是它的全部内容,DoctrineObject(Hydrator)如果是新条目,应该能够关注ID映射。如果是编辑条目,则无论如何都会存在ID数据。与DoctrineModule /docs给出的示例相比,这并不是真正的交易。