我开始怀疑这不起作用,因为在我的用例中它只是不起作用 - 而我错过了一些东西 - 但我必须咨询您的专业知识以确保,并看看是否有人可以提出解决方法.
我有一个多对多的情况,我正在用一个关联类来实现,所以我们在 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;
}
同样,数据在转储到屏幕时看起来是正确的,但是您重新加载表单,并且集合中的元素与以前一样多。
谢谢!