Propel Single Table Inheritance Issue
- by lo_fye
I have a table called "talk", which is defined as abstract in my schema.xml file.
It generates 4 objects (1 per classkey): Comment, Rating, Review, Checkin
It also generates TalkPeer, but I couldn't get it to generate the other 4 peers (CommentPeer, RatingPeer, ReviewPeer, CheckinPeer), so I created them by hand, and made them inherit from TalkPeer.php, which inherits from BaseTalkPeer. I then implemented getOMClass() in each of those peers.
The problem is that when I do queries using the 4 peers, they return all 4 types of objects. That is, ReviewPeer will return Visits, Ratings, Comments, AND Reviews.
Example:
$c = new Criteria();
$c->add(RatingPeer::VALUE, 5, Criteria::GREATER_THAN);
$positive_ratings = RatingPeer::doSelect($c);
This returns all comments, ratings, reviews, & checkins that have a value 5.
ReviewPeer should only return Review objects, and can't figure
out how to do this.
Do I actually have to go through and change all my criteria to manually specify the classkey?
That seems a little pointless, since the Peer name already distinct.
I don't want to have to customize each Peer. I should be able to customize JUST the TalkPeer, since they all inherit from it... I just can't figure out how.
I tried changing doSelectStmt just in TalkPeer so that it automatically adds the CLASSKEY restriction to the Criteria. It almost works, but I get a: Fatal error: Cannot instantiate abstract class Talk in /models/om/BaseTalkPeer.php on line 503. Line 503 is in BaseTalkPeer::populateObjects(), and is the 3rd line below:
$cls = TalkPeer::getOMClass($row, 0);
$cls = substr('.'.$cls, strrpos('.'.$cls, '.') + 1);
$obj = new $cls();
The docs talked about overriding BaseTalkPeer::populateObject(). I have a feeling that's my problem, but even after reading the source code, I still couldn't figure out how to get it to work.
Here is what I tried in TalkPeer::doSelectStmt:
public static function doSelectStmt(Criteria $criteria, PropelPDO $con = null)
{
$keys = array('models.Visit'=>1,'models.Comment'=>2,'models.Rating'=>3,'models.Review'=>4);
$class_name = self::getOMClass();
if(isset($keys[$class_name]))
{ //Talk itself is not a returnable type, so we must check
$class_key = $keys[$class_name];
$criteria->add(TalkPeer::CLASS_KEY, $class_key);
}
return parent::doSelectStmt($criteria, $con = null);
}
Here is an example of my getOMClass method from ReviewPeer:
public static function getOMClass()
{
return self::CLASSNAME_4; //aka 'talk.Review';
}
Here is the relevant bit of my schema:
<table name="talk" idMethod="native" abstract="true">
<column name="talk_pk" type="INTEGER" required="true" autoIncrement="true" primaryKey="true" />
<column name="class_key" type="INTEGER" required="true" default="" inheritance="single">
<inheritance key="1" class="Visit" extends="models.Talk" />
<inheritance key="2" class="Comment" extends="models.Talk" />
<inheritance key="3" class="Rating" extends="models.Talk" />
<inheritance key="4" class="Review" extends="models.Rating" />
</column>
</table>
P.S. - No, I can't upgrade from 1.3 to 1.4. There's just too much
code that would need to be re-tested