ViewModel.class.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. namespace Think\Model;
  12. use Think\Model;
  13. /**
  14. * ThinkPHP视图模型扩展
  15. */
  16. class ViewModel extends Model
  17. {
  18. protected $viewFields = array();
  19. /**
  20. * 自动检测数据表信息
  21. * @access protected
  22. * @return void
  23. */
  24. protected function _checkTableInfo()
  25. {}
  26. /**
  27. * 得到完整的数据表名
  28. * @access public
  29. * @return string
  30. */
  31. public function getTableName()
  32. {
  33. if (empty($this->trueTableName)) {
  34. $tableName = '';
  35. foreach ($this->viewFields as $key => $view) {
  36. // 获取数据表名称
  37. if (isset($view['_table'])) {
  38. // 2011/10/17 添加实际表名定义支持 可以实现同一个表的视图
  39. $tableName .= $view['_table'];
  40. $prefix = $this->tablePrefix;
  41. $tableName = preg_replace_callback("/__([A-Z_-]+)__/sU", function ($match) use ($prefix) {return $prefix . strtolower($match[1]);}, $tableName);
  42. } else {
  43. $class = parse_res_name($key, C('DEFAULT_M_LAYER'));
  44. $Model = class_exists($class) ? new $class() : M($key);
  45. $tableName .= $Model->getTableName();
  46. }
  47. // 表别名定义
  48. $tableName .= !empty($view['_as']) ? ' ' . $view['_as'] : ' ' . $key;
  49. // 支持ON 条件定义
  50. $tableName .= !empty($view['_on']) ? ' ON ' . $view['_on'] : '';
  51. // 指定JOIN类型 例如 RIGHT INNER LEFT 下一个表有效
  52. $type = !empty($view['_type']) ? $view['_type'] : '';
  53. $tableName .= ' ' . strtoupper($type) . ' JOIN ';
  54. $len = strlen($type . '_JOIN ');
  55. }
  56. $tableName = substr($tableName, 0, -$len);
  57. $this->trueTableName = $tableName;
  58. }
  59. return $this->trueTableName;
  60. }
  61. /**
  62. * 表达式过滤方法
  63. * @access protected
  64. * @param string $options 表达式
  65. * @return void
  66. */
  67. protected function _options_filter(&$options)
  68. {
  69. if (isset($options['field'])) {
  70. $options['field'] = $this->checkFields($options['field']);
  71. } else {
  72. $options['field'] = $this->checkFields();
  73. }
  74. if (isset($options['group'])) {
  75. $options['group'] = $this->checkGroup($options['group']);
  76. }
  77. if (isset($options['where'])) {
  78. $options['where'] = $this->checkCondition($options['where']);
  79. }
  80. if (isset($options['order'])) {
  81. $options['order'] = $this->checkOrder($options['order']);
  82. }
  83. }
  84. /**
  85. * 检查是否定义了所有字段
  86. * @access protected
  87. * @param string $name 模型名称
  88. * @param array $fields 字段数组
  89. * @return array
  90. */
  91. private function _checkFields($name, $fields)
  92. {
  93. if (false !== $pos = array_search('*', $fields)) {
  94. // 定义所有字段
  95. $fields = array_merge($fields, M($name)->getDbFields());
  96. unset($fields[$pos]);
  97. }
  98. return $fields;
  99. }
  100. /**
  101. * 检查条件中的视图字段
  102. * @param $where 条件表达式
  103. * @return array
  104. */
  105. protected function checkCondition($where)
  106. {
  107. if (is_array($where)) {
  108. $fields = $field_map_table = array();
  109. foreach ($this->viewFields as $key => $val) {
  110. $table_alias = isset($val['_as']) ? $val['_as'] : $key;
  111. $val = $this->_checkFields($key, $val);
  112. foreach ($val as $as_name => $v) {
  113. if (is_numeric($as_name)) {
  114. $fields[] = $v; //所有表字段集合
  115. $field_map_table[] = $table_alias; //所有表字段对应表名集合
  116. } else {
  117. $fields[$as_name] = $v;
  118. $field_map_table[$as_name] = $table_alias;
  119. }
  120. }
  121. }
  122. $where = $this->_parseWhere($where, $fields, $field_map_table);
  123. }
  124. return $where;
  125. }
  126. /**
  127. * 解析where表达式
  128. * @param $where
  129. * @param $fields
  130. * @param $field_map_table
  131. * @return array
  132. */
  133. private function _parseWhere($where, $fields, $field_map_table)
  134. {
  135. $view = array();
  136. foreach ($where as $name => $val) {
  137. if ('_complex' == $name) {
  138. //复合查询
  139. foreach ($val as $k => $v) {
  140. if (false === strpos(substr($k, 0, 1), '_')) {
  141. if (false !== $field = array_search($k, $fields, true)) { // 存在视图字段
  142. $k = is_numeric($field) ? $field_map_table[$field] . '.' . $k : $field_map_table[$field] . '.' . $field; //字段别名
  143. }
  144. } else if (is_array($v)) {
  145. //数组复合查询
  146. $v = $this->_parseWhere($val[$k], $fields, $field_map_table);
  147. }
  148. $view[$name][$k] = $v;
  149. }
  150. } else {
  151. if (strpos($name, '|')) {
  152. //name|title快捷查询
  153. $arr = explode('|', $name);
  154. foreach ($arr as $k => $v) {
  155. if (false !== $field = array_search($v, $fields, true)) {
  156. $arr[$k] = is_numeric($field) ? $field_map_table[$field] . '.' . $v : $field_map_table[$field] . '.' . $field;
  157. }
  158. }
  159. $view[implode('|', $arr)] = $val;
  160. } else if (strpos($name, '&')) {
  161. //name&title快捷查询
  162. $arr = explode('&', $name);
  163. foreach ($arr as $k => $v) {
  164. if (false !== $field = array_search($v, $fields, true)) {
  165. $arr[$k] = is_numeric($field) ? $field_map_table[$field] . '.' . $v : $field_map_table[$field] . '.' . $field;
  166. }
  167. }
  168. $view[implode('&', $arr)] = $val;
  169. } else {
  170. if (false !== $field = array_search($name, $fields, true)) {
  171. $name = is_numeric($field) ? $field_map_table[$field] . '.' . $name : $field_map_table[$field] . '.' . $field;
  172. }
  173. $view[$name] = $val;
  174. }
  175. }
  176. }
  177. return $view;
  178. }
  179. /**
  180. * 检查Order表达式中的视图字段
  181. * @access protected
  182. * @param string $order 字段
  183. * @return string
  184. */
  185. protected function checkOrder($order = '')
  186. {
  187. if (is_string($order) && !empty($order)) {
  188. $orders = explode(',', $order);
  189. $_order = array();
  190. foreach ($orders as $order) {
  191. $array = explode(' ', trim($order));
  192. $field = $array[0];
  193. $sort = isset($array[1]) ? $array[1] : 'ASC';
  194. // 解析成视图字段
  195. foreach ($this->viewFields as $name => $val) {
  196. $k = isset($val['_as']) ? $val['_as'] : $name;
  197. $val = $this->_checkFields($name, $val);
  198. if (false !== $_field = array_search($field, $val, true)) {
  199. // 存在视图字段
  200. $field = is_numeric($_field) ? $k . '.' . $field : $k . '.' . $_field;
  201. break;
  202. }
  203. }
  204. $_order[] = $field . ' ' . $sort;
  205. }
  206. $order = implode(',', $_order);
  207. }
  208. return $order;
  209. }
  210. /**
  211. * 检查Group表达式中的视图字段
  212. * @access protected
  213. * @param string $group 字段
  214. * @return string
  215. */
  216. protected function checkGroup($group = '')
  217. {
  218. if (!empty($group)) {
  219. $groups = explode(',', $group);
  220. $_group = array();
  221. foreach ($groups as $field) {
  222. // 解析成视图字段
  223. foreach ($this->viewFields as $name => $val) {
  224. $k = isset($val['_as']) ? $val['_as'] : $name;
  225. $val = $this->_checkFields($name, $val);
  226. if (false !== $_field = array_search($field, $val, true)) {
  227. // 存在视图字段
  228. $field = is_numeric($_field) ? $k . '.' . $field : $k . '.' . $_field;
  229. break;
  230. }
  231. }
  232. $_group[] = $field;
  233. }
  234. $group = implode(',', $_group);
  235. }
  236. return $group;
  237. }
  238. /**
  239. * 检查fields表达式中的视图字段
  240. * @access protected
  241. * @param string $fields 字段
  242. * @return string
  243. */
  244. protected function checkFields($fields = '')
  245. {
  246. if (empty($fields) || '*' == $fields) {
  247. // 获取全部视图字段
  248. $fields = array();
  249. foreach ($this->viewFields as $name => $val) {
  250. $k = isset($val['_as']) ? $val['_as'] : $name;
  251. $val = $this->_checkFields($name, $val);
  252. foreach ($val as $key => $field) {
  253. if (is_numeric($key)) {
  254. $fields[] = $k . '.' . $field . ' AS ' . $field;
  255. } elseif ('_' != substr($key, 0, 1)) {
  256. // 以_开头的为特殊定义
  257. if (false !== strpos($key, '*') || false !== strpos($key, '(') || false !== strpos($key, '.')) {
  258. //如果包含* 或者 使用了sql方法 则不再添加前面的表名
  259. $fields[] = $key . ' AS ' . $field;
  260. } else {
  261. $fields[] = $k . '.' . $key . ' AS ' . $field;
  262. }
  263. }
  264. }
  265. }
  266. $fields = implode(',', $fields);
  267. } else {
  268. if (!is_array($fields)) {
  269. $fields = explode(',', $fields);
  270. }
  271. // 解析成视图字段
  272. $array = array();
  273. foreach ($fields as $key => $field) {
  274. if (strpos($field, '(') || strpos(strtolower($field), ' as ')) {
  275. // 使用了函数或者别名
  276. $array[] = $field;
  277. unset($fields[$key]);
  278. }
  279. }
  280. foreach ($this->viewFields as $name => $val) {
  281. $k = isset($val['_as']) ? $val['_as'] : $name;
  282. $val = $this->_checkFields($name, $val);
  283. foreach ($fields as $key => $field) {
  284. if (false !== $_field = array_search($field, $val, true)) {
  285. // 存在视图字段
  286. if (is_numeric($_field)) {
  287. $array[] = $k . '.' . $field . ' AS ' . $field;
  288. } elseif ('_' != substr($_field, 0, 1)) {
  289. if (false !== strpos($_field, '*') || false !== strpos($_field, '(') || false !== strpos($_field, '.'))
  290. //如果包含* 或者 使用了sql方法 则不再添加前面的表名
  291. {
  292. $array[] = $_field . ' AS ' . $field;
  293. } else {
  294. $array[] = $k . '.' . $_field . ' AS ' . $field;
  295. }
  296. }
  297. }
  298. }
  299. }
  300. $fields = implode(',', $array);
  301. }
  302. return $fields;
  303. }
  304. }