Orm Doctrine2:继承类的有效映射
我在弄清楚如何使用Doctrine2配置类的映射时遇到了一个问题 假设我有这些表格:Orm Doctrine2:继承类的有效映射,orm,doctrine-orm,symfony,Orm,Doctrine Orm,Symfony,我在弄清楚如何使用Doctrine2配置类的映射时遇到了一个问题 假设我有这些表格: Address table --------------------- - id - civic_no - road - state - country PersonnalAddress table --------------------- - id - base_address_id - type - is_primary BusinessAddress table ----
Address table
---------------------
- id
- civic_no
- road
- state
- country
PersonnalAddress table
---------------------
- id
- base_address_id
- type
- is_primary
BusinessAddress table
---------------------
- id
- base_address_id
- business_name
- shipping_phone
- is_primary
和这些PHP对象:
class Address{}
class BusinessAddress extends Address{}
class PersonalAddress extends Address{}
考虑到下列要求:
- 地址本身可以存在(地址类不是抽象的)
- personalAddress和businessAddress可以具有完全相同的地址数据
- 如果我删除或编辑该地址,则会对从中继承的所有业务或个人地址产生影响
- 我不希望数据库中有任何数据重复(这是第二种标准形式的要求)
- 代理方法意味着代码重复,我不希望有任何重复
- 魔法方法在可测试性方面并不好,我更喜欢没有
Address table:
id | civic_no | road | state | country
1 123 test qc ca
PersonnalAddress table:
id | base_address_id | type | is_primary
1 1 A 0
2 1 B 1
BusinessAddress table:
id | base_address_id | business_name | shipping_phone | is_primary
1 1 chic choc 1231234 1
实施符合这些要求的解决方案的最佳策略是什么?而不是扩展地址类,您必须在地址上创建一个OneToMany关系,在个人地址和业务地址上创建一个manytone关系。大概是这样的:
<?php
// ...
use Doctrine\Common\Collections\ArrayCollection;
// ...
class Address
{
// ...
/**
* @ORM\OneToMany(targetEntity="PersonalAddress", mappedBy="address")
*/
private $personalAddresses;
/**
* @ORM\OneToMany(targetEntity="BusinessAddress", mappedBy="address")
*/
private $businessAddresses;
public function __construct()
{
$this->personalAddresses = new ArrayCollection();
$this->businessAddresses = new ArrayCollection();
}
// ...
}
除了扩展Address类之外,您还必须在Address上创建一个OneToMany关系,在PersonalAddress和BusinessAddress上创建一个ManyToOne关系。大概是这样的:
<?php
// ...
use Doctrine\Common\Collections\ArrayCollection;
// ...
class Address
{
// ...
/**
* @ORM\OneToMany(targetEntity="PersonalAddress", mappedBy="address")
*/
private $personalAddresses;
/**
* @ORM\OneToMany(targetEntity="BusinessAddress", mappedBy="address")
*/
private $businessAddresses;
public function __construct()
{
$this->personalAddresses = new ArrayCollection();
$this->businessAddresses = new ArrayCollection();
}
// ...
}
好的,这有点长,但我认为它涵盖了你的所有基础,如果你有任何问题,请随时提问
这附带了一个警告,我不知道您是否可以在MappedSuperclass上执行多对一操作。如果这是不可能的,那么您可以改为使用类表继承。试试看,告诉我们它是否有效
请记住,我很快推出了这段代码,它未经测试,因此可能不正确,但希望您了解它的工作原理
我们开始了强>
接口,以便更容易地说出“地址是什么”,而不必生成抽象类,然后重写方法并造成“糟糕的设计”感觉;)
你不需要的抽象实体,但如果你不使用它,你需要复制ID代码
/**
* @ORM\MappedSuperclass
*/
abstract class AbstractEntity {
/**
* Entity ID column.
*
* @var integer
*
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
*/
private $id;
public function getId() {
return $id;
}
}
基本地址,您可以单独存储或链接到“ComplexAddress”
“ComplexAddress”只是让您可以重用代码来将调用委派给基本地址
/**
* @ORM\MappedSuperclass
*/
abstract class ComplexAddress extends AbstractEntity implements Address {
/** @ORM\Many-To-One(targetEntity="BasicAddress")
private $basicAddress;
public function __construct(BasicAddress $basicAddress) {
$this->basicAddress = $basicAddress;
}
public function getRoad() {
return $this->basicAddress->getRoad();
}
// other methods for implementing "Address" just delegate to BasicAddress
}
公共广播
/**
* @ORM\Entity()
*/
class PersonalAddress extends ComplexAddress {
/** @ORM\Column(type="boolean") */
private $isPrimary;
public function isPrimary() {
return $isPrimary;
}
// other personal address methods here
}
商业地址
/**
* @ORM\Entity()
*/
class BusinessAddress extends ComplexAddress {
/** @ORM\Column() */
private $businessName;
public function getBusinessName() {
return $this->businessName;
}
// other business address methods here
}
编辑:刚刚注意到我忘了将级联参数用于删除,但您可能需要直接处理此问题-删除基本地址时,也会删除使用它的其他地址。好的,这有点长,但我认为它涵盖了所有基础,如果您有任何问题,请随时提问
这附带了一个警告,我不知道您是否可以在MappedSuperclass上执行多对一操作。如果这是不可能的,那么您可以改为使用类表继承。试试看,告诉我们它是否有效
请记住,我很快推出了这段代码,它未经测试,因此可能不正确,但希望您了解它的工作原理
我们开始了强>
接口,以便更容易地说出“地址是什么”,而不必生成抽象类,然后重写方法并造成“糟糕的设计”感觉;)
你不需要的抽象实体,但如果你不使用它,你需要复制ID代码
/**
* @ORM\MappedSuperclass
*/
abstract class AbstractEntity {
/**
* Entity ID column.
*
* @var integer
*
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue
*/
private $id;
public function getId() {
return $id;
}
}
基本地址,您可以单独存储或链接到“ComplexAddress”
“ComplexAddress”只是让您可以重用代码来将调用委派给基本地址
/**
* @ORM\MappedSuperclass
*/
abstract class ComplexAddress extends AbstractEntity implements Address {
/** @ORM\Many-To-One(targetEntity="BasicAddress")
private $basicAddress;
public function __construct(BasicAddress $basicAddress) {
$this->basicAddress = $basicAddress;
}
public function getRoad() {
return $this->basicAddress->getRoad();
}
// other methods for implementing "Address" just delegate to BasicAddress
}
公共广播
/**
* @ORM\Entity()
*/
class PersonalAddress extends ComplexAddress {
/** @ORM\Column(type="boolean") */
private $isPrimary;
public function isPrimary() {
return $isPrimary;
}
// other personal address methods here
}
商业地址
/**
* @ORM\Entity()
*/
class BusinessAddress extends ComplexAddress {
/** @ORM\Column() */
private $businessName;
public function getBusinessName() {
return $this->businessName;
}
// other business address methods here
}
编辑:刚刚注意到我忘了输入要删除的级联参数,但是您可能需要直接处理此问题-当删除基本地址时,也会删除使用它的其他地址。很有趣,但是为什么我的地址对象必须知道personalAddress和businessAddress?另外,我如何在不使用代理方法的情况下从PersonnalAddress类访问Address方法?您的意思是,如何从PersonalAddressClass
访问Address
类?创建运行原则:generate:entities
的getter和setter,您可以执行$personalAddress->getAddress()
。这是我的第一次实现尝试。从PHP的角度来看,这并不是我想要的。将使用该类的人现在必须处理该对象有2个对象。因此,为了能够使用具有统一对象的对象,我必须创建代理方法,如PersonalAddress、businessAddress等。。。这看起来像:公共函数getStreet(){return$this->address->getRoad();}这是一种非常糟糕的做法(如果它在条令社区中使用得很好的话),为什么?您只需编写:$businessAddress->getAddress()->getRoad()
。我不希望使用代码的用户必须理解对象背后的逻辑。他们用的是商业地址,就是这样。这就是为什么我想使用继承,现在使用关系,因为您可以100%只使用关系来满足OO需求,而不使用扩展,但这不是好的和直观的很有趣,但是为什么我的地址对象必须知道personalAddress和businessAddress?另外,我如何在不使用代理方法的情况下从PersonnalAddress类访问Address方法?您的意思是,如何从PersonalAddressClass
访问Address
类?创建运行原则:generate:entities
的getter和setter,您可以执行$personalAddress->getAddress()
。这是我的第一次实现尝试。从PHP的角度来看,这并不是我想要的。人