Page 1 of 1

Extending Objects

Posted: Sat Mar 14, 2009 11:42 pm
by Benjamin
I'm trying to figure out the best way to extend objects.

Reference the following code:

Code: Select all

 
abstract class BaseState extends BaseObject implements Persistent {
// code
}
 
class State extends BaseState {
// code
}
 
Now, to get a state object I can do this:

Code: Select all

 
$c = new Criteria();
$c->add(StatePeer::NAME, 'Florida');
$state = StatePeer::doSelectOne();
 
That gives me an instance of the State class. What I want to do is get the number of people that meet certain criteria in that state so I can generate a report. So my instinct was to extend the State class:

Code: Select all

 
class CasesByState extends State {
    public function getCaseCount($year = null) {
        // get the number of cases in this state
    }
}
 
But something doesn't seem right here. In order for me to populate an instance of the CasesByState it looks like I have to do something like this:

Code: Select all

 
# create db criteria
$query = new Criteria();
$query->add(StatePeer::NAME, 'Florida');
 
# get an instance of State
$state = StatePeer::doSelectOne($c);
 
# create instance of CasesByState
$cases = new CasesByState();
 
# copy State into CasesByState
$state->copyInto($cases);
 
So, that doesn't seem right. Maybe I need to extend the StatePeer class too?

Here is the code that populates an object from a PDO Statement in BaseStatePeer. StatePeer extends BaseStatePeer.

Code: Select all

 
/**
 * The returned array will contain objects of the default type or
 * objects that inherit from the default.
 *
 * @throws     PropelException Any exceptions caught during processing will be
 *       rethrown wrapped into a PropelException.
 */
public static function populateObjects(PDOStatement $stmt)
{
    $results = array();
 
    // set the class once to avoid overhead in the loop
    $cls = StatePeer::getOMClass();
    $cls = substr('.'.$cls, strrpos('.'.$cls, '.') + 1);
    // populate the object(s)
    while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
        $key = StatePeer::getPrimaryKeyHashFromRow($row, 0);
        if (null !== ($obj = StatePeer::getInstanceFromPool($key))) {
            $results[] = $obj;
        } else {
            $obj = new $cls();
            $obj->hydrate($row);
            $results[] = $obj;
            StatePeer::addInstanceToPool($obj, $key);
        } // if key exists
    }
    $stmt->closeCursor();
    return $results;
}
 
Just need to be pointed in the right direction.

Re: Extending Objects

Posted: Sun Mar 15, 2009 12:09 am
by Chris Corbyn
Is this for Propel? If it is, Propel already provide the correct hierarchy:

Code: Select all

class BaseState ... {
   ...
   //Common (and needed) methods here
   ...
}
 
class State extends BaseState {
  //Nothing here... start adding your own stuff
}
You're supposed to edit the State class Propel provides, but not edit the BaseState class which Propel may overwrite if you change your schema/mapping.

Apologies if you're not asking about Propel, but that's what I deduced from your post.

If your problem is more of a general one. That being "How do I add functionality to an existing object", I believe that the Wrapper pattern is what you need:

Code: Select all

class MyState {
  private $_stateDelegate;
  public function __construct(State $stateDelegate) {
    $this->_stateDelegate = $stateDelegate;
  }
  
  public function methodThatExistsInState($arg) {
    return $this->stateDelegate->methodThatExistsInState($arg);
  }
  
  public function specialAddedMethod($arg1, $arg2) {
   // ... do things with the underlying State instance ...
   return $someResult;
  }
}
 
$myState = new MyState($state);
 
Magic method __call() can help cut out the boilerplate code, even that introduces some problems of its own.

Re: Extending Objects

Posted: Sun Mar 15, 2009 12:15 am
by Benjamin
Yes, propel is involved here.

I suppose I can just add a method to the State class to retrieve the Cases count. That's basically all I need to do and it's probably the correct solution.

But this does raise another question.

If I call StatePeer::doSelectOne(), how can I get that to retrieve an instance of CasesByState rather than State. Do I have to create a method in StatePeer calld doSelectCasesByStateOne()? Would there ever be a reason for me to extend the State class?

Re: Extending Objects

Posted: Sun Mar 15, 2009 12:23 am
by Chris Corbyn
astions wrote:I suppose I can just add a method to the State class to retrieve the Cases count. That's basically all I need to do and it's probably the correct solution.
Correct. This is what Propel intends for you to do. The State class is generated, but it's empty so you can edit it.
If I call StatePeer::doSelectOne(), how can I get that to retrieve an instance of CasesByState rather than State. Do I have to create a method in StatePeer calld doSelectCasesByStateOne()? Would there ever be a reason for me to extend the State class?
If you really wanted to do that you'd have to edit StatePeer to override the doSelectOne() method. Propel also provides an empty StatePeer class (extends BaseStatePeer) so that you can do this sort of thing.

Re: Extending Objects

Posted: Sun Mar 15, 2009 12:41 am
by Benjamin
Ok great. Thank you :)