How to extend repositories in Doctrine 2? for share common functionalities in different table names?

719 views Asked by At

I have been doing some research on this topic but so far I couldn't find anything helpful for my scenario.

In a brief: I have two tables Quote (table name: quote) and QuoteArchive (table name: quote_archive). Both share exactly the same columns and types. As far as I have read this turn into a Doctrine MappedSuper Class ex: MappedSuperclassQuote.

After that Quote and QuoteArchive entities will extend from the MappedSuperclassQuote and both will share exactly the same structure.

Quote has a custom Repository with some functions. QuoteArchive needs exactly the same Repository functions as in Quote with the only difference being the table name and the PK.

I have two doubts in this scenario:

  • How to extend Doctrine entities when the PK (@Id) is different in the child classes?
  • How to extend or share the same repository between entities when the only change is the table name.

For get a better idea this is how my current entities looks like:

/**
 * @ORM\Entity
 * @ORM\Table(name="quote")
 * @ORM\Entity(repositoryClass="QuoteBundle\Entity\Repository\QuoteRepository")
 */
class Quote
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer",unique=true,nullable=false)
     * @ORM\GeneratedValue
     */
    private $quoteId;

    // ...
}

/**
 * @ORM\Entity
 * @ORM\Table(name="quote_archive")
 * @ORM\Entity(repositoryClass="QuoteBundle\Entity\Repository\QuoteArchiveRepository")
 */
class QuoteArchive
{   
    /**
     * @ORM\Id
     * @ORM\Column(type="integer",unique=true,nullable=false)
     */
    private $archiveId;

    // ...
}

Last but not least:

class QuoteRepository extends EntityRepository
{
    public function getCurrentQuoteId(int $OrigQuoteId)
    {
        $em   = $this->getEntityManager();
        $qb   = $em->createQueryBuilder();

        return $qb->select('q')
                  ->from('QuoteBundle:Quote')
                  ->where('q.origQuoteId =:origQuoteId')
                  ->setParameter('origQuoteId', $OrigQuoteId)
                  ->andWhere('q.quoteType =:quoteType')
                  ->setParameter('quoteType', 'current')
                  ->getQuery()
                  ->getResult();
    }
}

What is the problem here? I need to repeat the same exact function in QuoteArchiveRepository and change the table from quote to quote_archive and it's exactly what I am trying to avoid if possible.

Can any give me some ideas? Code example would be great :)

References:

1

There are 1 answers

1
Tom On

I think you're mistaking doing a MappedSuperclassQuote entity. You have to inherit the Archive from the Quote.

Example : you have your Quote entity The definition should be something like :

 /**
 * @ORM\Table(name="app_quote")
 * @ORM\InheritanceType("JOINED")
 * @ORM\DiscriminatorColumn(name="quote_type", fieldName="quoteType", type="string")
 * @ORM\DiscriminatorMap({
 *     "quote":"YourBundle\Entity\Quote",
 *     "quote_archive":"YourBundle\Entity\QuoteArchive"
 * })
 * @Gedmo\Loggable
 * @ORM\Entity(repositoryClass="YourBundle\Repository\QuoteRepository")
 */

Why a JOINED inheritance ? Cause you want two separate tables (what SINGLE_TABLE is not doing) and you don't have a really abstract class (cause Quote AND QuoteArchive means something for you)

After, your table QuoteArchive should extends the first one :

/**
 * @ORM\Entity
 * @ORM\Table(name="app_quote_archive")
 */
class QuoteArchive extends Quote
{
...
}

Your column quote_type in app_quote will help you to know if this is an archived quote or not.

It provides you all you want : - QuoteArchive will have access to functions inside QuoteRepository - Each table has separated ids

One thing could be annoying for you : if you want to set a quote has archived, it's not so easy to change an entity type for now in Doctrine. In that case, it's better for you to use single_table joining type. All the datas are stored in a same table in database, making type change easy but you keep two different entities.