Do you mean model inheritance? If so there is this wiki entry:
Single Table Inheritance
If you were referring to mixing abstract classes and interfaces with the CActiveRecord object, this is relatively easy. This is the abstract class I currently use in my inheritance structure:
<?php
/**
* CActiveRecord derivative that encapsulates some behaviours specific to this project.
*
* @author Luke Jurgs
* @version 0.0.1-2012-10-05
*
* The following are virtual properties
* @property bool isEmpty are the attributes belonging to this empty?
*
* The following are properties and methods added by behaviors:
* @see PopulateBehavior
* @method mixed populateFromPost(string $postIndex = null)
* @method mixed populateFromGet(string $getIndex = null)
* @method mixed populateFromRequest(string $requestIndex = null)
*/
abstract class ActiveRecord extends CActiveRecord
{
/**
* Overrides the parent implementation to be composite friendly, can return composite attributes if the
* composite behaviour is found.
* @param mixed $names names of attributes whose value needs to be returned.
* If this is true (default), then all attribute values will be returned, including
* those that are not loaded from DB (null will be returned for those attributes).
* If this is null, all attributes except those that are not loaded from DB will be returned.
* @return array attribute values indexed by attribute names.
*/
public function getAttributes($names = true)
{
$attributes = parent::getAttributes($names);
if (null !== ($compositeBehavior = $this->asa('composite')))
{
$attributes = CMap::mergeArray($attributes, $compositeBehavior->getAttributes($names));
}
return $attributes;
}
/**
* Overrides the parent implementation to be composite friendly, can return composite attributes if the
* composite behaviour is found.
* @return array attribute labels (name=>label)
*/
public function attributeLabels()
{
if (null === ($compositeBehavior = $this->asa('composite')))
{
return array();
}
return $compositeBehavior->attributeLabels();
}
/**
* Create a new ActiveRecord from the supplied attributes.
* @param array $attributes attribute values to be set to the new ActiveRecord.
* @return ActiveRecord
*/
public static function fromAttributes($attributes)
{
$model = new static;
$model->attributes = $attributes;
return $model;
}
/**
* Determines if the column attributes in this record are all empty.
* @see StringHelper::isEmpty
* @param bool $excludePrimaryKey exclude the primary key from the operation.
* @return bool this record is empty.
*/
public function getIsEmpty($excludePrimaryKey = false)
{
$attributes = $this->attributes;
if ($excludePrimaryKey)
{
$primaryKey = $this->tableSchema->primaryKey;
if (is_string($primaryKey))
{
$primaryKey = array($primaryKey);
}
$primaryKey = array_flip($primaryKey);
$attributes = array_diff_key($attributes, $primaryKey);
}
foreach ($attributes as $attribute)
{
if (!StringHelper::isEmpty($attribute))
{
return false;
}
}
return true;
}
public function behaviors()
{
return array(
//DbUnixTime - Converts between unix timestamps and db timestamps
'dbUnixTime' => array(
'class' => 'DbUnixTimeBehavior',
),
//Populate - Allows for the easy capture of attributes from http submitted data
'populate' => array(
'class' => 'PopulateBehavior',
),
);
}
public function afterConstruct()
{
if (0 !== strcmp('search', $this->scenario) && $this->isNewRecord)
{ //add and update the timestamps where appropriate
if ($this->isDateTimeAttribute('created') && (null === $this->created))
{
$this->setAttribute('created', time());
}
if ($this->isDateTimeAttribute('timestamp') && (null === $this->timestamp))
{
$this->setAttribute('timestamp', time());
}
}
parent::afterConstruct();
}
public function beforeSave()
{
if ($this->isNewRecord && $this->isDateTimeAttribute('updated'))
{
$this->setAttribute('updated', time());
}
if ($this->isDateTimeAttribute('timestamp'))
{
$this->setAttribute('timestamp', time());
}
return parent::beforeSave();
}
private function isDateTimeAttribute($attribute)
{
if ($this->hasAttribute($attribute) && in_array(strtolower($this->tableSchema->columns[$attribute]->dbType),
array('datetime', 'timestamp', 'timestamp without time zone'))
)
{
return true;
}
return false;
}
}
Obviously this is only abstract because I don’t want it being instantiated, not because it has abstract members.
As you can see it just sits between CActiveRecord and my database models. I don’t currently implement any interfaces, I generally find the Yii bundled ones (ArrayAccess and Transverse) sufficient for my needs.