2

我将 Doctrine 2.2.0 与 Codeigniter 一起使用。我是 Doctrine 的新手(或者一般来说是 ORM 的新手)。

我正在基于 YAML 文件设置实体和代理类,效果很好。我在我的 Doctrine 类中反映我的数据库中的多态关联时确实存在问题。我正在寻找一个关于如何在 Doctrine 中实现以下多态关联的具体示例。

在我的数据库中,我有一个名为 products 的表。根据字段的值,object_typeobject_id想与表格视频或表格汽车中的记录相关(我在这里简化了)。我想将两种产品类型保留在 2 个单独的表中,因为一个与另一个无关,并且两个表都与其他表相关。

我查看了 Doctrine Inheritance 文档和其他示例,但它似乎对我没有帮助。如果可能的话,我想避免添加列descriptionprice表格 videos 和 cars

非常感谢!

|Table: products                                      |
|-----------------------------------------------------|
| ID | description | price  | object_type | object_id |
|-----------------------------------------------------|
| 1  | A video     | 20.00  | video       | 12        |
| 2  | A car       | 159.00 | car         | 5         |

|Table: videos                               |
|--------------------------------------------|
| ID | filename     | artist_id | date       |
|--------------------------------------------|
| 12 | somename.mp4 | 189       | 2011-02-15 |

|Table: cars                   |
|------------------------------|
| ID | brand_id | model | year |
|------------------------------|
| 5  | 17       | astra | 2010 |
4

2 回答 2

4

自己找到了解决方案。我在下面列出了我已完成的不同步骤。这个答案很大,但我尽量做到完整。

最重要的内容在 Product YAML 文件inheritanceType: JOINEDdiscriminatorColumn:discriminatorMap:以及 Video 和 Car 实体类class Video extends Productclass Car extends Product

1) 数据库模式

CREATE TABLE IF NOT EXISTS `artists` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `brands` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `cars` (
  `id` int(11) NOT NULL,
  `model` varchar(255) NOT NULL,
  `release_date` date NOT NULL,
  `brand_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `description` varchar(255) NOT NULL,
  `price` double NOT NULL,
  `object_type` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `videos` (
  `id` int(11) NOT NULL,
  `file_name` varchar(255) NOT NULL,
  `release_date` date NOT NULL,
  `artist_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

2) Doctrine YAML 文件(您需要从中创建实体和代理类)

实体.Artist.dcm.yml

Entities\Artist:
    type: entity
    table: artists
    id:
        id:
            type: integer
            primary: true
            notnull: true
            generator:
                strategy: AUTO
    fields:
        name:
            type: string(255)
            notnull: true
    oneToMany:
        videos:
            targetEntity: Video
            mappedBy: artist
    options:
        charset: utf8
        type: InnoDB

实体.品牌.dcm.yml

Entities\Brand:
    type: entity
    table: brands
    id:
        id:
            type: integer
            primary: true
            notnull: true
            generator:
                strategy: AUTO
    fields:
        name:
            type: string(255)
            notnull: true
    oneToMany:
        cars:
            targetEntity: Car
            mappedBy: brand
    options:
        charset: utf8
        type: InnoDB

实体.Car.dcm.yml

Entities\Car:
    type: entity
    table: cars
    fields:
        model:
            type: string
            notnull: true
        release_date:
            type: date
            notnull: true
    oneToOne: #unidirectional    
        brand:
            targetEntity: Brand
            joinColumns:
                brand_id:
                    referencedColumnName: id
    options:
        charset: utf8
        type: InnoDB

实体.Product.dcm.yml

Entities\Product:
    type: entity
    table: products
    id:
        id:
            type: string
            primary: true
            notnull: true
            generator:
                strategy: AUTO
    fields:
        description:
            type: string(255)
            notnull: true
        price:
            type: decimal
            notnull: true
    inheritanceType: JOINED
    discriminatorColumn:
        name: object_type
        type: string
        length: 255
    discriminatorMap:
        video: Video
        car: Car
    options:
        charset: utf8
        type: InnoDB

实体.视频.dcm.yml

Entities\Video:
    type: entity
    table: videos
    fields:
        file_name:
            type: string
            notnull: true
        release_date:
            type: date
            notnull: true
    oneToOne: #unidirectional    
        artist:
            targetEntity: Artist
            joinColumns:
                artist_id:
                    referencedColumnName: id
    options:
        charset: utf8
        type: InnoDB

3) 创建实体和代理类

