Single table inheritance

You are viewing revision #1 of this wiki article.
This is the latest version of this article.

Relational databases do not support inheritance so if we need to represent it, we have to somehow store meta info while keeping performance by minimizing JOINs. One way to solve this problem is using single table inheritance. All fields for the whole class tree are stored in a single table. Class name is stored in the type field of the same table.

Schema will be the following:

[sql]

CREATE TABLE `car` (
	`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
	`name` varchar(255) NOT NULL,
	`type` varchar(100) NOT NULL,
	PRIMARY KEY (`id`)
);

Base AR model with overridden instantiate method:

class Car extends CActiveRecord {
	static function model($className=__CLASS__) {
		return parent::model($className);
	}

	function tableName() {
		return 'car';
	}

	/**
	 * We're overriding this method to fill findAll() and similar method result
	 * with proper models.
	 *
	 * @param array $attributes
	 * @return Car
	 */
	protected function instantiate($attributes){
		switch($attributes['type']){
			case 'sport':
				$class='SportCar';
			break;
			case 'family':
				$class='FamilyCar';
			break;
			default:
				$class=get_class($this);
		}
		$model=new $class(null);
		return $model;
	}
}

And, finally, our children:

class SportCar extends Car {
	static function model($className=__CLASS__) {
		return parent::model($className);
	}

	function defaultScope(){
		return array(
			'condition'=>"type='sport'",
		);
	}
}

class FamilyCar extends Car {
	static function model($className=__CLASS__) {
		return parent::model($className);
	}

	function defaultScope(){
		return array(
			'condition'=>"type='family'",
		);
	}
}

In the above we've overridden defaultScope so, for example, when you'll search using FamilyCar model, it will return only family cars.