Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doctrine 2 - Class Table Inheritance, selecting by type

I have two entities - News and Page. Definition looks like this:

/**
 * Description of Page
 * @Entity
 * @InheritanceType("JOINED")
 * @DiscriminatorColumn(name="type", type="string")
 * @DiscriminatorMap({
 *  "news" = "News" ,
 *  "page" = "Page"})
 *
 * @table(
 *  name="pages"
 * )
 */
class Page extends BaseEntity {...}
class News extends Page {...}

I know, how to select only "news" entities - simple SELECT ... FROM News n.

But is there some way how to select only "page" entities, which are mapped directly to Page class? Or do I have to create some extra entity extending Page for this?

like image 364
Jan Langer Avatar asked Feb 19 '11 22:02

Jan Langer


2 Answers

The solution is to use x INSTANCE OF Entity in WHERE clause.

http://groups.google.com/group/doctrine-user/browse_thread/thread/b1dc52ed447204e2

like image 84
Jan Langer Avatar answered Nov 06 '22 14:11

Jan Langer


The solution, that I use is that I create a Switcher on the root entity Repository class, like so:

class PageRepository extends EntityRepository
{
  protected $_switchEntityNameSave = null;

  /**
   * @param type $fqcn 
   */
  protected function _swapEntityDiscriminator($fqcn = null){
    if(isset($fqcn)){
       $this->_switchEntityNameSave = $this->_entityName;
       $this->_entityName = $fqcn;
    } else {
       $this->_entityName = $this->_switchEntityNameSave;
       unset($this->_switchEntityNameSave);
    }
  }

  // ... AND TO USE... 

  public function findSomeStuff()
  {
    $this->_swapEntityDiscriminator(News::getFqcn());
    // The query, the result in a variable, $q for example
    $this->_swapEntityDiscriminator();
    return $q->getQuery();
  }

}

Then, in the parent classe, I do the Getter getFqcn(), like so:

abstract class BaseEntity {
  /**
   * Get fqcn
   * 
   * Fully Qualified Class Name
   *
   * @return string
   */
  public static function getFqcn()
  {
      return get_called_class();
  }
  // ...
}

That use the Late static binding feature and give me the full class name on the concrete object (either News or Page).

I do put abstract, to be sure to not instantiate it.

What I also add in the concrete classes, a few constants:

class News extends Page {
  const HUMAN_READABLE = "News";
  const DISCRIMINATOR = "news";   // SAME as your @DiscriminatorMap() Annotation.

}

That way, my Repository I can create specialized finders only on one of the types.

like image 30
renoirb Avatar answered Nov 06 '22 15:11

renoirb