【问题标题】:Reflect MySQL polymorphic association in Doctrine 2.2在 Doctrine 2.2 中反映 MySQL 多态关联
【发布时间】:2012-04-09 21:08:28
【问题描述】:

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

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

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

我查看了 Doctrine Inheritance 文档和其他示例,但它似乎对我没有帮助。 如果可能,我想避免将 descriptionprice 列添加到视频和汽车表格中

非常感谢!

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

【问题讨论】:

    标签: doctrine-orm codeigniter-2


    【解决方案1】:

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

    最重要的是产品 YAML 文件 inheritanceType: JOINEDdiscriminatorColumn:discriminatorMap: 以及视频和汽车实体类 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 文件(您需要从中创建实体和代理类)

    Entities.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
    

    Entities.Brand.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
    

    Entities.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
    

    Entities.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
    

    Entities.Video.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。 I've used Joel Verhagen's excellent guide

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

    这会产生以下实体类

    Artist.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;
        }
    }
    

    Car.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;
        }
    }
    

    Product.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;
        }
    }
    

    Video.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
    

    【讨论】:

    • 感谢您的完整自动回答!它对我很有帮助!但是我有一个问题:如果 Video 实体依赖于其他实体会怎样?谢谢
    【解决方案2】:

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

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

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

    【讨论】:

    • 您已在回答区发表评论。
    猜你喜欢
    • 2016-01-26
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    • 2017-11-06
    • 1970-01-01
    • 2016-08-20
    • 1970-01-01
    相关资源
    最近更新 更多