<?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 ViewModel extends Model {

    protected $viewFields = array();

    /**
     * 自动检测数据表信息
     * @access protected
     * @return void
     */
    protected function _checkTableInfo() {}

    /**
     * 得到完整的数据表名
     * @access public
     * @return string
     */
    public function getTableName() {
        if(empty($this->trueTableName)) {
            $tableName = '';
            foreach ($this->viewFields as $key=>$view){
                // 获取数据表名称
                if(isset($view['_table'])) { // 2011/10/17 添加实际表名定义支持 可以实现同一个表的视图
                    $tableName .=   $view['_table'];
                    $prefix     =   $this->tablePrefix;
                    $tableName  =   preg_replace_callback("/__([A-Z_-]+)__/sU", function($match) use($prefix){ return $prefix.strtolower($match[1]);}, $tableName);
                }else{
                    $class  =   $key.'Model';
                    $Model  =  class_exists($class)?new $class():M($key);
                    $tableName .= $Model->getTableName();
                }
                // 表别名定义
                $tableName .= !empty($view['_as'])?' '.$view['_as']:' '.$key;
                // 支持ON 条件定义
                $tableName .= !empty($view['_on'])?' ON '.$view['_on']:'';
                // 指定JOIN类型 例如 RIGHT INNER LEFT 下一个表有效
                $type = !empty($view['_type'])?$view['_type']:'';
                $tableName   .= ' '.strtoupper($type).' JOIN ';
                $len  =  strlen($type.'_JOIN ');
            }
            $tableName = substr($tableName,0,-$len);
            $this->trueTableName    =   $tableName;
        }
        return $this->trueTableName;
    }

    /**
     * 表达式过滤方法
     * @access protected
     * @param string $options 表达式
     * @return void
     */
    protected function _options_filter(&$options) {
        if(isset($options['field']))
            $options['field'] = $this->checkFields($options['field']);
        else
            $options['field'] = $this->checkFields();
        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 string $name 模型名称
     * @param array $fields 字段数组
     * @return array
     */
    private function _checkFields($name,$fields) {
        if(false !== $pos = array_search('*',$fields)) {// 定义所有字段
            $fields  =  array_merge($fields,M($name)->getDbFields());
            unset($fields[$pos]);
        }
        return $fields;
    }

    /**
     * 检查条件中的视图字段
     * @access protected
     * @param mixed $data 条件表达式
     * @return array
     */
    protected function checkCondition($where) {
        if(is_array($where)) {
            $view   =   array();
            // 检查视图字段
            foreach ($this->viewFields as $key=>$val){
                $k = isset($val['_as'])?$val['_as']:$key;
                $val  =  $this->_checkFields($key,$val);
                foreach ($where as $name=>$value){
                    if(false !== $field = array_search($name,$val,true)) {
                        // 存在视图字段
                        $_key   =   is_numeric($field)?    $k.'.'.$name   :   $k.'.'.$field;
                        $view[$_key]    =   $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';
                // 解析成视图字段
                foreach ($this->viewFields as $name=>$val){
                    $k = isset($val['_as'])?$val['_as']:$name;
                    $val  =  $this->_checkFields($name,$val);
                    if(false !== $_field = array_search($field,$val,true)) {
                        // 存在视图字段
                        $field     =  is_numeric($_field)?$k.'.'.$field:$k.'.'.$_field;
                        break;
                    }
                }
                $_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){
                // 解析成视图字段
                foreach ($this->viewFields as $name=>$val){
                    $k = isset($val['_as'])?$val['_as']:$name;
                    $val  =  $this->_checkFields($name,$val);
                    if(false !== $_field = array_search($field,$val,true)) {
                        // 存在视图字段
                        $field     =  is_numeric($_field)?$k.'.'.$field:$k.'.'.$_field;
                        break;
                    }
                }
                $_group[] = $field;
            }
            $group  =   implode(',',$_group);
         }
        return $group;
    }

    /**
     * 检查fields表达式中的视图字段
     * @access protected
     * @param string $fields 字段
     * @return string
     */
    protected function checkFields($fields='') {
        if(empty($fields) || '*'==$fields ) {
            // 获取全部视图字段
            $fields =   array();
            foreach ($this->viewFields as $name=>$val){
                $k = isset($val['_as'])?$val['_as']:$name;
                $val  =  $this->_checkFields($name,$val);
                foreach ($val as $key=>$field){
                    if(is_numeric($key)) {
                        $fields[]    =   $k.'.'.$field.' AS '.$field;
                    }elseif('_' != substr($key,0,1)) {
                        // 以_开头的为特殊定义
                        if( false !== strpos($key,'*') ||  false !== strpos($key,'(') || false !== strpos($key,'.')) {
                            //如果包含* 或者 使用了sql方法 则不再添加前面的表名
                            $fields[]    =   $key.' AS '.$field;
                        }else{
                            $fields[]    =   $k.'.'.$key.' AS '.$field;
                        }
                    }
                }
            }
            $fields = implode(',',$fields);
        }else{
            if(!is_array($fields))
                $fields =   explode(',',$fields);
            // 解析成视图字段
            $array =  array();
            foreach ($fields as $key=>$field){
                if(strpos($field,'(') || strpos(strtolower($field),' as ')){
                    // 使用了函数或者别名
                    $array[] =  $field;
                    unset($fields[$key]);
                }
            }
            foreach ($this->viewFields as $name=>$val){
                $k = isset($val['_as'])?$val['_as']:$name;
                $val  =  $this->_checkFields($name,$val);
                foreach ($fields as $key=>$field){
                    if(false !== $_field = array_search($field,$val,true)) {
                        // 存在视图字段
                        if(is_numeric($_field)) {
                            $array[]    =   $k.'.'.$field.' AS '.$field;
                        }elseif('_' != substr($_field,0,1)){
                            if( false !== strpos($_field,'*') ||  false !== strpos($_field,'(') || false !== strpos($_field,'.'))
                                //如果包含* 或者 使用了sql方法 则不再添加前面的表名
                                $array[]    =   $_field.' AS '.$field;
                            else
                                $array[]    =   $k.'.'.$_field.' AS '.$field;
                        }
                    }
                }
            }
            $fields = implode(',',$array);
        }
        return $fields;
    }
}