App.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2018 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;
  12. use think\exception\ClassNotFoundException;
  13. use think\exception\HttpResponseException;
  14. use think\route\Dispatch;
  15. /**
  16. * App 应用管理
  17. */
  18. class App extends Container
  19. {
  20. const VERSION = '5.1.37 LTS';
  21. /**
  22. * 当前模块路径
  23. * @var string
  24. */
  25. protected $modulePath;
  26. /**
  27. * 应用调试模式
  28. * @var bool
  29. */
  30. protected $appDebug = true;
  31. /**
  32. * 应用开始时间
  33. * @var float
  34. */
  35. protected $beginTime;
  36. /**
  37. * 应用内存初始占用
  38. * @var integer
  39. */
  40. protected $beginMem;
  41. /**
  42. * 应用类库命名空间
  43. * @var string
  44. */
  45. protected $namespace = 'app';
  46. /**
  47. * 应用类库后缀
  48. * @var bool
  49. */
  50. protected $suffix = false;
  51. /**
  52. * 严格路由检测
  53. * @var bool
  54. */
  55. protected $routeMust;
  56. /**
  57. * 应用类库目录
  58. * @var string
  59. */
  60. protected $appPath;
  61. /**
  62. * 框架目录
  63. * @var string
  64. */
  65. protected $thinkPath;
  66. /**
  67. * 应用根目录
  68. * @var string
  69. */
  70. protected $rootPath;
  71. /**
  72. * 运行时目录
  73. * @var string
  74. */
  75. protected $runtimePath;
  76. /**
  77. * 配置目录
  78. * @var string
  79. */
  80. protected $configPath;
  81. /**
  82. * 路由目录
  83. * @var string
  84. */
  85. protected $routePath;
  86. /**
  87. * 配置后缀
  88. * @var string
  89. */
  90. protected $configExt;
  91. /**
  92. * 应用调度实例
  93. * @var Dispatch
  94. */
  95. protected $dispatch;
  96. /**
  97. * 绑定模块(控制器)
  98. * @var string
  99. */
  100. protected $bindModule;
  101. /**
  102. * 初始化
  103. * @var bool
  104. */
  105. protected $initialized = false;
  106. protected static $modulesInited = [];
  107. public function __construct($appPath = '')
  108. {
  109. $this->thinkPath = CMF_ROOT . 'vendor' . DIRECTORY_SEPARATOR . 'thinkphp' . DIRECTORY_SEPARATOR;
  110. $this->path($appPath);
  111. }
  112. /**
  113. * 绑定模块或者控制器
  114. * @access public
  115. * @param string $bind
  116. * @return $this
  117. */
  118. public function bind($bind)
  119. {
  120. $this->bindModule = $bind;
  121. return $this;
  122. }
  123. /**
  124. * 设置应用类库目录
  125. * @access public
  126. * @param string $path 路径
  127. * @return $this
  128. */
  129. public function path($path)
  130. {
  131. $this->appPath = $path ? realpath($path) . DIRECTORY_SEPARATOR : $this->getAppPath();
  132. return $this;
  133. }
  134. /**
  135. * 初始化应用
  136. * @access public
  137. * @return void
  138. */
  139. public function initialize()
  140. {
  141. if ($this->initialized) {
  142. return;
  143. }
  144. $this->initialized = true;
  145. $this->beginTime = microtime(true);
  146. $this->beginMem = memory_get_usage();
  147. $this->rootPath = dirname($this->appPath) . DIRECTORY_SEPARATOR;
  148. $this->runtimePath = CMF_DATA . 'runtime' . DIRECTORY_SEPARATOR;
  149. $this->routePath = CMF_DATA . 'route' . DIRECTORY_SEPARATOR;
  150. $this->configPath = CMF_DATA . 'config' . DIRECTORY_SEPARATOR;
  151. if (defined('RUNTIME_PATH')) {
  152. $this->runtimePath = RUNTIME_PATH;
  153. }
  154. if (defined('ROUTE_PATH')) {
  155. $this->routePath = ROUTE_PATH;
  156. }
  157. if (defined('CONFIG_PATH')) {
  158. $this->configPath = CONFIG_PATH;
  159. }
  160. static::setInstance($this);
  161. $this->instance('app', $this);
  162. $this->configExt = $this->env->get('config_ext', '.php');
  163. // 加载惯例配置文件
  164. $this->config->set(include $this->thinkPath . 'convention.php');
  165. // 设置路径环境变量
  166. $this->env->set([
  167. 'think_path' => $this->thinkPath,
  168. 'root_path' => $this->rootPath,
  169. 'app_path' => $this->appPath,
  170. 'config_path' => $this->configPath,
  171. 'route_path' => $this->routePath,
  172. 'runtime_path' => $this->runtimePath,
  173. 'extend_path' => $this->rootPath . 'extend' . DIRECTORY_SEPARATOR,
  174. 'vendor_path' => $this->rootPath . 'vendor' . DIRECTORY_SEPARATOR,
  175. ]);
  176. // 加载环境变量配置文件
  177. if (is_file($this->rootPath . '.env')) {
  178. $this->env->load($this->rootPath . '.env');
  179. }
  180. if (defined('APP_NAMESPACE')) {
  181. $this->namespace = APP_NAMESPACE;
  182. }
  183. $this->env->set('app_namespace', $this->namespace);
  184. // 注册应用命名空间
  185. Loader::addNamespace($this->namespace, $this->appPath);
  186. // 初始化应用
  187. $this->init();
  188. // 开启类名后缀
  189. $this->suffix = $this->config('app.class_suffix');
  190. // 应用调试模式
  191. $this->appDebug = $this->env->get('app_debug', $this->config('app.app_debug'));
  192. $this->env->set('app_debug', $this->appDebug);
  193. if (!$this->appDebug) {
  194. ini_set('display_errors', 'Off');
  195. } elseif (PHP_SAPI != 'cli') {
  196. //重新申请一块比较大的buffer
  197. if (ob_get_level() > 0) {
  198. $output = ob_get_clean();
  199. }
  200. ob_start();
  201. if (!empty($output)) {
  202. echo $output;
  203. }
  204. }
  205. // 注册异常处理类
  206. if ($this->config('app.exception_handle')) {
  207. Error::setExceptionHandler($this->config('app.exception_handle'));
  208. }
  209. // 注册根命名空间
  210. if (!empty($this->config('app.root_namespace'))) {
  211. Loader::addNamespace($this->config('app.root_namespace'));
  212. }
  213. // 加载composer autofile文件
  214. Loader::loadComposerAutoloadFiles();
  215. // 注册类库别名
  216. Loader::addClassAlias($this->config->pull('alias'));
  217. // 数据库配置初始化
  218. Db::init($this->config->pull('database'));
  219. // 设置系统时区
  220. date_default_timezone_set($this->config('app.default_timezone'));
  221. // 读取语言包
  222. $this->loadLangPack();
  223. // 路由初始化
  224. $this->routeInit();
  225. if (PHP_SAPI != 'cli') {
  226. // 监听app_init
  227. $this->hook->listen('app_init');
  228. }
  229. }
  230. /**
  231. * 初始化应用或模块
  232. * @access public
  233. * @param string $module 模块名
  234. * @return void
  235. */
  236. public function init($module = '')
  237. {
  238. // 定位模块目录
  239. $module = $module ? $module . DIRECTORY_SEPARATOR : '';
  240. $path = $this->appPath . $module;
  241. if (empty($module) || empty(static::$modulesInited[$module])) {
  242. // 加载初始化文件
  243. if (is_file($path . 'init.php')) {
  244. include $path . 'init.php';
  245. } elseif (is_file($this->runtimePath . $module . 'init.php')) {
  246. include $this->runtimePath . $module . 'init.php';
  247. } else {
  248. // 加载行为扩展文件
  249. if (is_file($path . 'tags.php')) {
  250. $tags = include $path . 'tags.php';
  251. if (is_array($tags)) {
  252. $this->hook->import($tags);
  253. }
  254. }
  255. // 加载公共文件
  256. if (is_file($path . 'common.php')) {
  257. include_once $path . 'common.php';
  258. }
  259. if ('' == $module) {
  260. // 加载系统助手函数
  261. include $this->thinkPath . 'helper.php';
  262. // 加载主要配置
  263. $mainConfigNames = ['app', 'database', 'template', 'paginate'];
  264. if ($this->namespace == 'app' || $this->namespace == 'api') {
  265. foreach ($mainConfigNames as $configName) {
  266. $this->config->load(CMF_ROOT . "vendor/thinkcmf/cmf-{$this->namespace}/src/" . $configName . $this->configExt, $configName);
  267. }
  268. $tagsFile = CMF_ROOT . "vendor/thinkcmf/cmf-{$this->namespace}/src/" . 'tags.php';
  269. if (is_file($tagsFile)) {
  270. $tags = include $tagsFile;
  271. if (is_array($tags)) {
  272. $this->hook->import($tags);
  273. }
  274. }
  275. }
  276. $mainConfigNames = ['app', 'database', 'template', 'paginate'];
  277. foreach ($mainConfigNames as $configName) {
  278. $this->config->load($path . $configName . $this->configExt, $configName);
  279. }
  280. }
  281. // 加载中间件
  282. if (is_file($path . 'middleware.php')) {
  283. $middleware = include $path . 'middleware.php';
  284. if (is_array($middleware)) {
  285. $this->middleware->import($middleware);
  286. }
  287. }
  288. // 注册服务的容器对象实例
  289. if (is_file($path . 'provider.php')) {
  290. $provider = include $path . 'provider.php';
  291. if (is_array($provider)) {
  292. $this->bindTo($provider);
  293. }
  294. }
  295. // 自动读取配置文件
  296. if (is_dir($path . 'config')) {
  297. $dir = $path . 'config' . DIRECTORY_SEPARATOR;
  298. } elseif (is_dir($this->configPath . $module)) {
  299. $dir = $this->configPath . $module;
  300. }
  301. $files = isset($dir) ? scandir($dir) : [];
  302. foreach ($files as $file) {
  303. if ('.' . pathinfo($file, PATHINFO_EXTENSION) === $this->configExt) {
  304. $this->config->load($dir . $file, pathinfo($file, PATHINFO_FILENAME));
  305. }
  306. }
  307. }
  308. static::$modulesInited[$module] = true;
  309. }
  310. $this->setModulePath($path);
  311. if ($module) {
  312. // 对容器中的对象实例进行配置更新
  313. $this->containerConfigUpdate($module);
  314. }
  315. }
  316. protected function containerConfigUpdate($module)
  317. {
  318. $config = $this->config->get();
  319. // 注册异常处理类
  320. if ($config['app']['exception_handle']) {
  321. Error::setExceptionHandler($config['app']['exception_handle']);
  322. }
  323. Db::init($config['database']);
  324. $this->middleware->setConfig($config['middleware']);
  325. $this->route->setConfig($config['app']);
  326. $this->request->init($config['app']);
  327. $this->cookie->init($config['cookie']);
  328. $this->view->init($config['template']);
  329. $this->log->init($config['log']);
  330. $this->session->setConfig($config['session']);
  331. $this->debug->setConfig($config['trace']);
  332. $this->cache->init($config['cache'], true);
  333. // 加载当前模块语言包
  334. $this->lang->load($this->appPath . $module . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR . $this->request->langset() . '.php');
  335. // 模块请求缓存检查
  336. $this->checkRequestCache(
  337. $config['app']['request_cache'],
  338. $config['app']['request_cache_expire'],
  339. $config['app']['request_cache_except']
  340. );
  341. }
  342. /**
  343. * 执行应用程序
  344. * @access public
  345. * @return Response
  346. * @throws Exception
  347. */
  348. public function run()
  349. {
  350. try {
  351. // 初始化应用
  352. $this->initialize();
  353. if ($this->bindModule) {
  354. // 模块/控制器绑定
  355. $this->route->bind($this->bindModule);
  356. } elseif ($this->config('app.auto_bind_module')) {
  357. // 入口自动绑定
  358. $name = pathinfo($this->request->baseFile(), PATHINFO_FILENAME);
  359. if ($name && 'index' != $name && is_dir($this->appPath . $name)) {
  360. $this->route->bind($name);
  361. }
  362. }
  363. // 监听app_dispatch
  364. $this->hook->listen('app_dispatch');
  365. $dispatch = $this->dispatch;
  366. if (empty($dispatch)) {
  367. // 路由检测
  368. $dispatch = $this->routeCheck()->init();
  369. }
  370. // 插件路由参数处理
  371. $routeInfo = $this->request->routeInfo();
  372. if (!empty($routeInfo['route']) && strpos($routeInfo['route'], '\cmf\controller\PluginController@index?') !== false) {
  373. parse_str(str_replace('\cmf\controller\PluginController@index?', '', $routeInfo['route']), $routeParams);
  374. $this->request->withRoute($routeParams);
  375. }
  376. // 记录当前调度信息
  377. $this->request->dispatch($dispatch);
  378. // 记录路由和请求信息
  379. if ($this->appDebug) {
  380. $this->log('[ ROUTE ] ' . var_export($this->request->routeInfo(), true));
  381. $this->log('[ HEADER ] ' . var_export($this->request->header(), true));
  382. $this->log('[ PARAM ] ' . var_export($this->request->param(), true));
  383. }
  384. // 监听app_begin
  385. $this->hook->listen('app_begin');
  386. // 请求缓存检查
  387. $this->checkRequestCache(
  388. $this->config('request_cache'),
  389. $this->config('request_cache_expire'),
  390. $this->config('request_cache_except')
  391. );
  392. $data = null;
  393. } catch (HttpResponseException $exception) {
  394. $dispatch = null;
  395. $data = $exception->getResponse();
  396. }
  397. $this->middleware->add(function (Request $request, $next) use ($dispatch, $data) {
  398. return is_null($data) ? $dispatch->run() : $data;
  399. });
  400. $response = $this->middleware->dispatch($this->request);
  401. // 监听app_end
  402. $this->hook->listen('app_end', $response);
  403. return $response;
  404. }
  405. protected function getRouteCacheKey()
  406. {
  407. if ($this->config->get('route_check_cache_key')) {
  408. $closure = $this->config->get('route_check_cache_key');
  409. $routeKey = $closure($this->request);
  410. } else {
  411. $routeKey = md5($this->request->baseUrl(true) . ':' . $this->request->method());
  412. }
  413. return $routeKey;
  414. }
  415. protected function loadLangPack()
  416. {
  417. // 读取默认语言
  418. $this->lang->range($this->config('app.default_lang'));
  419. if ($this->config('app.lang_switch_on')) {
  420. // 开启多语言机制 检测当前语言
  421. $this->lang->detect();
  422. }
  423. $this->request->setLangset($this->lang->range());
  424. // 加载系统语言包
  425. $this->lang->load([
  426. $this->thinkPath . 'lang' . DIRECTORY_SEPARATOR . $this->request->langset() . '.php',
  427. $this->appPath . 'lang' . DIRECTORY_SEPARATOR . $this->request->langset() . '.php',
  428. ]);
  429. }
  430. /**
  431. * 设置当前地址的请求缓存
  432. * @access public
  433. * @param string $key 缓存标识,支持变量规则 ,例如 item/:name/:id
  434. * @param mixed $expire 缓存有效期
  435. * @param array $except 缓存排除
  436. * @param string $tag 缓存标签
  437. * @return void
  438. */
  439. public function checkRequestCache($key, $expire = null, $except = [], $tag = null)
  440. {
  441. $cache = $this->request->cache($key, $expire, $except, $tag);
  442. if ($cache) {
  443. $this->setResponseCache($cache);
  444. }
  445. }
  446. public function setResponseCache($cache)
  447. {
  448. list($key, $expire, $tag) = $cache;
  449. if (strtotime($this->request->server('HTTP_IF_MODIFIED_SINCE')) + $expire > $this->request->server('REQUEST_TIME')) {
  450. // 读取缓存
  451. $response = Response::create()->code(304);
  452. throw new HttpResponseException($response);
  453. } elseif ($this->cache->has($key)) {
  454. list($content, $header) = $this->cache->get($key);
  455. $response = Response::create($content)->header($header);
  456. throw new HttpResponseException($response);
  457. }
  458. }
  459. /**
  460. * 设置当前请求的调度信息
  461. * @access public
  462. * @param Dispatch $dispatch 调度信息
  463. * @return $this
  464. */
  465. public function dispatch(Dispatch $dispatch)
  466. {
  467. $this->dispatch = $dispatch;
  468. return $this;
  469. }
  470. /**
  471. * 记录调试信息
  472. * @access public
  473. * @param mixed $msg 调试信息
  474. * @param string $type 信息类型
  475. * @return void
  476. */
  477. public function log($msg, $type = 'info')
  478. {
  479. $this->appDebug && $this->log->record($msg, $type);
  480. }
  481. /**
  482. * 获取配置参数 为空则获取所有配置
  483. * @access public
  484. * @param string $name 配置参数名(支持二级配置 .号分割)
  485. * @return mixed
  486. */
  487. public function config($name = '')
  488. {
  489. return $this->config->get($name);
  490. }
  491. /**
  492. * 路由初始化 导入路由定义规则
  493. * @access public
  494. * @return void
  495. */
  496. public function routeInit()
  497. {
  498. // 路由检测
  499. if (is_dir($this->routePath)) {
  500. $files = scandir($this->routePath);
  501. foreach ($files as $file) {
  502. if (strpos($file, '.php')) {
  503. $filename = $this->routePath . $file;
  504. // 导入路由配置
  505. $rules = include $filename;
  506. if (is_array($rules)) {
  507. $this->route->import($rules);
  508. }
  509. }
  510. }
  511. } elseif (is_file($this->routePath)) {
  512. $rules = include $this->routePath;
  513. if (is_array($rules)) {
  514. $this->route->import($rules);
  515. }
  516. }
  517. if ($this->namespace == 'api') {
  518. $rules = include CMF_ROOT . 'vendor/thinkcmf/cmf-api/src/route.php';
  519. if (is_array($rules)) {
  520. $this->route->import($rules);
  521. }
  522. }
  523. if ($this->route->config('route_annotation')) {
  524. // 自动生成路由定义
  525. if ($this->appDebug) {
  526. $suffix = $this->route->config('controller_suffix') || $this->route->config('class_suffix');
  527. $this->build->buildRoute($suffix);
  528. }
  529. $filename = $this->runtimePath . 'build_route.php';
  530. if (is_file($filename)) {
  531. include $filename;
  532. }
  533. }
  534. }
  535. /**
  536. * URL路由检测(根据PATH_INFO)
  537. * @access public
  538. * @return Dispatch
  539. */
  540. public function routeCheck()
  541. {
  542. // 检测路由缓存
  543. if (!$this->appDebug && $this->config->get('route_check_cache')) {
  544. $routeKey = $this->getRouteCacheKey();
  545. $option = $this->config->get('route_cache_option');
  546. if ($option && $this->cache->connect($option)->has($routeKey)) {
  547. return $this->cache->connect($option)->get($routeKey);
  548. } elseif ($this->cache->has($routeKey)) {
  549. return $this->cache->get($routeKey);
  550. }
  551. }
  552. // 获取应用调度信息
  553. $path = $this->request->path();
  554. // 是否强制路由模式
  555. $must = !is_null($this->routeMust) ? $this->routeMust : $this->route->config('url_route_must');
  556. // 路由检测 返回一个Dispatch对象
  557. $dispatch = $this->route->check($path, $must);
  558. if (!empty($routeKey)) {
  559. try {
  560. if ($option) {
  561. $this->cache->connect($option)->tag('route_cache')->set($routeKey, $dispatch);
  562. } else {
  563. $this->cache->tag('route_cache')->set($routeKey, $dispatch);
  564. }
  565. } catch (\Exception $e) {
  566. // 存在闭包的时候缓存无效
  567. }
  568. }
  569. return $dispatch;
  570. }
  571. /**
  572. * 设置应用的路由检测机制
  573. * @access public
  574. * @param bool $must 是否强制检测路由
  575. * @return $this
  576. */
  577. public function routeMust($must = false)
  578. {
  579. $this->routeMust = $must;
  580. return $this;
  581. }
  582. /**
  583. * 解析模块和类名
  584. * @access protected
  585. * @param string $name 资源地址
  586. * @param string $layer 验证层名称
  587. * @param bool $appendSuffix 是否添加类名后缀
  588. * @return array
  589. */
  590. protected function parseModuleAndClass($name, $layer, $appendSuffix)
  591. {
  592. if (false !== strpos($name, '\\')) {
  593. $class = $name;
  594. $module = $this->request->module();
  595. } else {
  596. if (strpos($name, '/')) {
  597. list($module, $name) = explode('/', $name, 2);
  598. } else {
  599. $module = $this->request->module();
  600. }
  601. $class = $this->parseClass($module, $layer, $name, $appendSuffix);
  602. }
  603. return [$module, $class];
  604. }
  605. /**
  606. * 实例化应用类库
  607. * @access public
  608. * @param string $name 类名称
  609. * @param string $layer 业务层名称
  610. * @param bool $appendSuffix 是否添加类名后缀
  611. * @param string $common 公共模块名
  612. * @return object
  613. * @throws ClassNotFoundException
  614. */
  615. public function create($name, $layer, $appendSuffix = false, $common = 'common')
  616. {
  617. $guid = $name . $layer;
  618. if ($this->__isset($guid)) {
  619. return $this->__get($guid);
  620. }
  621. list($module, $class) = $this->parseModuleAndClass($name, $layer, $appendSuffix);
  622. if (class_exists($class)) {
  623. $object = $this->__get($class);
  624. } else {
  625. $class = str_replace('\\' . $module . '\\', '\\' . $common . '\\', $class);
  626. if (class_exists($class)) {
  627. $object = $this->__get($class);
  628. } else {
  629. throw new ClassNotFoundException('class not exists:' . $class, $class);
  630. }
  631. }
  632. $this->__set($guid, $class);
  633. return $object;
  634. }
  635. /**
  636. * 实例化(分层)模型
  637. * @access public
  638. * @param string $name Model名称
  639. * @param string $layer 业务层名称
  640. * @param bool $appendSuffix 是否添加类名后缀
  641. * @param string $common 公共模块名
  642. * @return Model
  643. * @throws ClassNotFoundException
  644. */
  645. public function model($name = '', $layer = 'model', $appendSuffix = false, $common = 'common')
  646. {
  647. return $this->create($name, $layer, $appendSuffix, $common);
  648. }
  649. /**
  650. * 实例化(分层)控制器 格式:[模块名/]控制器名
  651. * @access public
  652. * @param string $name 资源地址
  653. * @param string $layer 控制层名称
  654. * @param bool $appendSuffix 是否添加类名后缀
  655. * @param string $empty 空控制器名称
  656. * @return object
  657. * @throws ClassNotFoundException
  658. */
  659. public function controller($name, $layer = 'controller', $appendSuffix = false, $empty = '')
  660. {
  661. list($module, $class) = $this->parseModuleAndClass($name, $layer, $appendSuffix);
  662. if (class_exists($class)) {
  663. return $this->make($class, true);
  664. } elseif ($empty && class_exists($emptyClass = $this->parseClass($module, $layer, $empty, $appendSuffix))) {
  665. return $this->make($emptyClass, true);
  666. }
  667. throw new ClassNotFoundException('class not exists:' . $class, $class);
  668. }
  669. /**
  670. * 实例化验证类 格式:[模块名/]验证器名
  671. * @access public
  672. * @param string $name 资源地址
  673. * @param string $layer 验证层名称
  674. * @param bool $appendSuffix 是否添加类名后缀
  675. * @param string $common 公共模块名
  676. * @return Validate
  677. * @throws ClassNotFoundException
  678. */
  679. public function validate($name = '', $layer = 'validate', $appendSuffix = false, $common = 'common')
  680. {
  681. $name = $name ?: $this->config('default_validate');
  682. if (empty($name)) {
  683. return new Validate;
  684. }
  685. return $this->create($name, $layer, $appendSuffix, $common);
  686. }
  687. /**
  688. * 数据库初始化
  689. * @access public
  690. * @param mixed $config 数据库配置
  691. * @param bool|string $name 连接标识 true 强制重新连接
  692. * @return \think\db\Query
  693. */
  694. public function db($config = [], $name = false)
  695. {
  696. return Db::connect($config, $name);
  697. }
  698. /**
  699. * 远程调用模块的操作方法 参数格式 [模块/控制器/]操作
  700. * @access public
  701. * @param string $url 调用地址
  702. * @param string|array $vars 调用参数 支持字符串和数组
  703. * @param string $layer 要调用的控制层名称
  704. * @param bool $appendSuffix 是否添加类名后缀
  705. * @return mixed
  706. * @throws ClassNotFoundException
  707. */
  708. public function action($url, $vars = [], $layer = 'controller', $appendSuffix = false)
  709. {
  710. $info = pathinfo($url);
  711. $action = $info['basename'];
  712. $module = '.' != $info['dirname'] ? $info['dirname'] : $this->request->controller();
  713. $class = $this->controller($module, $layer, $appendSuffix);
  714. if (is_scalar($vars)) {
  715. if (strpos($vars, '=')) {
  716. parse_str($vars, $vars);
  717. } else {
  718. $vars = [$vars];
  719. }
  720. }
  721. return $this->invokeMethod([$class, $action . $this->config('action_suffix')], $vars);
  722. }
  723. /**
  724. * 解析应用类的类名
  725. * @access public
  726. * @param string $module 模块名
  727. * @param string $layer 层名 controller model ...
  728. * @param string $name 类名
  729. * @param bool $appendSuffix
  730. * @return string
  731. */
  732. public function parseClass($module, $layer, $name, $appendSuffix = false)
  733. {
  734. $name = str_replace(['/', '.'], '\\', $name);
  735. $array = explode('\\', $name);
  736. $class = Loader::parseName(array_pop($array), 1) . ($this->suffix || $appendSuffix ? ucfirst($layer) : '');
  737. $path = $array ? implode('\\', $array) . '\\' : '';
  738. return $this->namespace . '\\' . ($module ? $module . '\\' : '') . $layer . '\\' . $path . $class;
  739. }
  740. /**
  741. * 获取框架版本
  742. * @access public
  743. * @return string
  744. */
  745. public function version()
  746. {
  747. return static::VERSION;
  748. }
  749. /**
  750. * 是否为调试模式
  751. * @access public
  752. * @return bool
  753. */
  754. public function isDebug()
  755. {
  756. return $this->appDebug;
  757. }
  758. /**
  759. * 获取模块路径
  760. * @access public
  761. * @return string
  762. */
  763. public function getModulePath()
  764. {
  765. return $this->modulePath;
  766. }
  767. /**
  768. * 设置模块路径
  769. * @access public
  770. * @param string $path 路径
  771. * @return void
  772. */
  773. public function setModulePath($path)
  774. {
  775. $this->modulePath = $path;
  776. $this->env->set('module_path', $path);
  777. }
  778. /**
  779. * 获取应用根目录
  780. * @access public
  781. * @return string
  782. */
  783. public function getRootPath()
  784. {
  785. return $this->rootPath;
  786. }
  787. /**
  788. * 获取应用类库目录
  789. * @access public
  790. * @return string
  791. */
  792. public function getAppPath()
  793. {
  794. if (is_null($this->appPath)) {
  795. $this->appPath = Loader::getRootPath() . 'application' . DIRECTORY_SEPARATOR;
  796. }
  797. return $this->appPath;
  798. }
  799. /**
  800. * 获取应用运行时目录
  801. * @access public
  802. * @return string
  803. */
  804. public function getRuntimePath()
  805. {
  806. return $this->runtimePath;
  807. }
  808. /**
  809. * 获取核心框架目录
  810. * @access public
  811. * @return string
  812. */
  813. public function getThinkPath()
  814. {
  815. return $this->thinkPath;
  816. }
  817. /**
  818. * 获取路由目录
  819. * @access public
  820. * @return string
  821. */
  822. public function getRoutePath()
  823. {
  824. return $this->routePath;
  825. }
  826. /**
  827. * 获取应用配置目录
  828. * @access public
  829. * @return string
  830. */
  831. public function getConfigPath()
  832. {
  833. return $this->configPath;
  834. }
  835. /**
  836. * 获取配置后缀
  837. * @access public
  838. * @return string
  839. */
  840. public function getConfigExt()
  841. {
  842. return $this->configExt;
  843. }
  844. /**
  845. * 获取应用类库命名空间
  846. * @access public
  847. * @return string
  848. */
  849. public function getNamespace()
  850. {
  851. return $this->namespace;
  852. }
  853. /**
  854. * 设置应用类库命名空间
  855. * @access public
  856. * @param string $namespace 命名空间名称
  857. * @return $this
  858. */
  859. public function setNamespace($namespace)
  860. {
  861. $this->namespace = $namespace;
  862. return $this;
  863. }
  864. /**
  865. * 是否启用类库后缀
  866. * @access public
  867. * @return bool
  868. */
  869. public function getSuffix()
  870. {
  871. return $this->suffix;
  872. }
  873. /**
  874. * 获取应用开启时间
  875. * @access public
  876. * @return float
  877. */
  878. public function getBeginTime()
  879. {
  880. return $this->beginTime;
  881. }
  882. /**
  883. * 获取应用初始内存占用
  884. * @access public
  885. * @return integer
  886. */
  887. public function getBeginMem()
  888. {
  889. return $this->beginMem;
  890. }
  891. }