1

我开始怀疑这不起作用,因为在我的用例中它只是不起作用 - 而我错过了一些东西 - 但我必须咨询您的专业知识以确保,并看看是否有人可以提出解决方法.

我有一个多对多的情况,我正在用一个关联类来实现,所以我们在 3 个参与类之间有一对多/多对一的关联。有一个 Interpreter 实体代表一个人,一个 Language 实体代表一种口语(实际上是一个工作语言对,但在这个以英语为中心的应用程序中,该对的一半被理解为英语)。一个解释器可以有多种语言,一种语言是多个解释器的工作语言之一。我们需要管理解释器语言的其他属性,因此需要管理 InterpreterLanguage 类。

当我调用$interpreter->removeInterpreterLanguage($interpreterLanguage);后跟 时$entityManager->flush(),内存中的解释器实体在其$interpreterLanguages集合中的元素如您所料那样少了一个,并且没有抛出错误或异常,但在数据库中发生了以下情况:什么都没有

我已经在 MVC 上下文中尝试过这个,使用 ZendFramework 3 并绑定了字段集,Zend\Form\Form当这让我发疯时,我编写了一个 CLI 脚本来尝试检查问题——结果相同。也许值得注意的是,对于更新标量属性,它工作正常。

我很抱歉没有包含我之前阅读的关于这个问题的讨论的链接——由于某种原因现在找不到它。但我记得有人说它不起作用,因为 Doctrine 在另一边看到 M:1,因此不会删除,你必须说$entityManager->remove($object)完成它。我的实验性 CLI 脚本似乎证实了这一点。不过,我想排除我做错了什么的可能性。

有任何想法吗?解决的建议?

所以这是我的语言实体:

/** module/InterpretersOffice/src/Entity/Language.php */

namespace InterpretersOffice\Entity;

use Doctrine\ORM\Mapping as ORM;
use Zend\Form\Annotation;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Entity class representing a language used by an Interpreter.
 *
 * @Annotation\Name("language")
 * @ORM\Entity(repositoryClass="InterpretersOffice\Entity\Repository\LanguageRepository")
 * @ORM\Table(name="languages",uniqueConstraints={@ORM\UniqueConstraint(name="unique_language",columns={"name"})})
 */
class Language
{
    /**
     * entity id.
     *     
     * @ORM\Id
     * @ORM\GeneratedValue @ORM\Column(type="smallint",options={"unsigned":true})
     */
    protected $id;

    /**
     * name of the language.
     *
     * @ORM\Column(type="string",length=50,nullable=false)
     *
     * @var string
     */
    protected $name;

    /**
     * comments.
     *
     * @ORM\Column(type="string",length=300,nullable=false,options={"default":""})
     *
     * @var string
     */
    protected $comments = '';

    /**
     *
     * @ORM\OneToMany(targetEntity="InterpreterLanguage",mappedBy="language")
     */
    protected $interpreterLanguages;

    /**
     * constructor
     */
    public function __construct()
    {
        $this->interpreterLanguages = new ArrayCollection();
    }
    // setters and getters omitted for brevity

}

这是解释器实体:

<?php
/** module/InterpretersOffice/src/Entity/Interpreter.php */

namespace InterpretersOffice\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;

/**
 * Entity representing an Interpreter.
 *
 * @ORM\Entity(repositoryClass="InterpretersOffice\Entity\Repository\InterpreterRepository")
 * @ORM\Table(name="interpreters")
 */
class Interpreter extends Person
{
    /**
     * entity id.
     *
     * @ORM\Id @ORM\GeneratedValue @ORM\Column(type="smallint",options={"unsigned":true})
     */
    protected $id;

    /**
     * phone number.
     *
     * @ORM\Column(type="string",length=16,nullable=true)
     *
     * @var string
     */
    protected $phone;

    /**
     * date of birth.
     *
     * @ORM\Column(type="date",nullable=true)
     *
     * @var string
     */
    protected $dob;

