views:

277

answers:

2

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

A: 

Ive never used inheritance in Propel but you should be able to modify the doSelectRS methods on each Peer class to modify the cirteria and specify the extra condition for the iheritance 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);
}
prodigitalson
None of the official docs mention doing this, and I would like to avoid customizing each Peer if at all possible. When dealing with Propel I've come to believe that less customization = fewer bugs.
lo_fye
haha oh i agree. and the way the docs read it sounds as if you are doing everything properly. the ambiguous part is the core of your issue though (ie. are they expected to return all subclasses as you are experiencing or are they supposed to return only the subclass for the Peer used). i dont think it has anything to do with overriding populate objects - i think thats for if you only want properties that apply to a given subclass set in the entity. I dont have a propel project set up - do you think you could post the body of `populateObjects` and `doSelect`?
prodigitalson
I think doSelectRS is a Propel 1.2 thing. I remember it, but it's nowhere to be found in my 1.3 codebase :( I am trying a variation of your suggestion though, by altering doSelectStmt. 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();
lo_fye
yeah thats right PDO is iuse in > 1.3 so they changed the method to Stmt to reflect it returns a PDOStatement... And that would make since now that i think about because it. So you changed `RatingPeer::doSelectStmt` to overload `BaseRatingPeer::doSelectStmt` - or does `BaseRatingPeer` inherit its `doSelectStmt` logic?
prodigitalson
RatingPeer inherits from TalkPeer, actually, and TalkPeer inherits from BaseTalkPeer. I changed the doSelectStmt in TalkPeer.
lo_fye
A: 

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?

Ron
lo_fye