7
votes

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?

2
What are you trying to do? I'm not sure you use Class Table Inheritance in a proper way.Boris Guéry
I have basic entity Page, which has properties like title, text, author etc. News extends it with some extra properties like summary, comments association... It will probably be possible to do this using single table inheritance, but I do not think that is right approach, because the result is one big table.Jan Langer
Did I miss something? ...Why can you just query SELECT * FROM Page...?Cobby
Because it selects everything in that table - including entries of subclassesJan Langer

2 Answers

1
votes

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.