为避免为TestChildEntityA和TestChildEntityB定义单独的字段,我在TestOwnerEntity中将baseEntities定义为其父类,这是一个抽象类。我知道既不能在PHP 7中也不能在任何其他编程语言中实例化抽象类,但这不是实例化TestBaseEntity。当我从TestOwnerEntity(控制器中的getActionAB)调用getBaseEntities时,最初收到以下错误,但后来意识到addBaseEntities和removeBaseEntities可能导致相同的问题。如果我将TestOwnerEntity中的“ @var TestBaseEntity []”替换为“ @var TestChildEntityA []”或@var TestChildEntityB [],则getBaseEntities可以正常工作,但这意味着我必须定义两个字段,而不仅仅是一个字段,并且一种我都想避免的get方法。
错误
注意:未定义索引:所有者
$this->switchPersisterContext($offset, $limit);
$criteria = [];
$parameters = [];
$owningAssoc = $this->class->associationMappings[$assoc['mappedBy']]; // Highlighted
$sourceClass = $this->em->getClassMetadata($assoc['sourceEntity']);
$tableAlias = $this->getSQLTableAlias($owningAssoc['inherited'] ?? $this-
>class->name);
这些是我在应用程序中拥有的类:
基础实体
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity()
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(name="type", type="string")
* @ORM\DiscriminatorMap({"testA" = "TestChildEntityA", "testB" = "TestChildEntityB"})
* @ORM\Entity(repositoryClass="App\Repository\TestBaseEntityRepository")
*/
abstract class TestBaseEntity
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
public function getId(): ?int
{
return $this->id;
}
abstract public function getOwner(): TestOwnerEntity;
abstract public function setOwner(TestOwnerEntity $owner): void;
}
子实体A
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="App\Repository\TestChildEntityARepository")
*/
class TestChildEntityA extends TestBaseEntity
{
/**
* @var TestOwnerEntity
* @ORM\ManyToOne(targetEntity="TestOwnerEntity", inversedBy="baseEntities")
* @ORM\JoinColumn(nullable=true)
*/
private $owner;
/**
* @return TestOwnerEntity
*/
public function getOwner(): TestOwnerEntity
{
return $this->owner;
}
/**
* @param TestOwnerEntity $owner
*/
public function setOwner(TestOwnerEntity $owner): void
{
$this->owner = $owner;
}
}
子实体B
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="App\Repository\TestChildEntityBRepository")
*/
class TestChildEntityB extends TestBaseEntity
{
/**
* @var TestOwnerEntity
* @ORM\ManyToOne(targetEntity="TestOwnerEntity", inversedBy="baseEntities")
* @ORM\JoinColumn(nullable=false)
*/
private $owner;
/**
* @return TestOwnerEntity
*/
public function getOwner(): TestOwnerEntity
{
return $this->owner;
}
/**
* @param TestOwnerEntity $owner
*/
public function setOwner(TestOwnerEntity $owner): void
{
$this->owner = $owner;
}
}
所属实体
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="App\Repository\TestOwnerEntityRepository")
*/
class TestOwnerEntity
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
public function getId(): ?int
{
return $this->id;
}
public function __construct()
{
$this->baseEntities = new ArrayCollection();
}
/**
* @var TestBaseEntity[]|ArrayCollection
*
* @ORM\OneToMany(
* targetEntity="TestBaseEntity",
* mappedBy="owner",
* orphanRemoval=true,
* cascade={"persist"}
* )
*/
private $baseEntities;
public function getBaseEntities()
{
return $this->baseEntities;
}
public function addBaseEntities(TestBaseEntity $baseEntity): void
{
$baseEntity->setOwner($this);
if (!$this->baseEntities->contains($baseEntity)) {
$this->baseEntities->add($baseEntity);
}
}
public function removeBaseEntities(TestBaseEntity $baseEntity): void
{
$this->baseEntities->removeElement($baseEntity);
}
}
控制器
<?php
/**
* Created by PhpStorm.
* User: User
* Date: 05/02/2019
* Time: 21:00
*/
namespace App\Controller;
use App\Entity\TestBaseEntity;
use App\Entity\TestChildEntityA;
use App\Entity\TestChildEntityB;
use App\Entity\TestOwnerEntity;
use App\Repository\TestBaseEntityRepository;
use App\Repository\TestChildEntityARepository;
use App\Repository\TestChildEntityBRepository;
use App\Repository\TestOwnerEntityRepository;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class TestController extends AbstractController
{
/**
* @Route("/")
*/
public function indexAction()
{
$owner = new TestOwnerEntity();
$objA = new TestChildEntityA();
$objB = new TestChildEntityB();
$objA->setOwner($owner);
$objB->setOwner($owner);
// Calling addBaseEntities is successful when $owner has been newly instantiated
$owner->addBaseEntities($objA);
$owner->addBaseEntities($objB);
$em = $this->getDoctrine()->getManager();
$em->persist($owner);
$em->persist($objA);
$em->persist($objB);
$em->flush();
return new Response("done");
}
/**
* @Route("/getAB")
*/
public function getActionAB(TestChildEntityBRepository $repo, TestOwnerEntityRepository $ownerrepo)
{
$owner = $ownerrepo->findAll()[0];
// getBaseEntities fails because baseEntities is defined using an abstract class in TestOwnerEntity
$b = $owner->getBaseEntities()[0];
return new Response($b->getId());
}
/**
* @Route("/addA")
*/
public function addActionA(TestOwnerEntityRepository $ownerrepo)
{
$a = new TestChildEntityA();
$owner = $ownerrepo->findAll()[0];
$a->setOwner($owner);
// $owner->addBaseEntities($objA); addBaseEntities fails when $owner is retreived from the database
// $a->setOwner($owner); setOwner is sufficient to add $a to the database but it's best practice to also
// append to the entity array in TestOwnerEntity. Removing the check "$this->baseEntities->contains($baseEntity)"
// in addBaseEntities stops the error.
$em = $this->getDoctrine()->getManager();
$em->persist($owner);
$em->persist($a);
$em->flush();
return new Response($a->getOwner()->getId());
}
/**
* @Route("/delA")
*/
public function delActionA(TestOwnerEntityRepository $ownerrepo, TestChildEntityARepository $arepo)
{
$owner = $ownerrepo->findAll()[0];
// removeBaseEntities also fails
$owner->removeBaseEntities($arepo->findAll()[0]);
$em = $this->getDoctrine()->getManager();
$em->flush();
return new Response("done");
}
}
如果按照我的方式这样做不可行,请提出一个更好的选择。 TestBaseEntity代表用户将在我正在处理的应用程序中接收的通知的类,而子A和B分别是我希望包含在同一列表中的管理通知和论坛通知,因为这没有意义它们位于不同的收件箱中。
编辑:我尝试使用强制转换,但是PHP本身不支持它。