| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- <?php
- // +----------------------------------------------------------------------
- // | 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 <liu21st@gmail.com>
- // +----------------------------------------------------------------------
- namespace Think\Model;
- use Think\Model;
- /**
- * ThinkPHP 聚合模型扩展
- */
- class MergeModel extends Model
- {
- protected $modelList = array(); // 包含的模型列表 第一个必须是主表模型
- protected $masterModel = ''; // 主模型
- protected $joinType = 'INNER'; // 聚合模型的查询JOIN类型
- protected $fk = ''; // 外键名 默认为主表名_id
- protected $mapFields = array(); // 需要处理的模型映射字段,避免混淆 array( id => 'user.id' )
- /**
- * 架构函数
- * 取得DB类的实例对象 字段检查
- * @access public
- * @param string $name 模型名称
- * @param string $tablePrefix 表前缀
- * @param mixed $connection 数据库连接信息
- */
- public function __construct($name = '', $tablePrefix = '', $connection = '')
- {
- parent::__construct($name, $tablePrefix, $connection);
- // 聚合模型的字段信息
- if (empty($this->fields) && !empty($this->modelList)) {
- $fields = array();
- foreach ($this->modelList as $model) {
- // 获取模型的字段信息
- $result = $this->db->getFields(M($model)->getTableName());
- $_fields = array_keys($result);
- // $this->mapFields = array_intersect($fields,$_fields);
- $fields = array_merge($fields, $_fields);
- }
- $this->fields = $fields;
- }
- // 设置第一个模型为主表模型
- if (empty($this->masterModel) && !empty($this->modelList)) {
- $this->masterModel = $this->modelList[0];
- }
- // 主表的主键名
- $this->pk = M($this->masterModel)->getPk();
- // 设置默认外键名 仅支持单一外键
- if (empty($this->fk)) {
- $this->fk = strtolower($this->masterModel) . '_id';
- }
- }
- /**
- * 得到完整的数据表名
- * @access public
- * @return string
- */
- public function getTableName()
- {
- if (empty($this->trueTableName)) {
- $tableName = array();
- $models = $this->modelList;
- foreach ($models as $model) {
- $tableName[] = M($model)->getTableName() . ' ' . $model;
- }
- $this->trueTableName = implode(',', $tableName);
- }
- return $this->trueTableName;
- }
- /**
- * 自动检测数据表信息
- * @access protected
- * @return void
- */
- protected function _checkTableInfo()
- {}
- /**
- * 新增聚合数据
- * @access public
- * @param mixed $data 数据
- * @param array $options 表达式
- * @param boolean $replace 是否replace
- * @return mixed
- */
- public function add($data = '', $options = array(), $replace = false)
- {
- if (empty($data)) {
- // 没有传递数据,获取当前数据对象的值
- if (!empty($this->data)) {
- $data = $this->data;
- // 重置数据
- $this->data = array();
- } else {
- $this->error = L('_DATA_TYPE_INVALID_');
- return false;
- }
- }
- // 启动事务
- $this->startTrans();
- // 写入主表数据
- $result = M($this->masterModel)->strict(false)->add($data);
- if ($result) {
- // 写入外键数据
- $data[$this->fk] = $result;
- $models = $this->modelList;
- array_shift($models);
- // 写入附表数据
- foreach ($models as $model) {
- $res = M($model)->strict(false)->add($data);
- if (!$res) {
- $this->rollback();
- return false;
- }
- }
- // 提交事务
- $this->commit();
- } else {
- $this->rollback();
- return false;
- }
- return $result;
- }
- /**
- * 对保存到数据库的数据进行处理
- * @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)) {
- unset($data[$key]);
- } elseif (array_key_exists($key, $this->mapFields)) {
- // 需要处理映射字段
- $data[$this->mapFields[$key]] = $val;
- unset($data[$key]);
- }
- }
- }
- // 安全过滤
- if (!empty($this->options['filter'])) {
- $data = array_map($this->options['filter'], $data);
- unset($this->options['filter']);
- }
- $this->_before_write($data);
- return $data;
- }
- /**
- * 保存聚合模型数据
- * @access public
- * @param mixed $data 数据
- * @param array $options 表达式
- * @return boolean
- */
- public function save($data = '', $options = array())
- {
- // 根据主表的主键更新
- if (empty($data)) {
- // 没有传递数据,获取当前数据对象的值
- if (!empty($this->data)) {
- $data = $this->data;
- // 重置数据
- $this->data = array();
- } else {
- $this->error = L('_DATA_TYPE_INVALID_');
- return false;
- }
- }
- if (empty($data)) {
- // 没有数据则不执行
- $this->error = L('_DATA_TYPE_INVALID_');
- return false;
- }
- // 如果存在主键数据 则自动作为更新条件
- $pk = $this->pk;
- if (isset($data[$pk])) {
- $where[$pk] = $data[$pk];
- $options['where'] = $where;
- unset($data[$pk]);
- }
- $options['join'] = '';
- $options = $this->_parseOptions($options);
- // 更新操作不使用JOIN
- $options['table'] = $this->getTableName();
- if (is_array($options['where']) && isset($options['where'][$pk])) {
- $pkValue = $options['where'][$pk];
- }
- if (false === $this->_before_update($data, $options)) {
- return false;
- }
- $result = $this->db->update($data, $options);
- if (false !== $result) {
- if (isset($pkValue)) {
- $data[$pk] = $pkValue;
- }
- $this->_after_update($data, $options);
- }
- return $result;
- }
- /**
- * 删除聚合模型数据
- * @access public
- * @param mixed $options 表达式
- * @return mixed
- */
- public function delete($options = array())
- {
- $pk = $this->pk;
- if (empty($options) && empty($this->options['where'])) {
- // 如果删除条件为空 则删除当前数据对象所对应的记录
- if (!empty($this->data) && isset($this->data[$pk])) {
- return $this->delete($this->data[$pk]);
- } else {
- return false;
- }
- }
- if (is_numeric($options) || is_string($options)) {
- // 根据主键删除记录
- if (strpos($options, ',')) {
- $where[$pk] = array('IN', $options);
- } else {
- $where[$pk] = $options;
- }
- $options = array();
- $options['where'] = $where;
- }
- // 分析表达式
- $options['join'] = '';
- $options = $this->_parseOptions($options);
- if (empty($options['where'])) {
- // 如果条件为空 不进行删除操作 除非设置 1=1
- return false;
- }
- if (is_array($options['where']) && isset($options['where'][$pk])) {
- $pkValue = $options['where'][$pk];
- }
- $options['table'] = implode(',', $this->modelList);
- $options['using'] = $this->getTableName();
- if (false === $this->_before_delete($options)) {
- return false;
- }
- $result = $this->db->delete($options);
- if (false !== $result) {
- $data = array();
- if (isset($pkValue)) {
- $data[$pk] = $pkValue;
- }
- $this->_after_delete($data, $options);
- }
- // 返回删除记录个数
- return $result;
- }
- /**
- * 表达式过滤方法
- * @access protected
- * @param string $options 表达式
- * @return void
- */
- protected function _options_filter(&$options)
- {
- if (!isset($options['join'])) {
- $models = $this->modelList;
- array_shift($models);
- foreach ($models as $model) {
- $options['join'][] = $this->joinType . ' JOIN ' . M($model)->getTableName() . ' ' . $model . ' ON ' . $this->masterModel . '.' . $this->pk . ' = ' . $model . '.' . $this->fk;
- }
- }
- $options['table'] = M($this->masterModel)->getTableName() . ' ' . $this->masterModel;
- $options['field'] = $this->checkFields(isset($options['field']) ? $options['field'] : '');
- if (isset($options['group'])) {
- $options['group'] = $this->checkGroup($options['group']);
- }
- if (isset($options['where'])) {
- $options['where'] = $this->checkCondition($options['where']);
- }
- if (isset($options['order'])) {
- $options['order'] = $this->checkOrder($options['order']);
- }
- }
- /**
- * 检查条件中的聚合字段
- * @access protected
- * @param mixed $data 条件表达式
- * @return array
- */
- protected function checkCondition($where)
- {
- if (is_array($where)) {
- $view = array();
- foreach ($where as $name => $value) {
- if (array_key_exists($name, $this->mapFields)) {
- // 需要处理映射字段
- $view[$this->mapFields[$name]] = $value;
- unset($where[$name]);
- }
- }
- $where = array_merge($where, $view);
- }
- return $where;
- }
- /**
- * 检查Order表达式中的聚合字段
- * @access protected
- * @param string $order 字段
- * @return string
- */
- protected function checkOrder($order = '')
- {
- if (is_string($order) && !empty($order)) {
- $orders = explode(',', $order);
- $_order = array();
- foreach ($orders as $order) {
- $array = explode(' ', trim($order));
- $field = $array[0];
- $sort = isset($array[1]) ? $array[1] : 'ASC';
- if (array_key_exists($field, $this->mapFields)) {
- // 需要处理映射字段
- $field = $this->mapFields[$field];
- }
- $_order[] = $field . ' ' . $sort;
- }
- $order = implode(',', $_order);
- }
- return $order;
- }
- /**
- * 检查Group表达式中的聚合字段
- * @access protected
- * @param string $group 字段
- * @return string
- */
- protected function checkGroup($group = '')
- {
- if (!empty($group)) {
- $groups = explode(',', $group);
- $_group = array();
- foreach ($groups as $field) {
- // 解析成聚合字段
- if (array_key_exists($field, $this->mapFields)) {
- // 需要处理映射字段
- $field = $this->mapFields[$field];
- }
- $_group[] = $field;
- }
- $group = implode(',', $_group);
- }
- return $group;
- }
- /**
- * 检查fields表达式中的聚合字段
- * @access protected
- * @param string $fields 字段
- * @return string
- */
- protected function checkFields($fields = '')
- {
- if (empty($fields) || '*' == $fields) {
- // 获取全部聚合字段
- $fields = $this->fields;
- }
- if (!is_array($fields)) {
- $fields = explode(',', $fields);
- }
- // 解析成聚合字段
- $array = array();
- foreach ($fields as $field) {
- if (array_key_exists($field, $this->mapFields)) {
- // 需要处理映射字段
- $array[] = $this->mapFields[$field] . ' AS ' . $field;
- } else {
- $array[] = $field;
- }
- }
- $fields = implode(',', $array);
- return $fields;
- }
- /**
- * 获取数据表字段信息
- * @access public
- * @return array
- */
- public function getDbFields()
- {
- return $this->fields;
- }
- }
|