我使用 CodeIgniter。我使用了 Joel Verhagen 的优秀指南

!!使用产品扩展视频和汽车很重要 - 见下文!

这导致以下实体类

艺术家.php

namespace Entities;

use Doctrine\ORM\Mapping as ORM;

/**
 * Entities\Artist
 *
 * @ORM\Table(name="artists")
 * @ORM\Entity
 */
class Artist
{
    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string $name
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * @var \Doctrine\Common\Collections\ArrayCollection
     *
     * @ORM\OneToMany(targetEntity="Entities\Video", mappedBy="artist")
     */
    private $videos;

    public function __construct()
    {
        $this->videos = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Artist
     */
    public function setName($name)
    {
        $this->name = $name;
        return $this;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Add videos
     *
     * @param Entities\Video $videos
     */
    public function addVideo(\Entities\Video $videos)
    {
        $this->videos[] = $videos;
    }

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

品牌.php

namespace Entities;

use Doctrine\ORM\Mapping as ORM;

/**
 * Entities\Brand
 *
 * @ORM\Table(name="brands")
 * @ORM\Entity
 */
class Brand
{
    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string $name
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;

    /**
     * @var \Doctrine\Common\Collections\ArrayCollection
     *
     * @ORM\OneToMany(targetEntity="Entities\Car", mappedBy="brand")
     */
    private $cars;

    public function __construct()
    {
        $this->cars = new \Doctrine\Common\Collections\ArrayCollection();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Brand
     */
    public function setName($name)
    {
        $this->name = $name;
        return $this;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Add cars
     *
     * @param Entities\Car $cars
     */
    public function addCar(\Entities\Car $cars)
    {
        $this->cars[] = $cars;
    }

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

汽车.php

namespace Entities;

use Doctrine\ORM\Mapping as ORM;

/**
 * Entities\Car
 *
 * @ORM\Table(name="cars")
 * @ORM\Entity
 */
class Car extends Product //Important that Car extends Product
{
    /**
     * @var string $model
     *
     * @ORM\Column(name="model", type="string")
     */
    private $model;

    /**
     * @var date $release_date
     *
     * @ORM\Column(name="release_date", type="date")
     */
    private $release_date;

    /**
     * @var Entities\Brand
     *
     * @ORM\OneToOne(targetEntity="Entities\Brand")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="brand_id", referencedColumnName="id", unique=true)
     * })
     */
    private $brand;


    /**
     * Set model
     *
     * @param string $model
     * @return Car
     */
    public function setModel($model)
    {
        $this->model = $model;
        return $this;
    }

    /**
     * Get model
     *
     * @return string 
     */
    public function getModel()
    {
        return $this->model;
    }

    /**
     * Set release_date
     *
     * @param date $releaseDate
     * @return Car
     */
    public function setReleaseDate($releaseDate)
    {
        $this->release_date = $releaseDate;
        return $this;
    }

    /**
     * Get release_date
     *
     * @return date 
     */
    public function getReleaseDate()
    {
        return $this->release_date;
    }

    /**
     * Set brand
     *
     * @param Entities\Brand $brand
     * @return Car
     */
    public function setBrand(\Entities\Brand $brand = null)
    {
        $this->brand = $brand;
        return $this;
    }

    /**
     * Get brand
     *
     * @return Entities\Brand 
     */
    public function getBrand()
    {
        return $this->brand;
    }
}

产品.php

namespace Entities;

use Doctrine\ORM\Mapping as ORM;

/**
 * Entities\Product
 *
 * @ORM\Table(name="products")
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="", type="", length=)
 * @ORM\DiscriminatorMap({"video" = "Entities\Video", "car" = "Entities\Car"})
 * @ORM\Entity
 */
class Product
{
    /**
     * @var string $id
     *
     * @ORM\Column(name="id", type="string")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string $description
     *
     * @ORM\Column(name="description", type="string", length=255)
     */
    private $description;

    /**
     * @var decimal $price
     *
     * @ORM\Column(name="price", type="decimal")
     */
    private $price;


    /**
     * Get id
     *
     * @return string 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set description
     *
     * @param string $description
     * @return Product
     */
    public function setDescription($description)
    {
        $this->description = $description;
        return $this;
    }

    /**
     * Get description
     *
     * @return string 
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Set price
     *
     * @param decimal $price
     * @return Product
     */
    public function setPrice($price)
    {
        $this->price = $price;
        return $this;
    }

    /**
     * Get price
     *
     * @return decimal 
     */
    public function getPrice()
    {
        return $this->price;
    }
}

视频.php

namespace Entities;

use Doctrine\ORM\Mapping as ORM;

/**
 * Entities\Video
 *
 * @ORM\Table(name="videos")
 * @ORM\Entity
 */
class Video extends Product //Important that Video extends Product
{
    /**
     * @var string $file_name
     *
     * @ORM\Column(name="file_name", type="string")
     */
    private $file_name;

    /**
     * @var date $release_date
     *
     * @ORM\Column(name="release_date", type="date")
     */
    private $release_date;

    /**
     * @var Entities\Artist
     *
     * @ORM\OneToOne(targetEntity="Entities\Artist")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="artist_id", referencedColumnName="id", unique=true)
     * })
     */
    private $artist;


    /**
     * Set file_name
     *
     * @param string $fileName
     * @return Video
     */
    public function setFileName($fileName)
    {
        $this->file_name = $fileName;
        return $this;
    }

    /**
     * Get file_name
     *
     * @return string 
     */
    public function getFileName()
    {
        return $this->file_name;
    }

    /**
     * Set release_date
     *
     * @param date $releaseDate
     * @return Video
     */
    public function setReleaseDate($releaseDate)
    {
        $this->release_date = $releaseDate;
        return $this;
    }

    /**
     * Get release_date
     *
     * @return date 
     */
    public function getReleaseDate()
    {
        return $this->release_date;
    }

    /**
     * Set artist
     *
     * @param Entities\Artist $artist
     * @return Video
     */
    public function setArtist(\Entities\Artist $artist = null)
    {
        $this->artist = $artist;
        return $this;
    }

    /**
     * Get artist
     *
     * @return Entities\Artist 
     */
    public function getArtist()
    {
        return $this->artist;
    }
}

3) 创建新汽车和新视频

这就是我的 CodeIgniter 控制器中的内容。该代码假定您创建了一个名为 Metallica 的艺术家和一个名为 Ford 的品牌。

public function createVideo()
{
    //Instantiate new Entities\Video object
    $video = new Entities\Video;

    //Since it extends Entities\Product you can set the common Product properties
    $video->setDescription('This is a Metallica clip');
    $video->setPrice(19.95);

    //Setting the custom Video properties
    $artist = $this->doctrine->em->getRepository('Entities\Artist')->findOneBy(array('name' => 'Metallica'));
    $video->setArtist($artist);
    $video->setReleaseDate(new DateTime());
    $video->setFileName('metallica.mp4');

    //Save
    $this->doctrine->em->persist($video);
    $this->doctrine->em->flush();
}

public function createCar()
{
    //Instantiate new Entities\Car object
    $car = new Entities\Car;

    //Since it extends Entities\Product you can set the common Product properties
    $car->setDescription('This is Ford Mondeo of 2011');
    $car->setPrice(19.95);

    //Setting the custom Car properties
    $brand = $this->doctrine->em->getRepository('Entities\Brand')->findOneBy(array('name' => 'Ford'));
    $car->setBrand($brand);
    $car->setReleaseDate(DateTime::createFromFormat('Y-m-d', '2011-11-15'));
    $car->setModel('Mondeo');

    //Save
    $this->doctrine->em->persist($car);
    $this->doctrine->em->flush();
}

4)提取所有产品

关于如何提取所有产品的示例

public function extractAllProducts()
{
    $products = $this->doctrine->em->getRepository('Entities\Product')->findAll();
    foreach($products as $product)
    {
        printf('%s for € %s<br />', $product->getDescription(), $product->getPrice());
    }
}

这导致

This is a Metallica clip for € 19.95
This is Ford Mondeo of 2011 for € 19.95

如何提取所有视频的示例

public function extractAllVideos()
{
    $videos = $this->doctrine->em->getRepository('Entities\Video')->findAll();
    foreach($videos as $video)
    {
        printf('%s, released %s for € %s<br />', $video->getDescription(),  $video->getReleaseDate()->format('Y'), $video->getPrice());
    }
}

这导致

This is a Metallica clip, released 2012 for € 19.95
于 2012-06-18T15:44:18.787 回答
0

您找对地方了,继承映射当然是实现这一目标所需要的。据我所知,这是“类表继承”的完美示例。

查看手册以获取有关如何实现此功能的示例/说明。

http://docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/reference/inheritance-mapping.html#class-table-inheritance

于 2012-04-09T23:36:28.290 回答