Difference between #3 and #4 of Extending an ActiveRecord model

unchanged
Title
Extending an ActiveRecord model
unchanged
Category
How-tos
unchanged
Tags
active record, CActiveRecord, extending
changed
Content
Introduction
============
Let's say that we have an ActiveRecord model that we want to refine with extra
data, we could go and add columns to the database and include them in the
ActiveRecord model. 
Example
-------
We have an ActiveRecord class called 'vehicle':
~~~
[php]
class vehicle extends CActiveRecord {
  public $manufacturer;
  public $manufacture_date;
  public $price;
...
// rest of normal active record stuff
...
}
~~~
Now lets say we want some sub classes of vehicle,
~~~
[php]
class car extends vehicle{
  public $number_of_wheels;
  public $number_of_doors;
  public $hasSunroof;
}
class boat extends vehicle{
  public $number_of_hulls;
  public $hasSail;
}
class plane extends vehicle{
  public $maximum_altitude;
  public $number_of_seats;
}
~~~
Adding all of the these extra columns for all the subclasses to the database
will cause the table to become very big very quickly, and only a handful of the
columns on each row would be populated.
As long as we're not too worried about sorting and searching the extra data we
can include it as a single extra text column in the original vehicle table -
we'll call it 'params'.
Now we can extend the original vehicle class as follows:
~~~
[php]
class vehicleExtended extends vehicle{
  /**
   * @var string The name of the class
   */
  public $name;

  protected $_viewFile

  /**
   * We can have different view files for the different classes
   * @return string The view file location
   */
  public function getViewFile() {
      return $this->_viewFile;
  }
  /**
   * Returns the static model of the specified AR class.
   * @param string $className active record class name.
   * @return VisitServiceItem the static model class
   */
   public static function model($className = __CLASS__) {
      return parent::model($className);
   }
  /**
    * Saves meta data* Overrides the ActiveRecord save to insert
the extra parameters
   * This class has into JSON text and save it in the params
attribute
    * @return boolean
    */data base
   */
  public function beforeSave()save($runValidation = true,
$attributes = null) {
     $this->name = get_class($this);
     $vars = get_object_vars($this);
     $this->params = json_encode($vars);
     return parent::save($runValidation, $attributes);
  }
  /**
    * Creates* Overrides the correct class
typeActiveRecord function to read the extra params and
populates
   * create a new class based on the meta data
    * @param array $attributes
    * @return CActiveRecord
    */
   public and return the sub class
   */
  public function instantiate($attributes)findByPk($pk,
$condition = '', $params = array()) {
       $vars
     $result =
json_decode($attributes['params'],parent::findByPk($pk,
$condition, $params);
     if ($result !== null) {
         $extendedVars = json_decode($result->params, true);
       $type
         $type = $vars['name'];
       $subClass$extendedVars['name'];
         $subClass = new $type;
       foreach ($vars
         foreach ($extendedVars as $key => $var) {
           if
             if (property_exists($subClass, $key)) {
               $subClass->$key
                 $subClass->$key = $var;
           }
       }
       return
             }
         }
         $subClass->attributes = $result->attributes;
         return $subClass;
     }
     return false;
   }
}
~~~
Now all we need to do is change the subclass definitions to extend from this new
class
~~~
[php]
class car extends vehicleExtended{
  public $number_of_wheels;
  public $number_of_doors;
  public $hasSunroof;
  protected $_viewFile = 'application.views.vehicles.car';
}
class boat extends vehicleExtended{
  public $number_of_hulls;
  public $hasSail;
  protected $_viewFile = 'application.views.vehicles.boat';
}
class plane extends vehicleExtended{
  public $maximum_altitude;
  public $number_of_seats;
  protected $_viewFile = 'application.views.vehicles.plane';
}
~~~
As I said, this works well when the extra data just needs to be saved and not
indexed.
Any comments welcome.