Allows access and automatic saving of fields on HAS_ONE relations.
Notice ¶
Please note I am not using this extension in anything beyond alpha software myself, if you find a bug please leave a comment it and I will fix it ASAP.
Requirements ¶
Tested against 1.1.12 and above.
Rationale ¶
Normalised database schemas avoid the usage of NULL because it generally is reserved for unknown values. This extension allows optional attributes to be moved into other tables and still be referenced directly via the "parent" record.
Usage ¶
Warning: this extension takes some work to integrate, below is an example of some of the CActiveRecord methods you may need to extend to get it to work how you like.
class StockItem extents CActiveRecord
{
/**
* @return array the behaviors.
*/
public function behaviors()
{
return CMap::mergeArray(parent::behaviors(), array(
//Composite
'composite' => array(
'class' => 'ext.ECompositeBehavior',
),
));
}
/**
* Returns array that describes the attribute mapping, the key is the attribute on
* $this record, the corresponding element describes the relation and the
* attribute name on that related record.
* @return array
*/
public function compositeAttributes()
{
return array(
'cost' => array('stockItemCost', 'cost'),
'externalSku' => array('stockItemExternalSku', 'external_sku'),
'supplierSku' => array('stockItemSupplierSku', 'supplier_sku'),
'weight' => array('stockItemWeight', 'weight'),
);
}
/**
* @return array relational rules.
*/
public function relations()
{
return array(
'stockItemCost' => array(
self::HAS_ONE,
'StockItemCost',
'stock_item_id'
),
'stockItemExternalSku' => array(
self::HAS_ONE,
'StockItemExternalSku',
'stock_item_id'
),
'stockItemSupplierSku' => array(
self::HAS_ONE,
'StockItemSupplierSku',
'stock_item_id'
),
'stockItemWeight' => array(
self::HAS_ONE,
'StockItemWeight',
'stock_item_id'
),
);
}
/**
* 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 return CMap::mergeArray(array(
'id' => 'ID',
'name' => 'Name'
), array($compositeBehavior->attributeLabels()));
}
}
Once this is in place you can access the fields cost, externalSku, supplierSku and weight on StockItem records as if they were members, the only caveat is that the the hasAttribute method wont work unless you also override it, I do not use this so I have no example to provide at this time.
These fields can also be set, saved and validated, all using the rules defined on their model but as if they were a part of the parent. Right now it deletes any composite entry that is empty. I have found this to be the best balance.
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.