1. 程式人生 > >Thinkphp3.2.3 解決關聯模型的自動生成問題($_auto)

Thinkphp3.2.3 解決關聯模型的自動生成問題($_auto)

在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
{
    /*同上,不變*/
}

水平有限,歡迎指正~