<?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;

    }

}