Thinkphp3.2.3 解決關聯模型的自動生成問題($_auto)
阿新 • • 發佈:2019-01-26
在Thinkphp中,關聯模型經常會被使用到,然而最近在使用的時候發現關聯模型中的自動生成功能有些問題。
例如有一個類IdeaDetailModel對應表oidea_idea_detail,它有一個簡表oidea_idea_simple(類IdeaSimpleModel),IdeaDetailModel程式碼如下(只保留了部分功能):
<?php
namespace Idea\Model;
use Think\Model\RelationModel;
class IdeaDetailModel extends RelationModel
{
protected $tableName = 'idea_detail';
/* 關係模型 */
protected $_link = array(
// 與IdeaSimple關聯(一對一:HAS_ONE)
'Simple' => array(
'mapping_type' => self::HAS_ONE,
'class_name' => 'IdeaSimple',
'mapping_name' => 'Simple',
'foreign_key' => 'iid' ,
'relation_foreign_key' => 'id',
'mapping_fields' => 'star,heart,watch',
),
);
/* Idea模型自動完成 */
protected $_auto = array(
array('read', 0, self::MODEL_INSERT),
array('comment', 0, self::MODEL_INSERT),
array('status', 1, self::MODEL_INSERT),
array ('create_time', NOW_TIME, self::MODEL_INSERT),
array('update_time', NOW_TIME, self::MODEL_BOTH),
);
public function addIdea($uid, $arrIdeaInfo = null)
{
/*做些驗證*/
//寫入資料庫
$data = array('src_uid' => $uid, 'title' => $arrIdeaInfo['title'], 'summary' => $arrIdeaInfo['summary']);
$data['Simple'] = $data;
$data['content'] = $arrIdeaInfo['content'];
$data = $this->create($data);
if (!$data) {
return false;
}
$res = $this->relation(array('Simple'))->add($data);
return $res;
}
}
IdeaSimpleModel類程式碼如下(只保留部分功能):
<?php
namespace Idea\Model;
use Think\Model\RelationModel;
/**
*
*/
class IdeaSimpleModel extends RelationModel
{
/* Idea模型自動完成 */
protected $_auto = array(
array('star', 0, self::MODEL_INSERT),
array('heart', 0, self::MODEL_INSERT),
array('watch', 0, self::MODEL_INSERT),
array('status', 1, self::MODEL_INSERT),
array('update_time', NOW_TIME, self::MODEL_BOTH),
);
}
如果我們呼叫IdeaDetailModel類的addIdea方法,實際上是不能實現IdeaSimpleModel中的自動完成功能的。
解決方法如下(參考了http://www.thinkphp.cn/code/833.html,實際上是對Think\RelationModel類的部分函式進行了覆蓋,而我在其中添加了函式createRelationData):
<?php
namespace Common\Model;
use Think\Model\RelationModel;
/**
* 關聯模型自動完成類,過載RelationModel中的create方法
* 在使用關聯模型並且需要自動完成的時候使用該類
*/
class AutoCompleteRelationModel extends RelationModel
{
/**
* 過載create方法,不過濾欄位,並且生成需要資料
*/
function create($data = '', $type = '') {
// 如果沒有傳值預設取POST資料
if (empty($data)) {
$data = $_POST;
} elseif (is_object($data)) {
$data = get_object_vars($data);
}
// 驗證資料
if (empty($data) || !is_array($data)) {
$this->error = L('_DATA_TYPE_INVALID_');
return false;
}
// 狀態
$type = $type ? $type : (!empty($data[$this->getPk() ]) ? self::MODEL_UPDATE : self::MODEL_INSERT);
// 資料自動驗證
if (!$this->autoValidation($data, $type)) return false;
// 表單令牌驗證
if (!$this->autoCheckToken($data)) {
$this->error = L('_TOKEN_ERROR_');
return false;
}
// 驗證完成生成資料物件
if ($this->autoCheckFields) { // 開啟欄位檢測 則過濾非法欄位資料
$fields = $this->getDbFields();
foreach ($data as $key => $val) {
if (MAGIC_QUOTES_GPC && is_string($val)) {
$data[$key] = stripslashes($val);
}
}
}
// 建立完成對資料進行自動處理
$data=$this->autoOperation($data, $type);
$data = $this->createRelationData($data);
// $data=$this->createData($data);
// 返回建立的資料以供其他呼叫
return $data;
}
/**
* 自動錶單處理
* @access public
* @param array $data 建立資料
* @param string $type 建立型別
* @return mixed
*/
private function autoOperation($data, $type) {
if (!empty($this->options['auto'])) {
$_auto = $this->options['auto'];
unset($this->options['auto']);
} elseif (!empty($this->_auto)) {
$_auto = $this->_auto;
}
// 自動填充
if (isset($_auto)) {
foreach ($_auto as $auto) {
// 填充因子定義格式
// array('field','填充內容','填充條件','附加規則',[額外引數])
if (empty($auto[2])) $auto[2] = self::MODEL_INSERT; // 預設為新增的時候自動填充
if ($type == $auto[2] || $auto[2] == self::MODEL_BOTH) {
switch (trim($auto[3])) {
case 'function': // 使用函式進行填充 欄位的值作為引數
case 'callback': // 使用回撥方法
$args = isset($auto[4]) ? (array)$auto[4] : array();
if (isset($data[$auto[0]])) {
array_unshift($args, $data[$auto[0]]);
}
if ('function' == $auto[3]) {
$data[$auto[0]] = call_user_func_array($auto[1], $args);
} else {
$data[$auto[0]] = call_user_func_array(array(&$this,
$auto[1]
) , $args);
}
break;
case 'field': // 用其它欄位的值進行填充
$data[$auto[0]] = $data[$auto[1]];
break;
case 'ignore': // 為空忽略
if ('' === $data[$auto[0]]) unset($data[$auto[0]]);
break;
case 'string':
default: // 預設作為字串填充
$data[$auto[0]] = $auto[1];
}
if (false === $data[$auto[0]]) unset($data[$auto[0]]);
}
}
}
return $data;
}
/**
* 生成關聯模型需要的資料
*/
function createData($data) {
foreach ($data as $k => $v) {
if (in_array($k, $this->fields)) {
$data['Detail'][$k] = $v;
unset($data[$k]);
}
}
//刪除多餘欄位
unset($data['nid']);
unset($data['create_date']);
return $data;
}
/**
* ADD
* 對關聯模型使用D函式,從而實現自動完成
*/
function createRelationData($data)
{
$linkKeys = array_keys($this->_link);
if (empty($linkKeys) || !is_array($linkKeys)) {
return $data;
}
$arrMappingName = array();
foreach ($linkKeys as $index => $key) {
if (isset($this->_link[$key]['mapping_name'])) {
array_push($arrMappingName, $this->_link[$key]['mapping_name']);
unset($linkKeys[$index]);
}
}
$arrMappingName = array_merge($arrMappingName, $linkKeys);
foreach ($data as $model => $item) {
if (in_array($model, $arrMappingName)) {
$tempData = D($this->_link[$model]['class_name'])->create($item);
$data[$model] = $tempData;
}
}
return $data;
}
}
這樣就可以讓關聯模型支援自動完成功能了。使用方法:
<?php
namespace Idea\Model;
use Common\Model\AutoCompleteRelationModel;
// use Think\Model\RelationModel;
/**
* Idea model
* 對應表oidea_idea
*/
class IdeaDetailModel extends AutoCompleteRelationModel
{
/*同上,不變*/
}
水平有限,歡迎指正~