简体   繁体   English

Symfony2 / Doctrine2继承

[英]Symfony2/Doctrine2 Inheritance

I'm attempting to accomplish BASIC inheritance in Doctrine 2, but I'm running into several major issues. 我试图在Doctrine 2中完成BASIC继承,但是遇到了几个主要问题。 Such a task should not be so complicated. 这样的任务不应该那么复杂。 Let's get down to business... 我们开始谈正事吧...

I have three classes, BaseFoodType, Drink, and Snack. 我有三个类,BaseFoodType,Drink和Snack。 My BaseFoodType has the following class definition: 我的BaseFoodType具有以下类定义:

/** @ORM\MappedSuperclass */
class BaseFoodType {

    /**
     * @ORM\Column(type="integer", length=7)
     */
    public $budget = 0;
}

Which follows the instructions for inheritance on the doctrine website: http://docs.doctrine-project.org/en/2.0.x/reference/inheritance-mapping.html 遵循该学说网站上的继承说明: http : //docs.doctrine-project.org/en/2.0.x/reference/inheritance-mapping.html

Here is what the sub-classes look like prior to generating my entities: 这是生成我的实体之前的子类外观:

namespace MySite\MainBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * MySite\MainBundle\Entity\EventDrink
 *
 * @ORM\Table(name="drink")
 * @ORM\Entity
 */
class Drink extends BaseFoodType {

    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="integer", length=5, nullable=true)
     */
    public $people_count;
}

Both Drink, and Snack inherit from this base class but I'm running into numerous issues when attempting to build my entities using the doctrine:generate:entities command. Drink和Snack都继承自该基类,但是在尝试使用doctrine:generate:entities命令构建实体时遇到了很多问题。 First, Symfony inserts a private "budget" property into each subclass, along with getters and setters (THIS DEFEATS THE PURPOSE INHERITANCE) 首先,Symfony将私有的“预算”属性以及getter和setter插入到每个子类中(这不利于目的继承)

/**
 * @var integer
 */
private $budget;

/**
 * Set budget
 *
 * @param integer $budget
 */
public function setBudget($budget)
{
    $this->budget = $budget;

    return $this;
}

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

Second, I'm getting a fatal error: 其次,我收到一个致命错误:

Fatal error: Access level to MySite\\MainBundle\\Entity\\Drink::$budget must be public (as in class MySite\\MainBundle\\Entity\\BaseFoodType) in C:\\xampp\\htdocs\\MySite\\src\\MySite\\MainBundle\\Entity\\Drink.php on line 197 致命错误:在C:\\ xampp \\ htdocs \\ MySite \\ src \\ MySite \\ MainBundle \\ Entity \\中,对MySite \\ MainBundle \\ Entity \\ Drink :: $ budget的访问级别必须是公共的(如在MySite \\ MainBundle \\ Entity \\ BaseFoodType类中)第197行的Drink.php

I could probably make the generated properties public and be on my way, but again, that defeats the purpose of inheritance! 我可能可以将生成的属性公开并继续使用,但是,再次违反了继承的目的!

Thanks in advance for any insight. 预先感谢您的任何见解。

Doctrine provides the means to specify the visibility of generated fields. 教义提供指定生成字段可见性的方法。 Either protected or private. 受保护的或私有的。 The default is private. 默认值为私人。

The problem is that the Symfony command that invokes Doctrine offers no way to change this. 问题在于,调用Doctrine的Symfony命令无法更改它。

Creating your own subclass of the standard Symfony command will allow you more control over the generation process. 创建自己的标准Symfony命令的子类将使您可以更好地控制生成过程。 This might help you along. 这可能会帮助您。

namespace Foo\Bundle\FooBundle\Command;

use Doctrine\Bundle\DoctrineBundle\Command as DC;
use Doctrine\ORM\Tools\EntityGenerator;

class GenerateEntitiesDoctrineCommand extends DC\GenerateEntitiesDoctrineCommand
{

    protected function configure()
    {
        parent::configure();
        $this->setName('foo:generate:entities');
    }

    /**
     * get a doctrine entity generator
     *
     * @return EntityGenerator
     */
    protected function getEntityGenerator()
    {
        $entityGenerator = new EntityGenerator();
        $entityGenerator->setGenerateAnnotations(true);
        $entityGenerator->setGenerateStubMethods(true);
        $entityGenerator->setRegenerateEntityIfExists(false);
        $entityGenerator->setUpdateEntityIfExists(true);
        $entityGenerator->setNumSpaces(4);
        $entityGenerator->setAnnotationPrefix('ORM\\');
        $entityGenerator->setFieldVisibility($entityGenerator::FIELD_VISIBLE_PROTECTED);

        return $entityGenerator;
    }
}