    /**
     * working languages.
     *
     * @ORM\OneToMany(targetEntity="InterpreterLanguage",mappedBy="interpreter", cascade={"persist", "remove"})
     * 
     *
     * @var ArrayCollection of InterpreterLanguage
     */
    protected $interpreterLanguages;

    /**
     * Constructor.
     */
    public function __construct()
    {
        $this->interpreterLanguages = new ArrayCollection();
    }

    // some boring setters and getters omitted.... 

    /**
     * Add interpreterLanguage.
     *
     * @param InterpreterLanguage $interpreterLanguage
     *
     * @return Interpreter
     */
    public function addInterpreterLanguage(InterpreterLanguage $interpreterLanguage)
    {
        $this->interpreterLanguages->add($interpreterLanguage);
        return $this;
    }

    /**
     * Remove interpreterLanguage.
     *
     * @param \InterpretersOffice\Entity\InterpreterLanguage $interpreterLanguage
     *
     * @return Interpreter
     */
    public function removeInterpreterLanguage(InterpreterLanguage $interpreterLanguage)
    {       

        $this->interpreterLanguages->removeElement($interpreterLanguage);
        //$interpreterLanguage->setInterpreter(null)->setLanguage(null);
        return $this;
    }

    /**
     * Get interpreterLanguages.
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getInterpreterLanguages()
    {
        return $this->interpreterLanguages;
    }

    /*
     because "AllowRemove strategy for DoctrineModule hydrator requires both addInterpreterLanguages and  removeInterpreterLanguages to be defined in InterpretersOffice\Entity\Interpreter entity domain code, but one or both 
     [seemed] to be missing"
     */


    public function addInterpreterLanguages(Collection $interpreterLanguages)
    {
        foreach ($interpreterLanguages as $interpreterLanguage) {

            $interpreterLanguage->setInterpreter($this);
            $this->interpreterLanguages->add($interpreterLanguage);
        }
    }

    public function removeInterpreterLanguages(Collection $interpreterLanguages)
    {
        foreach ($interpreterLanguages as $interpreterLanguage) {

            $this->interpreterLanguages->removeElement($interpreterLanguage);

        }
    }

}

和关联类:

/** module/InterpretersOffice/src/Entity/InterpreterLanguage.php  */

namespace InterpretersOffice\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Entity representing an Interpreter's Language.
 *
 * Technically, it is a language *pair*, but in this system it is understood that
 * the other language of the pair is English. There is a many-to-many relationship
 * between interpreters and languages. But because there is also metadata to record
 * about the language (federal certification), it is implemented as a Many-To-One
 * relationship on either side.
 *
 * @ORM\Entity
 * @ORM\Table(name="interpreters_languages")
 */
class InterpreterLanguage
{
    /**
     * constructor.
     *
     * @param Interpreter $interpreter
     * @param Language    $language
     *
     * @todo a lifecycle callback to ensure certified languages have a boolean
     * $federalCertification set
     */
    public function __construct(
        Interpreter $interpreter = null,
        Language $language = null
    ) {
        if ($interpreter) {
            $this->setInterpreter($interpreter);
        }
        if ($language) {
            $this->setLanguage($language);
        }
    }

    /**
     * The Interpreter who works in this language.
     *
     * @ORM\ManyToOne(targetEntity="Interpreter",inversedBy="interpreterLanguages")
     * @ORM\Id
     *
     * @var Interpreter
     */
    protected $interpreter;

    /**
     * The language in which this interpreter works.
     *
     * @ORM\ManyToOne(targetEntity="Language",inversedBy="interpreterLanguages")
     * @ORM\Id
     *
     * @var Language
     */
    protected $language;

