Last active
November 24, 2015 09:54
-
-
Save luckily/fe48cf69216a49dc433f to your computer and use it in GitHub Desktop.
yii 1.1 CActiveRecord eager load behavior
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class ActiveEagerLoader extends CActiveRecordBehavior | |
{ | |
private $_relationKeys = array(); | |
public function with($keys = array()) | |
{ | |
if(!is_array($keys)) | |
throw new Exception('Only support array type values'); | |
$this->_relationKeys = $keys; | |
return $this; | |
} | |
public function findAll($condition = '', $params = array()) | |
{ | |
$criteria = $this->owner->getCommandBuilder()->createCriteria($condition, $params); | |
if(!empty($this->_relationKeys)) | |
return $this->query($criteria, true); | |
return $this->owner->findAll($condition, $params); | |
} | |
public function find($condition = '', $params = array()) | |
{ | |
$criteria = $this->owner->getCommandBuilder()->createCriteria($condition, $params); | |
if(!empty($this->_relationKeys)) | |
return $this->query($criteria); | |
return $this->owner->find($condition, $params); | |
} | |
protected function query($criteria, $all = false) | |
{ | |
$this->owner->beforeFindInternal(); | |
$this->owner->applyScopes($criteria); | |
$finder = $this->getEagerFinder($criteria); | |
return $finder->query($all); | |
} | |
protected function getEagerFinder($criteria) | |
{ | |
return new EagerFinder($this->owner, $criteria, $this->_relationKeys); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class EagerFinder extends CComponent | |
{ | |
// const BELONGS_TO = 'CBelongsToRelation'; | |
// const HAS_ONE = 'CHasOneRelation'; | |
// const HAS_MANY = 'CHasManyRelation'; | |
// const MANY_MANY = 'CManyManyRelation'; | |
// const STAT = 'CStatRelation'; | |
private $_mainModel = null; | |
private $_builder = null; | |
private $_dbCriteria = null; | |
private $_relationKeys = array(); | |
public function __construct($model, $criteria, $relationKeys) | |
{ | |
$this->_mainModel = $model; | |
$this->_builder = $model->getCommandBuilder(); | |
$this->_dbCriteria = $criteria; | |
$this->_relationKeys = $relationKeys; | |
} | |
public function query($all = false) | |
{ | |
Yii::trace(get_class($this).__METHOD__); | |
if(($rows = $this->_builder->createFindCommand($this->_mainModel->getTableSchema(), $this->_dbCriteria)->queryAll())!==array()) | |
{ | |
$baseRecords = $this->_mainModel->populateRecords($rows, false); | |
return $this->populateRecordsWithRelation($baseRecords); | |
} | |
else | |
{ | |
return array(); | |
} | |
} | |
public function populateRecordsWithRelation($mainModels) | |
{ | |
Yii::trace(get_class($this).__METHOD__); | |
/** | |
* formula:'VarName'=>array('RelationType', 'ClassName', 'ForeignKey', ...additional options) | |
*/ | |
$tempData = array(); | |
foreach($this->_relationKeys as $relationAttributeName) | |
{ | |
if(isset($this->_mainModel->relations()[$relationAttributeName])) | |
{ | |
$relationSetting = $this->_mainModel->relations()[$relationAttributeName]; | |
switch ($relationSetting[0]) { | |
case CActiveRecord::BELONGS_TO: | |
$foreignKey = $relationSetting[2]; | |
$relationConditionIds = array(); | |
foreach($mainModels as $mainModel) | |
{ | |
$relationConditionIds[] = $mainModel->$foreignKey; | |
} | |
$criteria = new CDbCriteria; | |
$criteria->addInCondition('id', array_unique($relationConditionIds)); | |
$relationModels = $this->getModel($relationSetting[1])->findAll($criteria); | |
foreach ($mainModels as $mainModel) | |
{ | |
$populateModel = array_filter($relationModels, function($relationModel) use($mainModel, $foreignKey) { | |
return $mainModel->$foreignKey == $relationModel->id; | |
}); | |
$mainModel->addRelatedRecord($relationAttributeName, reset($populateModel), false); | |
} | |
break; | |
case CActiveRecord::HAS_ONE: | |
var_dump($relationSetting);exit; | |
break; | |
case CActiveRecord::HAS_MANY: | |
var_dump($relationSetting);exit; | |
break; | |
case CActiveRecord::MANY_MANY: | |
var_dump($relationSetting);exit; | |
break; | |
default: | |
throw new Exception("can not find {$relationAttributeName} relation setting."); | |
break; | |
} | |
return $mainModels; | |
} | |
throw new Exception("can not find {$relationKey} relation setting."); | |
} | |
} | |
public function getModel($className) | |
{ | |
return CActiveRecord::model($className); | |
} | |
/** | |
* 1.先趴$with, 存成陣列 | |
* 2.解析陣列with, 然後再一一解析, master-model是否有跟with陣列的值對應到(可能要花時間瞭解model的relations()有哪些規格形式) | |
* 3.1foreach with, 組成各別的query | |
* 3.2如果with裡面還有再關連的東西, 就再遞回一次(額外功能,V2版本再做) | |
* 4.把master跟relation的model的query丟到querybuilder | |
* 5.把querybuilder的物件's做populate的動作 | |
* 6.回傳master的models | |
*/ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment