PageRenderTime 56ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/components/CmsBaseRenderer.php

https://bitbucket.org/lietu/nordcms-lietu
PHP | 317 lines | 193 code | 46 blank | 78 comment | 18 complexity | 1f27227af88ea32c48c1fe631e2e9ecf MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, Apache-2.0, GPL-3.0, BSD-2-Clause
  1. <?php
  2. /**
  3. * CmsBaseRenderer class file.
  4. * @author Christoffer Niska <christoffer.niska@nordsoftware.com>
  5. * @copyright Copyright &copy; 2011, Nord Software Ltd
  6. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  7. * @package cms.components
  8. */
  9. /**
  10. * Cms renderer base class. All renderers must be extended from this class.
  11. */
  12. class CmsBaseRenderer extends CComponent
  13. {
  14. protected $_patterns = array(
  15. 'block'=>'/{{block:([\w\d\._-]+)}}/i',
  16. 'email'=>'/{{email:([\w\d!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[\w\d!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[\w\d](?:[\w\d-]*[\w\d])?\.)+[\w\d](?:[\w\d-]*[\w\d])?)}}/i',
  17. 'file'=>'/{{file:([\d]+)}}/i',
  18. 'image'=>'/{{image:([\d]+)\|([\w]+)}}/i',
  19. 'link'=>'/{{(#?[\w\d\._-]+|https?:\/\/[\w\d_-]*(\.[\w\d_-]*)+.*)\|([\w\d\s-]+)}}/i',
  20. 'menu'=>'/{{menu:([\w\d\._-]+)}}/i',
  21. 'url'=>'/{{url:([\w\d\._-]+)}}/i',
  22. );
  23. static protected $blockStack = array();
  24. /**
  25. * Renders the given page.
  26. * @param CmsPage $page the page to render
  27. * @param bool $test If set to false, will handle errors internally, if set to true, will allow exceptions to pass through
  28. * @return string the rendered content
  29. */
  30. public function renderPage($page, $test=false)
  31. {
  32. $content = $page->body;
  33. $content = $this->renderURLs($content);
  34. $content = $this->renderLinks($content);
  35. $content = $this->renderEmails($content);
  36. $content = $this->renderImages($content);
  37. $content = $this->renderAttachments($content);
  38. $content = $this->renderBlocks($content, $test);
  39. $content = $this->renderMenus($content);
  40. return $content;
  41. }
  42. /**
  43. * Renders the given block.
  44. * @param CmsBlock $block the block to render
  45. * @param bool $test If set to false, will handle errors internally, if set to true, will allow exceptions to pass through
  46. * @return string the rendered content
  47. */
  48. public function renderBlock($block, $test=false)
  49. {
  50. // Check for infinite recursion
  51. if (in_array($block->name, self::$blockStack) === true) {
  52. throw new CmsRecursionException($block->name, self::$blockStack);
  53. }
  54. // Append current block name to the stack list
  55. self::$blockStack[] = $block->name;
  56. $content = $block->body;
  57. $content = $this->renderURLs($content);
  58. $content = $this->renderLinks($content);
  59. $content = $this->renderEmails($content);
  60. $content = $this->renderImages($content);
  61. $content = $this->renderAttachments($content);
  62. $content = $this->renderBlocks($content, $test);
  63. // Pop current block off the stack
  64. array_pop(self::$blockStack);
  65. return $content;
  66. }
  67. /**
  68. * Renders blocks within the given content.
  69. * @param string $content the content being rendered
  70. * @param bool $test If set to false, will handle errors internally, if set to true, will allow exceptions to pass through
  71. * @return string the content
  72. */
  73. protected function renderBlocks($content, $test=false)
  74. {
  75. $matches = array();
  76. preg_match_all($this->_patterns['block'], $content, $matches);
  77. $pairs = array();
  78. foreach ($matches[1] as $index => $name)
  79. {
  80. /** @var CmsBlock $block */
  81. $block = Yii::app()->cms->loadBlock($name);
  82. $blockContent = '';
  83. if ($block->published) {
  84. try {
  85. $blockContent = $block->render($test);
  86. } catch (CmsRecursionException $e) {
  87. // If we want to pass through exceptions, rethrow, otherwise ignore
  88. if ($test)
  89. throw $e;
  90. }
  91. }
  92. $pairs[$matches[0][$index]] = $blockContent;
  93. }
  94. if (!empty($pairs))
  95. $content = strtr($content, $pairs);
  96. return $content;
  97. }
  98. /**
  99. * Renders links within the given content.
  100. * @param string $content the content being rendered
  101. * @return string the content
  102. */
  103. protected function renderLinks($content)
  104. {
  105. $matches = array();
  106. preg_match_all($this->_patterns['link'], $content, $matches);
  107. $pairs = array();
  108. foreach ($matches[1] as $index => $target)
  109. {
  110. // If the target doesn't include 'http' it's treated as an internal link.
  111. if (strpos($target, '#') !== 0 && strpos($target, 'http') === false)
  112. {
  113. /** @var Cms $cms */
  114. $cms = Yii::app()->cms;
  115. /** @var CmsPage $page */
  116. $page = $cms->loadPage($target);
  117. $target = $page instanceof CmsPage ? $page->getUrl() : '#';
  118. }
  119. $text = $matches[3][$index];
  120. $pairs[$matches[0][$index]] = CHtml::link($text, $target);
  121. }
  122. if (!empty($pairs))
  123. $content = strtr($content, $pairs);
  124. return $content;
  125. }
  126. /**
  127. * Renders URLS within the given content.
  128. * @param string $content the content being rendered
  129. * @return string the content
  130. */
  131. protected function renderURLs($content)
  132. {
  133. $matches = array();
  134. preg_match_all($this->_patterns['url'], $content, $matches);
  135. $pairs = array();
  136. foreach ($matches[1] as $index => $target)
  137. {
  138. // If the target doesn't include 'http' it's treated as an internal link.
  139. if (strpos($target, '#') !== 0 && strpos($target, 'http') === false)
  140. {
  141. /** @var Cms $cms */
  142. $cms = Yii::app()->cms;
  143. /** @var CmsPage $page */
  144. $page = $cms->loadPage($target);
  145. $target = $page instanceof CmsPage ? $page->getUrl() : '#';
  146. }
  147. $pairs[$matches[0][$index]] = $target;
  148. }
  149. if (!empty($pairs))
  150. $content = strtr($content, $pairs);
  151. return $content;
  152. }
  153. /**
  154. * Renders emails within the given content.
  155. * @param string $content the content being rendered
  156. * @return string the content
  157. */
  158. protected function renderEmails($content)
  159. {
  160. $matches = array();
  161. preg_match_all($this->_patterns['email'], $content, $matches);
  162. $pairs = array();
  163. foreach ($matches[1] as $index => $id)
  164. {
  165. $email = str_rot13($matches[1][$index]);
  166. $pairs[$matches[0][$index]] = CHtml::mailto($email, $email, array('class'=>'email', 'rel'=>'nofollow'));
  167. }
  168. if (!empty($pairs))
  169. {
  170. $content = strtr($content, $pairs);
  171. /** @var CClientScript $cs */
  172. $cs = Yii::app()->getClientScript();
  173. $cs->registerScriptFile(Yii::app()->cms->getAssetsUrl().'/js/cms-rot13.js');
  174. $cs->registerScript(__CLASS__.'#'.uniqid(true, true).'_emailObfuscation', "
  175. !function($) {
  176. $('.email').each(function() {
  177. var element = $(this);
  178. if (!element.attr('data-decoded')) {
  179. var href = $(this).attr('href'),
  180. address = Cms.Rot13.decode(href.substring(href.indexOf(':') + 1)),
  181. value = Cms.Rot13.decode($(this).text());
  182. element.attr('href', 'mailto:' + address);
  183. element.text(value);
  184. element.attr('data-decoded', 1);
  185. }
  186. });
  187. }(jQuery);
  188. ");
  189. }
  190. return $content;
  191. }
  192. /**
  193. * Renders images within the given content.
  194. * @param string $content the content being rendered
  195. * @return string the content
  196. */
  197. protected function renderImages($content)
  198. {
  199. $matches = array();
  200. preg_match_all($this->_patterns['image'], $content, $matches);
  201. $pairs = array();
  202. foreach ($matches[1] as $index => $id)
  203. {
  204. /** @var Image $image */
  205. $image = Yii::app()->image->load($id);
  206. if ($image instanceof Image)
  207. {
  208. $url = $image->getUrl($matches[2][$index]);
  209. if ($url !== false)
  210. $pairs[$matches[0][$index]] = CHtml::image($url, $image->name);
  211. }
  212. }
  213. if (!empty($pairs) )
  214. $content = strtr($content, $pairs);
  215. return $content;
  216. }
  217. /**
  218. * Renders attachments within the given content.
  219. * @param string $content the content being rendered
  220. * @return string the content
  221. */
  222. protected function renderAttachments($content)
  223. {
  224. $matches = array();
  225. preg_match_all($this->_patterns['file'], $content, $matches);
  226. $pairs = array();
  227. foreach ($matches[1] as $index => $id)
  228. {
  229. /** @var CmsAttachment $attachment */
  230. $attachment = CmsAttachment::model()->findByPk($id);
  231. if ($attachment instanceof CmsAttachment)
  232. {
  233. $url = $attachment->getUrl();
  234. $name = $attachment->resolveName();
  235. $pairs[$matches[0][$index]] = CHtml::link($name, $url);
  236. }
  237. }
  238. if (!empty($pairs))
  239. $content = strtr($content, $pairs);
  240. return $content;
  241. }
  242. /**
  243. * Removes the block tags within the given content.
  244. * @param string $content the content being rendered
  245. * @return string the content
  246. */
  247. public function removeBlocks($content)
  248. {
  249. return preg_replace($this->_patterns['block'], '', $content);
  250. }
  251. /**
  252. * Renders menus within the given content.
  253. * @param string $content the content being rendered
  254. * @return string the content
  255. */
  256. protected function renderMenus($content)
  257. {
  258. $matches = array();
  259. preg_match_all($this->_patterns['menu'], $content, $matches);
  260. $pairs = array();
  261. foreach ($matches[1] as $index => $name)
  262. {
  263. /** @var CmsMenu $menu */
  264. $menu = Yii::app()->cms->loadMenu($name);
  265. $pairs[$matches[0][$index]] = $menu->render();
  266. }
  267. if (!empty($pairs))
  268. $content = strtr($content, $pairs);
  269. return $content;
  270. }
  271. }