【问题标题】:Symfony: Overwrite doctrine entity from other bundleSymfony:从其他捆绑包中覆盖教义实体
【发布时间】:2014-11-02 15:12:47
【问题描述】:

我正在编写一个可供多个客户使用的 Symfony 应用程序。有些客户需要额外的功能,所以我的想法是把我所有的标准功能都放在BundleA中,把额外的功能放在BundleB中,BundleB只对需要的客户启用。

我想在 BundleB 中做的一件事是通过添加一个额外的字段来扩展 BundleA 中的实体。

我的代码目前看起来像这样:

<?php
// BundleA/Model/Element.php

namespace BundleA\Model;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\MappedSuperclass
 */
abstract class Element
{
    // All shared fields defined here
}

<?php
// BundleA/Entity/Element.php
namespace BundleA\Entity;

use BundleA\Model\Element as AbstractElement;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="Element")
 * @ORM\Entity
 */
class Element extends AbstractElement
{
}


<?php
// BundleB/Entity/BundleBElement.php
namespace BundleB\Entity\Entity;

use BundleA\Model\Element as AbstractElement;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="Element")
 */
class BundleBElement extends AbstractElement
{
    /**
     * @ORM\Column(name="mypage_id", type="integer")
     */
    protected $mypageId;
}

如果我尝试为上述代码转储 SQL,我会得到以下信息:

名称为“元素”的表已存在。

我认为基本上我需要的是某种配置选项,它可以让我配置用于实体的元素类。比如:

bundle:
    element_class: BundleB\Entity\BundleBElement

但我不确定如何实现这样的配置选项。

所有客户都有自己的数据库,因此不应该存在实体冲突的问题。

【问题讨论】:

  • 先解决一个问题。您有两个具有相同 @ORM\Table(name="Element") 的实体
  • 我知道。我希望两者都具有相同的表名,因为它们中只有一个应该处于活动状态。要么它应该被配置为使用来自 BundleA 或来自 BundleB 的元素,而不是来自两者。所以我想要一个配置选项,例如“bundle.element_class”,它定义了应该将哪个类用作实体。
  • 不是这么简单的。 Doctrine2 配置允许您指定要映射的目录。如果打开自动映射,则默认情况下会自动映射捆绑包。这意味着您可以告诉它忽略一个目录并使用另一个目录。

标签: php symfony orm doctrine


【解决方案1】:

你要的是single table inheritance:

<?php
// BundleA/Model/Element.php

namespace BundleA\Model;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="type", type="string")
 * @ORM\DiscriminatorMap({"a"="Element", "b"="BundleBElement"})
 */
abstract class Element
{
    // All shared fields defined here
}

<?php

namespace BundleA\Entity;

use BundleA\Model\Element as AbstractElement;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Element extends AbstractElement
{
}


<?php

namespace BundleB\Entity\Entity;

use BundleA\Model\Element as AbstractElement;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class BundleBElement extends AbstractElement
{
    /**
     * @ORM\Column(type="integer")
     */
    protected $mypageId;
}

请注意,@Table 注释已被删除。 (对于大多数用例来说,它们实际上是不必要的。不知道为什么人们总是添加它们。)

【讨论】:

    【解决方案2】:

    您有 两个 表定义。尝试删除实体中的表定义或使用不同的表名。

    <?php
    // BundleA/Model/Element.php
    
    namespace BundleA\Model;
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * @ORM\MappedSuperclass
     */
    abstract class Element
    {
        // All shared fields defined here
    }
    
    <?php
    // BundleA/Entity/Element.php
    namespace BundleA\Entity;
    
    use BundleA\Model\Element as AbstractElement;
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * @ORM\Table(name="Element")
     * @ORM\Entity
     */
    class Element extends AbstractElement
    {
    }
    
    
    <?php
    // BundleB/Entity/BundleBElement.php
    namespace BundleB\Entity\Entity;
    
    use BundleA\Model\Element as AbstractElement;
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * @ORM\Entity
     * @ORM\Table(name="ElementB")
     */
    class BundleBElement extends AbstractElement
    {
        /**
         * @ORM\Column(name="mypage_id", type="integer")
         */
        protected $mypageId;
    }
    

    如果你想扩展它,你可以删除实体 A 中的表定义,这样你就只有 一个 带有扩展数据的表:

    <?php
    // BundleA/Model/Element.php
    
    namespace BundleA\Model;
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * @ORM\MappedSuperclass
     */
    abstract class Element
    {
        // All shared fields defined here
    }
    
    <?php
    // BundleA/Entity/Element.php
    namespace BundleA\Entity;
    
    use BundleA\Model\Element as AbstractElement;
    use Doctrine\ORM\Mapping as ORM;
    
    class Element extends AbstractElement
    {
    }
    
    
    <?php
    // BundleB/Entity/BundleBElement.php
    namespace BundleB\Entity\Entity;
    
    use BundleA\Model\Element as AbstractElement;
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * @ORM\Entity
     * @ORM\Table(name="Element")
     */
    class BundleBElement extends AbstractElement
    {
        /**
         * @ORM\Column(name="mypage_id", type="integer")
         */
        protected $mypageId;
    }
    

    【讨论】:

    • 我更喜欢使用单个表(元素),因为应该只使用其中一个,具体取决于激活的捆绑包。所以如果 BundleB 被激活,BundleA 中的元素应该不被使用。
    猜你喜欢
    • 2015-03-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-02
    • 1970-01-01
    • 2018-05-04
    • 1970-01-01
    • 2018-12-21
    • 1970-01-01
    相关资源
    最近更新 更多