nifty
nifty

Reputation: 45

Symfony: Overwrite doctrine entity from other bundle

I'm writing a Symfony application which will be used by multiple customers. Some customers require extra functionality, so my idea is that I put all my standard functionality in BundleA, and place extra functionality in BundleB, which is only enabled for customers which require it.

One of the things I want to do in BundleB, is to extend an entity in BundleA, by adding an extra field.

My code currently looks something like this:

<?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;
}

If I try to dump the SQL for the above code, I get the following:

The table with name 'element' already exists.

Basically what I need I think, is some sort of config option which lets me configure which Element-class to use for the entity. Something like:

bundle:
    element_class: BundleB\Entity\BundleBElement

but I'm unsure about how to implement such a config option.

All the customers have their own database, so there shouldn't be a issue of conflicting entities.

Upvotes: 1

Views: 1406

Answers (2)

lxg
lxg

Reputation: 13107

What you want is 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;
}

Please note that the @Table annotations were removed. (They are actually unnecessary for most use cases. Don't know why people always add them.)

Upvotes: 0

xate
xate

Reputation: 6379

Your having two table definitions. Try to delete the table definition in your Entity or use a different table name.

<?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;
}

If you wanna extend it, you might delete the table definition in your Entity A so you only have one table with the extended data:

<?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;
}

Upvotes: 2

Related Questions