This does two things. 这有两件事。 It sets the property visibility to protected. 它将属性可见性设置为protected。 This prevents php errors. 这样可以防止php错误。

$entityGenerator->setFieldVisibility($entityGenerator::FIELD_VISIBLE_PROTECTED);

It also copies the annotations from mapped super class into the entity class. 还将注释从映射的超类复制到实体类。

$entityGenerator->setGenerateAnnotations(true);

Here's some example code where properties are inherited from a base class and their visibility and annotations copy correctly into the inheriting class 这是一些示例代码,其中属性是从基类继承的,它们的可见性和注释正确复制到了继承的类中

/** @ORM\MappedSuperclass */
class DataSuper {
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;
    /**
     * @ORM\ManyToOne(targetEntity="Campaign", inversedBy="data")
     * @ORM\JoinColumn(name="campaign_id", referencedColumnName="id")
     * @Exclude
     */
    protected $campaign;

    /**
     * @ORM\Column(type="text", nullable=true, name="data")
     */
    protected $data;

    /**
     * @ORM\Column(type="datetime")
     */
    protected $createdDate;
}


/**
 * @ORM\Entity(repositoryClass="Foo\Bundle\FooBundle\Entity\DataRepository")
 * @ORM\Table(name="data")
 * @ExclusionPolicy("none")
 */
class Data extends DataSuper
{
}

After generation the Data class looks like: 生成后,Data类如下所示:

class Data extends DataSuper
{

/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer", precision=0, scale=0, nullable=false, unique=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
protected $id;

/**
 * @var string
 *
 * @ORM\Column(name="data", type="text", precision=0, scale=0, nullable=true, unique=false)
 */
protected $data;

/**
 * @var \DateTime
 *
 * @ORM\Column(name="createdDate", type="datetime", precision=0, scale=0, nullable=false, unique=false)
 */
protected $createdDate;

/**
 * @var \Foo\Bundle\FooBundle\Entity\Campaign
 *
 * @ORM\ManyToOne(targetEntity="Foo\Bundle\FooBundle\Entity\Campaign", inversedBy="data")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="campaign_id", referencedColumnName="id", nullable=true)
 * })
 */
protected $campaign;


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

/**
 * Set data
 *
 * @param string $data
 * @return Data
 */
public function setData($data)
{
    $this->data = $data;

    return $this;
}

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

/**
 * Set createdDate
 *
 * @param \DateTime $createdDate
 * @return Data
 */
public function setCreatedDate($createdDate)
{
    $this->createdDate = $createdDate;

    return $this;
}

/**
 * Get createdDate
 *
 * @return \DateTime 
 */
public function getCreatedDate()
{
    return $this->createdDate;
}

/**
 * Set campaign
 *
 * @param \Foo\Bundle\FooBundle\Entity\Campaign $campaign
 * @return Data
 */
public function setCampaign(\Foo\Bundle\FooBundle\Entity\Campaign $campaign = null)
{
    $this->campaign = $campaign;

    return $this;
}

/**
 * Get campaign
 *
 * @return \Foo\Bundle\FooBundle\Entity\Campaign 
 */
public function getCampaign()
{
    return $this->campaign;
}
}

And the table structure is correct once you do: 完成后,表结构是正确的:

php app/console doctrine:schema:update --force

The exception is being thrown because BaseFoodType::budget is a public property and doctrine:generate:entities created a private property in your Drink / Snack classes extending BaseFoodType ( which is not correct but the way the command works by now ). 抛出异常是因为BaseFoodType::budget公共属性,而doctrine:generate:entities在扩展BaseFoodType的Drink / Snack类中创建了私有属性(这是不正确的,但是命令现在的工作方式)。

Property visibility in a subclass can only be the same level or more liberate ( private -> protected -> public ) but never more restrictive. 子类中的属性可见性只能是同一级别或更高级别的(private-> protected-> public),而从不更严格。

doctrine:generate:entities did not take superclass's public property into account when generating the getters/setters as the implementation with a public property is non-standard. 生成吸气剂/设定剂时, 教义:生成:实体未考虑超类的公共财产,因为公共财产的实施是非标准的。

Therefore you will have to adjust the generated class manually. 因此,您将不得不手动调整生成的类。

I recommend using private/protected properties combined with getters & setters. 我建议将私有/受保护的属性与getter和setter结合使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM