Think.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2019 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. declare (strict_types = 1);
  12. namespace think\view\driver;
  13. use think\App;
  14. use think\helper\Str;
  15. use think\Template;
  16. use think\template\exception\TemplateNotFoundException;
  17. class Think
  18. {
  19. // 模板引擎实例
  20. private $template;
  21. private $app;
  22. // 模板引擎参数
  23. protected $config = [
  24. // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法
  25. 'auto_rule' => 1,
  26. // 视图目录名
  27. 'view_dir_name' => 'view',
  28. // 模板起始路径
  29. 'view_path' => '',
  30. // 模板文件后缀
  31. 'view_suffix' => 'html',
  32. // 模板文件名分隔符
  33. 'view_depr' => DIRECTORY_SEPARATOR,
  34. // 是否开启模板编译缓存,设为false则每次都会重新编译
  35. 'tpl_cache' => true,
  36. ];
  37. public function __construct(App $app, array $config = [])
  38. {
  39. $this->app = $app;
  40. $this->config = array_merge($this->config, (array) $config);
  41. if (empty($this->config['cache_path'])) {
  42. $this->config['cache_path'] = $app->getRuntimePath() . 'temp' . DIRECTORY_SEPARATOR;
  43. }
  44. $this->template = new Template($this->config);
  45. $this->template->setCache($app->cache);
  46. $this->template->extend('$Think', function (array $vars) {
  47. $type = strtoupper(trim(array_shift($vars)));
  48. $param = implode('.', $vars);
  49. switch ($type) {
  50. case 'CONST':
  51. $parseStr = strtoupper($param);
  52. break;
  53. case 'CONFIG':
  54. $parseStr = 'config(\'' . $param . '\')';
  55. break;
  56. case 'LANG':
  57. $parseStr = 'lang(\'' . $param . '\')';
  58. break;
  59. case 'NOW':
  60. $parseStr = "date('Y-m-d g:i a',time())";
  61. break;
  62. case 'LDELIM':
  63. $parseStr = '\'' . ltrim($this->getConfig('tpl_begin'), '\\') . '\'';
  64. break;
  65. case 'RDELIM':
  66. $parseStr = '\'' . ltrim($this->getConfig('tpl_end'), '\\') . '\'';
  67. break;
  68. default:
  69. $parseStr = defined($type) ? $type : '\'\'';
  70. }
  71. return $parseStr;
  72. });
  73. $this->template->extend('$Request', function (array $vars) {
  74. // 获取Request请求对象参数
  75. $method = array_shift($vars);
  76. if (!empty($vars)) {
  77. $params = implode('.', $vars);
  78. if ('true' != $params) {
  79. $params = '\'' . $params . '\'';
  80. }
  81. } else {
  82. $params = '';
  83. }
  84. return 'app(\'request\')->' . $method . '(' . $params . ')';
  85. });
  86. }
  87. /**
  88. * 检测是否存在模板文件
  89. * @access public
  90. * @param string $template 模板文件或者模板规则
  91. * @return bool
  92. */
  93. public function exists(string $template): bool
  94. {
  95. if ('' == pathinfo($template, PATHINFO_EXTENSION)) {
  96. // 获取模板文件名
  97. $template = $this->parseTemplate($template);
  98. }
  99. return is_file($template);
  100. }
  101. /**
  102. * 渲染模板文件
  103. * @access public
  104. * @param string $template 模板文件
  105. * @param array $data 模板变量
  106. * @return void
  107. */
  108. public function fetch(string $template, array $data = []): void
  109. {
  110. if (empty($this->config['view_path'])) {
  111. $view = $this->config['view_dir_name'];
  112. if (is_dir($this->app->getAppPath() . $view)) {
  113. $path = $this->app->getAppPath() . $view . DIRECTORY_SEPARATOR;
  114. } else {
  115. $appName = $this->app->http->getName();
  116. $path = $this->app->getRootPath() . $view . DIRECTORY_SEPARATOR . ($appName ? $appName . DIRECTORY_SEPARATOR : '');
  117. }
  118. $this->config['view_path'] = $path;
  119. $this->template->view_path = $path;
  120. }
  121. if ('' == pathinfo($template, PATHINFO_EXTENSION)) {
  122. // 获取模板文件名
  123. $template = $this->parseTemplate($template);
  124. }
  125. // 模板不存在 抛出异常
  126. if (!is_file($template)) {
  127. throw new TemplateNotFoundException('template not exists:' . $template, $template);
  128. }
  129. // 记录视图信息
  130. $this->app['log']
  131. ->record('[ VIEW ] ' . $template . ' [ ' . var_export(array_keys($data), true) . ' ]');
  132. $this->template->fetch($template, $data);
  133. }
  134. /**
  135. * 渲染模板内容
  136. * @access public
  137. * @param string $template 模板内容
  138. * @param array $data 模板变量
  139. * @return void
  140. */
  141. public function display(string $template, array $data = []): void
  142. {
  143. $this->template->display($template, $data);
  144. }
  145. /**
  146. * 自动定位模板文件
  147. * @access private
  148. * @param string $template 模板文件规则
  149. * @return string
  150. */
  151. private function parseTemplate(string $template): string
  152. {
  153. // 分析模板文件规则
  154. $request = $this->app['request'];
  155. // 获取视图根目录
  156. if (strpos($template, '@')) {
  157. // 跨模块调用
  158. list($app, $template) = explode('@', $template);
  159. }
  160. if (isset($app)) {
  161. $view = $this->config['view_dir_name'];
  162. $viewPath = $this->app->getBasePath() . $app . DIRECTORY_SEPARATOR . $view . DIRECTORY_SEPARATOR;
  163. if (is_dir($viewPath)) {
  164. $path = $viewPath;
  165. } else {
  166. $path = $this->app->getRootPath() . $view . DIRECTORY_SEPARATOR . $app . DIRECTORY_SEPARATOR;
  167. }
  168. $this->template->view_path = $path;
  169. } else {
  170. $path = $this->config['view_path'];
  171. }
  172. $depr = $this->config['view_depr'];
  173. if (0 !== strpos($template, '/')) {
  174. $template = str_replace(['/', ':'], $depr, $template);
  175. $controller = $request->controller();
  176. if (strpos($controller, '.')) {
  177. $pos = strrpos($controller, '.');
  178. $controller = substr($controller, 0, $pos) . '.' . Str::snake(substr($controller, $pos + 1));
  179. } else {
  180. $controller = Str::snake($controller);
  181. }
  182. if ($controller) {
  183. if ('' == $template) {
  184. // 如果模板文件名为空 按照默认模板渲染规则定位
  185. if (2 == $this->config['auto_rule']) {
  186. $template = $request->action(true);
  187. } elseif (3 == $this->config['auto_rule']) {
  188. $template = $request->action();
  189. } else {
  190. $template = Str::snake($request->action());
  191. }
  192. $template = str_replace('.', DIRECTORY_SEPARATOR, $controller) . $depr . $template;
  193. } elseif (false === strpos($template, $depr)) {
  194. $template = str_replace('.', DIRECTORY_SEPARATOR, $controller) . $depr . $template;
  195. }
  196. }
  197. } else {
  198. $template = str_replace(['/', ':'], $depr, substr($template, 1));
  199. }
  200. return $path . ltrim($template, '/') . '.' . ltrim($this->config['view_suffix'], '.');
  201. }
  202. /**
  203. * 配置模板引擎
  204. * @access private
  205. * @param array $config 参数
  206. * @return void
  207. */
  208. public function config(array $config): void
  209. {
  210. $this->template->config($config);
  211. $this->config = array_merge($this->config, $config);
  212. }
  213. /**
  214. * 获取模板引擎配置
  215. * @access public
  216. * @param string $name 参数名
  217. * @return void
  218. */
  219. public function getConfig(string $name)
  220. {
  221. return $this->template->getConfig($name);
  222. }
  223. public function __call($method, $params)
  224. {
  225. return call_user_func_array([$this->template, $method], $params);
  226. }
  227. }