Widget.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. <?php
  2. /*
  3. * FecShop file.
  4. *
  5. * @link http://www.fecshop.com/
  6. * @copyright Copyright (c) 2016 FecShop Software LLC
  7. * @license http://www.fecshop.com/license/
  8. */
  9. namespace fecshop\services\page;
  10. use fec\helpers\CCache;
  11. use fecshop\interfaces\block\BlockCache;
  12. use fecshop\services\Service;
  13. use Yii;
  14. use yii\base\InvalidConfigException;
  15. use yii\base\InvalidValueException;
  16. /**
  17. * Page widget services.
  18. * @author Terry Zhao <2358269014@qq.com>
  19. * @since 1.0
  20. */
  21. class Widget extends Service
  22. {
  23. public $defaultObMethod = 'getLastData';
  24. public $widgetConfig;
  25. /**
  26. * @param configKey String or Array
  27. * 如果传递的是一个配置数组,内容格式如下:
  28. * [
  29. * # class 选填
  30. * 'class' => 'fec\block\TestMenu',
  31. * # view 为 必填 , view可以用两种方式
  32. * # view 1 使用绝对地址的方式
  33. * 'view' => '@fec/views/testmenu/index.php',
  34. * OR
  35. * # view 2 使用相对地址,通过当前模板进行查找
  36. * 'view' => 'cms/home/index.php',
  37. *
  38. * # 下面为选填
  39. * 'method'=> 'getLastData',
  40. * 'terry1'=> 'My1',
  41. * 'terry2'=> 'My2',
  42. * ]
  43. * 如果传递的是字符串,那么会去配置($widgetConfig)中查找
  44. * 最后找到后,通过renderContent函数,得到html
  45. * 该功能大致为通过一个动态数据提供者block,和内容显示部分view,view里面需要使用的动态变量
  46. * 由block提供,最终生成一个html区块,返回。
  47. */
  48. protected function actionRender($configKey, $parentThis = '')
  49. {
  50. $config = '';
  51. if (is_array($configKey)) {
  52. $config = $configKey;
  53. $configKey = '';
  54. } else {
  55. if (isset($this->widgetConfig[$configKey])) {
  56. $config = $this->widgetConfig[$configKey];
  57. } else {
  58. throw new InvalidValueException(" config key: '$configKey', can not find in ".'Yii::$service->page->widget->widgetConfig'.', you must config it before use it.');
  59. }
  60. }
  61. return $this->renderContent($configKey, $config, $parentThis);
  62. }
  63. /**
  64. * @param $configKey | string ,使用配置中的widget,该参数对应相应的数组key
  65. * @param $config,就是上面actionRender()方法中的参数,格式一样。
  66. * @param $parentThis | array or '' , 调用层传递的参数数组,可以在view中调用。
  67. *
  68. */
  69. protected function actionRenderContentHtml($configKey, $config, $parentThis = '')
  70. {
  71. if (!isset($config['view']) || empty($config['view'])
  72. ) {
  73. throw new InvalidConfigException('view and class must exist in array config!');
  74. }
  75. $params = [];
  76. $view = $config['view'];
  77. unset($config['view']);
  78. $viewFile = $this->getViewFile($view);
  79. if (!isset($config['class']) || empty($config['class'])) {
  80. if ($parentThis) {
  81. $params['parentThis'] = $parentThis;
  82. }
  83. return Yii::$app->view->renderFile($viewFile, $params);
  84. }
  85. if (isset($config['method']) && !empty($config['method'])) {
  86. $method = $config['method'];
  87. unset($config['method']);
  88. } else {
  89. $method = $this->defaultObMethod;
  90. }
  91. $ob = Yii::createObject($config);
  92. $params = $ob->$method();
  93. if ($parentThis) {
  94. $params['parentThis'] = $parentThis;
  95. }
  96. return Yii::$app->view->renderFile($viewFile, $params);
  97. }
  98. /**
  99. * @param $configKey | string , 标记,以及报错排查时使用的key。
  100. * @param $config,就是上面actionRender()方法中的参数,格式一样。
  101. * @param $parentThis | array or '' , 调用层传递的参数数组,可以在view中调用。
  102. *
  103. */
  104. protected function actionRenderContent($configKey, $config, $parentThis = '')
  105. {
  106. if (isset($config['cache']['enable']) && $config['cache']['enable']) {
  107. if (!isset($config['class']) || !$config['class']) {
  108. throw new InvalidConfigException('in widget ['.$configKey.'],you enable cache ,you must config widget class .');
  109. } elseif ($ob = new $config['class']()) {
  110. if ($ob instanceof BlockCache) {
  111. $cacheKey = $ob->getCacheKey();
  112. if (!($content = CCache::get($cacheKey))) {
  113. $cache = $config['cache'];
  114. $timeout = isset($cache['timeout']) ? $cache['timeout'] : 0;
  115. unset($config['cache']);
  116. $content = $this->renderContentHtml($configKey, $config, $parentThis);
  117. CCache::set($cacheKey, $content, $timeout);
  118. }
  119. return $content;
  120. } else {
  121. throw new InvalidConfigException($config['class'].' must implete fecshop\interfaces\block\BlockCache when you use block cache .');
  122. }
  123. }
  124. }
  125. // 查看 $config['class'] 是否在YiiRewriteMap重写中存在配置,如果存在,则替换
  126. !isset($config['class']) || $config['class'] = Yii::mapGetClassName($config['class']);
  127. $content = $this->renderContentHtml($configKey, $config, $parentThis);
  128. return $content;
  129. }
  130. /**
  131. * find theme file by mutil theme ,if not find view file and $throwError=true, it will throw InvalidValueException.
  132. */
  133. protected function getViewFile($view, $throwError = true)
  134. {
  135. $view = trim($view);
  136. if (substr($view, 0, 1) == '@') {
  137. return Yii::getAlias($view);
  138. }
  139. $absoluteDir = Yii::$service->page->theme->getThemeDirArr();
  140. foreach ($absoluteDir as $dir) {
  141. if ($dir) {
  142. $file = $dir.'/'.$view;
  143. //echo $file."<br/>";
  144. if (file_exists($file)) {
  145. return $file;
  146. }
  147. }
  148. }
  149. // not find view file
  150. if ($throwError) {
  151. $notExistFile = [];
  152. foreach ($absoluteDir as $dir) {
  153. if ($dir) {
  154. $file = $dir.'/'.$view;
  155. $notExistFile[] = $file;
  156. }
  157. }
  158. throw new InvalidValueException('view file is not exist in'.implode(',', $notExistFile));
  159. } else {
  160. return false;
  161. }
  162. }
  163. }