问题
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
回答1:
Why don't you just remove the abstract=true statements so you generate all Peers, then add the abstract again, generate again to get the db exactly as you like it?
回答2:
Ive never used inheritance in Propel but you should be able to modify the doSelectRS methods on each Peer class to modify the criteria and specify the extra condition for the inheritance key. I dont have the docs in front of me but in pseudo code itd look something like this:
public static function doSelectRS(Criteria $c)
{
// you may want to check if the condition already exists in one of the criterion's before doing the following...
$c->add(RatingPeer::TYPE, 3);
return parent::doSelectRS($c);
}
来源:https://stackoverflow.com/questions/2067354/propel-single-table-inheritance-issue