text: <?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;
      }
  }