Orm 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 ----

我在弄清楚如何使用Doctrine2配置类的映射时遇到了一个问题

假设我有这些表格:

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关系,在PersonalAddressBusinessAddress上创建一个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的角度来看,这并不是我想要的。人