ThinkPHP3.2.5的Model基類,有些文件中沒提到的方法,可以經常看看。
阿新 • • 發佈:2018-11-08
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <[email protected]>
// +----------------------------------------------------------------------
namespace Think;
/**
* ThinkPHP Model模型類
* 實現了ORM和ActiveRecords模式
*/
class Model
{
// 操作狀態
const MODEL_INSERT = 1; // 插入模型資料
const MODEL_UPDATE = 2; // 更新模型資料
const MODEL_BOTH = 3; // 包含上面兩種方式
const MUST_VALIDATE = 1; // 必須驗證
const EXISTS_VALIDATE = 0; // 表單存在欄位則驗證
const VALUE_VALIDATE = 2; // 表單值不為空則驗證
// 當前資料庫操作物件
protected $db = null;
// 資料庫物件池
private $_db = array();
// 主鍵名稱
protected $pk = 'id';
// 主鍵是否自動增長
protected $autoinc = false;
// 資料表字首
protected $tablePrefix = null;
// 模型名稱
protected $name = '';
// 資料庫名稱
protected $dbName = '';
//資料庫配置
protected $connection = '';
// 資料表名(不包含表字首)
protected $tableName = '';
// 實際資料表名(包含表字首)
protected $trueTableName = '';
// 最近錯誤資訊
protected $error = '';
// 欄位資訊
protected $fields = array();
// 資料資訊
protected $data = array();
// 查詢表示式引數
protected $options = array();
protected $_validate = array(); // 自動驗證定義
protected $_auto = array(); // 自動完成定義
protected $_map = array(); // 欄位對映定義
protected $_scope = array(); // 命名範圍定義
// 是否自動檢測資料表字段資訊
protected $autoCheckFields = true;
// 是否批處理驗證
protected $patchValidate = false;
// 鏈操作方法列表
protected $methods = array('strict', 'order', 'alias', 'having', 'group', 'lock', 'distinct', 'auto', 'filter', 'validate', 'result', 'token', 'index', 'force', 'master');
/**
* 架構函式
* 取得DB類的例項物件 欄位檢查
* @access public
* @param string $name 模型名稱
* @param string $tablePrefix 表字首
* @param mixed $connection 資料庫連線資訊
*/
public function __construct($name = '', $tablePrefix = '', $connection = '')
{
// 模型初始化
$this->_initialize();
// 獲取模型名稱
if (!empty($name)) {
if (strpos($name, '.')) {
// 支援 資料庫名.模型名的 定義
list($this->dbName, $this->name) = explode('.', $name);
} else {
$this->name = $name;
}
} elseif (empty($this->name)) {
$this->name = $this->getModelName();
}
// 設定表字首
if (is_null($tablePrefix)) {
// 字首為Null表示沒有字首
$this->tablePrefix = '';
} elseif ('' != $tablePrefix) {
$this->tablePrefix = $tablePrefix;
} elseif (!isset($this->tablePrefix)) {
$this->tablePrefix = !empty($this->connection) && !is_null(C($this->connection . '.DB_PREFIX')) ? C($this->connection . '.DB_PREFIX') : C('DB_PREFIX');
}
// 資料庫初始化操作
// 獲取資料庫操作物件
// 當前模型有獨立的資料庫連線資訊
$this->db(0, empty($this->connection) ? $connection : $this->connection, true);
}
/**
* 自動檢測資料表資訊
* @access protected
* @return void
*/
protected function _checkTableInfo()
{
// 如果不是Model類 自動記錄資料表資訊
// 只在第一次執行記錄
if (empty($this->fields)) {
// 如果資料表字段沒有定義則自動獲取
if (C('DB_FIELDS_CACHE')) {
$fields = F('_fields/' . strtolower($this->getTableName()));
if ($fields) {
$this->fields = $fields;
if (!empty($fields['_pk'])) {
$this->pk = $fields['_pk'];
}
return;
}
}
// 每次都會讀取資料表資訊
$this->flush();
}
}
/**
* 獲取欄位資訊並快取
* @access public
* @return void
*/
public function flush()
{
// 快取不存在則查詢資料表資訊
$this->db->setModel($this->name);
$tableName = $this->getTableName();
$fields = $this->db->getFields($tableName);
if (!$fields) {
// 無法獲取欄位資訊
return false;
}
$this->fields = array_keys($fields);
unset($this->fields['_pk']);
foreach ($fields as $key => $val) {
// 記錄欄位型別
$type[$key] = $val['type'];
if ($val['primary']) {
// 增加複合主鍵支援
if (isset($this->fields['_pk']) && null != $this->fields['_pk']) {
if (is_string($this->fields['_pk'])) {
$this->pk = array($this->fields['_pk']);
$this->fields['_pk'] = $this->pk;
}
$this->pk[] = $key;
$this->fields['_pk'][] = $key;
} else {
$this->pk = $key;
$this->fields['_pk'] = $key;
}
if ($val['autoinc']) {
$this->autoinc = true;
}
}
}
// 記錄欄位型別資訊
$this->fields['_type'] = $type;
// 2008-3-7 增加快取開關控制
if (C('DB_FIELDS_CACHE')) {
// 永久快取資料表資訊
F('_fields/' . strtolower($tableName), $this->fields);
}
}
/**
* 設定資料物件的值
* @access public
* @param string $name 名稱
* @param mixed $value 值
* @return void
*/
public function __set($name, $value)
{
// 設定資料物件屬性
$this->data[$name] = $value;
}
/**
* 獲取資料物件的值
* @access public
* @param string $name 名稱
* @return mixed
*/
public function __get($name)
{
return isset($this->data[$name]) ? $this->data[$name] : null;
}
/**
* 檢測資料物件的值
* @access public
* @param string $name 名稱
* @return boolean
*/
public function __isset($name)
{
return isset($this->data[$name]);
}
/**
* 銷燬資料物件的值
* @access public
* @param string $name 名稱
* @return void
*/
public function __unset($name)
{
unset($this->data[$name]);
}
/**
* 利用__call方法實現一些特殊的Model方法
* @access public
* @param string $method 方法名稱
* @param array $args 呼叫引數
* @return mixed
*/
public function __call($method, $args)
{
if (in_array(strtolower($method), $this->methods, true)) {
// 連貫操作的實現
$this->options[strtolower($method)] = $args[0];
return $this;
} elseif (in_array(strtolower($method), array('count', 'sum', 'min', 'max', 'avg'), true)) {
// 統計查詢的實現
$field = isset($args[0]) ? $args[0] : '*';
return $this->getField(strtoupper($method) . '(' . $this->db->parseKey($field, true) . ') AS tp_' . $method);
} elseif (strtolower(substr($method, 0, 5)) == 'getby') {
// 根據某個欄位獲取記錄
$field = parse_name(substr($method, 5));
$where[$field] = $args[0];
return $this->where($where)->find();
} elseif (strtolower(substr($method, 0, 10)) == 'getfieldby') {
// 根據某個欄位獲取記錄的某個值
$name = parse_name(substr($method, 10));
$where[$name] = $args[0];
return $this->where($where)->getField($args[1]);
} elseif (isset($this->_scope[$method])) {
// 命名範圍的單獨呼叫支援
return $this->scope($method, $args[0]);
} else {
E(__CLASS__ . ':' . $method . L('_METHOD_NOT_EXIST_'));
return;
}
}
// 回撥方法 初始化模型
protected function _initialize()
{}
/**
* 對儲存到資料庫的資料進行處理
* @access protected
* @param mixed $data 要操作的資料
* @return boolean
*/
protected function _facade($data)
{
// 檢查資料欄位合法性
if (!empty($this->fields)) {
if (!empty($this->options['field'])) {
$fields = $this->options['field'];
unset($this->options['field']);
if (is_string($fields)) {
$fields = explode(',', $fields);
}
} else {
$fields = $this->fields;
}
foreach ($data as $key => $val) {
if (!in_array($key, $fields, true)) {
if (!empty($this->options['strict'])) {
E(L('_DATA_TYPE_INVALID_') . ':[' . $key . '=>' . $val . ']');
}
unset($data[$key]);
} elseif (is_scalar($val)) {
// 欄位型別檢查 和 強制轉換
$this->_parseType($data, $key);
}
}
}
// 安全過濾
if (!empty($this->options['filter'])) {
$data = array_map($this->options['filter'], $data);
unset($this->options['filter']);
}
$this->_before_write($data);
return $data;
}
// 寫入資料前的回撥方法 包括新增和更新
protect