    /**
     * Whether the Interpreter holds federal court interpreter certification in this language.
     *
     * The only certified languages in the US District Court system are Spanish,
     * Navajo and Haitian Creole. Of these, only the Spanish certification
     * program is active. This field should be a boolean for the certified
     * languages and null for everything else.
     *
     * @link http://www.uscourts.gov/services-forms/federal-court-interpreters/federal-court-interpreter-certification-examination the federal court certification program
     *
     * @ORM\Column(name="federal_certification",type="boolean",nullable=true)
     *
     * @var bool
     */
    protected $federalCertification;

    /**
     * Set interpreter.
     *
     * @param \InterpretersOffice\Entity\Interpreter $interpreter
     *
     * @return InterpreterLanguage
     */
    public function setInterpreter(Interpreter $interpreter = null)
    {
        $this->interpreter = $interpreter;

        return $this;
    }

    /**
     * Get interpreter.
     *
     * @return Interpreter
     */
    public function getInterpreter()
    {
        return $this->interpreter;
    }

    /**
     * Set language.
     *
     * @param Language $language
     *
     * @return InterpreterLanguage
     */
    public function setLanguage(Language $language = null)
    {
        $this->language = $language;

        return $this;
    }

    /**
     * Get language.
     *
     * @return Language
     */
    public function getLanguage()
    {
        return $this->language;
    }

    /**
     * Set federalCertification.
     *
     * @param bool $federalCertification
     *
     * @return InterpreterLanguage
     */
    public function setFederalCertification($federalCertification)
    {
        $this->federalCertification = $federalCertification;

        return $this;
    }

    /**
     * Get federalCertification.
     *
     * @return bool
     */
    public function getFederalCertification()
    {
        return $this->federalCertification;
    }
}

为简洁起见,我将省略 Form 和 Fieldset 类的代码——它们似乎工作正常(看起来也很有品位。谢谢 Bootstrap)。我加载表单,删除其中一个 InterpreterLanguages 并提交......这是控制器操作:

/**
 * updates an Interpreter entity.
 */
public function editAction()
{
    $viewModel = (new ViewModel())
            ->setTemplate('interpreters-office/admin/interpreters/form.phtml')
            ->setVariable('title', 'edit an interpreter');
    $id = $this->params()->fromRoute('id');

    $entity = $this->entityManager->find('InterpretersOffice\Entity\Interpreter', $id);
    if (!$entity) {
        return $viewModel->setVariables(['errorMessage' => "interpreter with id $id not found"]);
    }
    $form = new InterpreterForm($this->entityManager, ['action' => 'update']);
    $form->bind($entity);
    $viewModel->setVariables(['form' => $form, 'id' => $id ]);

    $request = $this->getRequest();
    if ($request->isPost()) {
        $form->setData($request->getPost());
        if (!$form->isValid()) {
            return $viewModel;
        }
        $this->entityManager->flush();
        $this->flashMessenger()
              ->addSuccessMessage(sprintf(
                  'The interpreter <strong>%s %s</strong> has been updated.',
                  $entity->getFirstname(),
                  $entity->getLastname()
              ));
        // dump the entity and see how it looksa after update
        echo "NOT redirecting. entity:<pre>";
        \Doctrine\Common\Util\Debug::dump($entity); echo "</pre>";
        //$this->redirect()->toRoute('interpreters');
    } else { 
        // dump the entity fresh from the database
        echo "loaded:<pre> "; \Doctrine\Common\Util\Debug::dump($entity);echo "</pre>";}

    return $viewModel;
}

同样,数据在转储到屏幕时看起来是正确的,但是您重新加载表单,并且集合中的元素与以前一样多。

谢谢!

4

1 回答 1

0

在 Interpreter.php 中,orphanRemoval=true !!

/**
 * working languages.
 *
 * @ORM\OneToMany(targetEntity="InterpreterLanguage",mappedBy="interpreter", 
 * cascade={"persist", "remove"},orphanRemoval=true)
 *
 * @var ArrayCollection of InterpreterLanguage
 */
protected $interpreterLanguages;
于 2017-01-13T22:50:11.690 回答