Difference between #4 and #3 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);
   }
  /**
   * Overrides the ActiveRecord save to insert the extra parameters
   * This class has into JSON text and save it * Saves meta
data in the data base
   */params attribute
    * @return boolean
    */
  public function save($runValidation = true, $attributes =
null)beforeSave() {
     $this->name = get_class($this);
     $vars = get_object_vars($this);
     $this->params = json_encode($vars);
     return parent::save($runValidation, $attributes);
  }
  /**
   * Overrides * Creates the ActiveRecord function to
read the extra paramscorrect class type and
   * create a new class based on populates the meta
data and return the sub class
   */
  public
    * @param array $attributes
    * @return CActiveRecord
    */
   public function findByPk($pk, $condition = '', $params =
array())instantiate($attributes) {
     $result
       $vars = parent::findByPk($pk, $condition, $params);
     if ($result !== null) {
         $extendedVars =
json_decode($result->params,json_decode($attributes['params'],
true);
         $type
       $type = $extendedVars['name'];
         $subClass$vars['name'];
       $subClass = new $type;
         foreach ($extendedVars
       foreach ($vars as $key => $var) {
             if
           if (property_exists($subClass, $key)) {
                 $subClass->$key
               $subClass->$key = $var;
             }
         }
         $subClass->attributes = $result->attributes;
         return
           }
       }
       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.
Write new article