/components/CmsBaseRenderer.php

https://bitbucket.org/tlemmens/fixes · PHP · 279 lines · 170 code · 38 blank · 71 comment · 15 complexity · 08f7417efe3ecd0e6a66dfe2aa5bb614 MD5 · raw file

  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. 'email'=>'/{{email:([\w\d!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[\w\d!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[\w\d](?:[\w\d-]*[\w\d])?\.)+[\w\d](?:[\w\d-]*[\w\d])?)}}/i',
  16. 'file'=>'/{{file:([\d]+)}}/i',
  17. 'image'=>'/{{image:([\d]+)}}/i',
  18. 'link'=>'/{{(#?[\w\d\._-]+|https?:\/\/[\w\d_-]*(\.[\w\d_-]*)+.*)\|([\w\d\s-]+)}}/i',
  19. 'node'=>'/{{node:([\w\d\._-]+)}}/i',
  20. 'url'=>'/{{url:([\w\d\._-]+)}}/i',
  21. );
  22. /**
  23. * Renders a specific node.
  24. * @param CmsNode $node the node to render
  25. * @return string the rendered node
  26. */
  27. public function render($node)
  28. {
  29. $heading = str_replace('{heading}', $node->heading, Yii::app()->cms->headingTemplate);
  30. $content = $this->renderHeading($heading, $node->body);
  31. $content = $this->renderURLs($content);
  32. $content = $this->renderLinks($content);
  33. $content = $this->renderEmails($content);
  34. $content = $this->renderImages($content);
  35. $content = $this->renderAttachments($content);
  36. $content = $this->renderNodes($content);
  37. return $content;
  38. }
  39. /**
  40. * Renders a specific node as a widget.
  41. * @param CmsNode $node the node to render
  42. * @return string the rendered node
  43. */
  44. public function renderWidget($node)
  45. {
  46. $heading = str_replace('{heading}', $node->heading, Yii::app()->cms->widgetHeadingTemplate);
  47. $content = $this->renderHeading($heading, $node->body);
  48. $content = $this->renderURLs($content);
  49. $content = $this->renderLinks($content);
  50. $content = $this->renderEmails($content);
  51. $content = $this->renderImages($content);
  52. $content = $this->renderAttachments($content);
  53. $content = $this->removeNodes($content); // widgets do not render inline nodes
  54. return $content;
  55. }
  56. /**
  57. * Renders the heading.
  58. * @param string $heading the heading to render
  59. * @param string $content the content being rendered
  60. * @return string the content
  61. */
  62. protected function renderHeading($heading, $content)
  63. {
  64. return str_replace('{{heading}}', $heading, $content);
  65. }
  66. /**
  67. * Renders nodes within the given content.
  68. * @param string $content the content being rendered
  69. * @return string the content
  70. */
  71. protected function renderNodes($content)
  72. {
  73. $matches = array();
  74. preg_match_all($this->_patterns['node'], $content, $matches);
  75. $pairs = array();
  76. foreach ($matches[1] as $index => $name)
  77. {
  78. /** @var CmsNode $node */
  79. $node = Yii::app()->cms->loadNode($name);
  80. $pairs[$matches[0][$index]] = $node instanceof CmsNode && $node->level === CmsNode::LEVEL_BLOCK
  81. ? $node->renderWidget() : '';
  82. }
  83. if (!empty($pairs))
  84. $content = strtr($content, $pairs);
  85. return $content;
  86. }
  87. /**
  88. * Renders links within the given content.
  89. * @param string $content the content being rendered
  90. * @return string the content
  91. */
  92. protected function renderLinks($content)
  93. {
  94. $matches = array();
  95. preg_match_all($this->_patterns['link'], $content, $matches);
  96. $pairs = array();
  97. foreach ($matches[1] as $index => $target)
  98. {
  99. // If the target doesn't include 'http' it's treated as an internal link.
  100. if (strpos($target, '#') !== 0 && strpos($target, 'http') === false)
  101. {
  102. /** @var Cms $cms */
  103. $cms = Yii::app()->cms;
  104. /** @var CmsNode $node */
  105. $node = $cms->loadNode($target);
  106. $target = $node instanceof CmsNode ? $node->getUrl() : '#';
  107. }
  108. $text = $matches[3][$index];
  109. $pairs[$matches[0][$index]] = CHtml::link($text, $target);
  110. }
  111. if (!empty($pairs))
  112. $content = strtr($content, $pairs);
  113. return $content;
  114. }
  115. /**
  116. * Renders URLS within the given content.
  117. * @param string $content the content being rendered
  118. * @return string the content
  119. */
  120. protected function renderURLs($content)
  121. {
  122. $matches = array();
  123. preg_match_all($this->_patterns['url'], $content, $matches);
  124. $pairs = array();
  125. foreach ($matches[1] as $index => $target)
  126. {
  127. // If the target doesn't include 'http' it's treated as an internal link.
  128. if (strpos($target, '#') !== 0 && strpos($target, 'http') === false)
  129. {
  130. /** @var Cms $cms */
  131. $cms = Yii::app()->cms;
  132. /** @var CmsNode $node */
  133. $node = $cms->loadNode($target);
  134. $target = $node !== null ? $node->getUrl() : '#';
  135. }
  136. $pairs[$matches[0][$index]] = $target;
  137. }
  138. if (!empty($pairs))
  139. $content = strtr($content, $pairs);
  140. return $content;
  141. }
  142. /**
  143. * Renders emails within the given content.
  144. * @param string $content the content being rendered
  145. * @return string the content
  146. */
  147. protected function renderEmails($content)
  148. {
  149. $matches = array();
  150. preg_match_all($this->_patterns['email'], $content, $matches);
  151. $pairs = array();
  152. foreach ($matches[1] as $index => $id)
  153. {
  154. $email = str_rot13($matches[1][$index]);
  155. $pairs[$matches[0][$index]] = CHtml::mailto($email, $email, array('class'=>'email', 'rel'=>'nofollow'));
  156. }
  157. if (!empty($pairs))
  158. {
  159. $content = strtr($content, $pairs);
  160. /** @var CClientScript $cs */
  161. $cs = Yii::app()->getClientScript();
  162. $assetsUrl = Yii::app()->cms->getAssetsUrl();
  163. $cs->registerScriptFile($assetsUrl.'/js/cms-rot13.js');
  164. $cs->registerScript(__CLASS__.'#'.uniqid(true, true).'_emailObfuscation', "
  165. (function($) {
  166. $('.email').each(function() {
  167. var element = $(this);
  168. if (!element.attr('data-decoded')) {
  169. var href = $(this).attr('href'),
  170. address = Cms.Rot13.decode(href.substring(href.indexOf(':') + 1)),
  171. value = Cms.Rot13.decode($(this).text());
  172. element.attr('href', 'mailto:' + address);
  173. element.text(value);
  174. element.attr('data-decoded', 1);
  175. }
  176. });
  177. })(jQuery);
  178. ");
  179. }
  180. return $content;
  181. }
  182. /**
  183. * Renders images within the given content.
  184. * @param string $content the content being rendered
  185. * @return string the content
  186. */
  187. protected function renderImages($content)
  188. {
  189. $matches = array();
  190. preg_match_all($this->_patterns['image'], $content, $matches);
  191. $pairs = array();
  192. foreach ($matches[1] as $index => $id)
  193. {
  194. /** @var CmsAttachment $attachment */
  195. $attachment = CmsAttachment::model()->findByPk($id);
  196. if ($attachment instanceof CmsAttachment && strpos($attachment->mimeType, 'image') !== false)
  197. {
  198. $url = $attachment->getUrl();
  199. $name = $attachment->resolveName();
  200. $pairs[$matches[0][$index]] = CHtml::image($url, $name);
  201. }
  202. }
  203. if (!empty($pairs) )
  204. $content = strtr($content, $pairs);
  205. return $content;
  206. }
  207. /**
  208. * Renders attachments within this node.
  209. * @param string $content the content being rendered
  210. * @return string the content
  211. */
  212. protected function renderAttachments($content)
  213. {
  214. $matches = array();
  215. preg_match_all($this->_patterns['file'], $content, $matches);
  216. $pairs = array();
  217. foreach ($matches[1] as $index => $id)
  218. {
  219. /** @var CmsAttachment $attachment */
  220. $attachment = CmsAttachment::model()->findByPk($id);
  221. if ($attachment instanceof CmsAttachment)
  222. {
  223. $url = $attachment->getUrl();
  224. $name = $attachment->resolveName();
  225. $pairs[$matches[0][$index]] = CHtml::link($name, $url);
  226. }
  227. }
  228. if (!empty($pairs))
  229. $content = strtr($content, $pairs);
  230. return $content;
  231. }
  232. /**
  233. * Removes the node tags within the given content.
  234. * @param string $content the content being rendered
  235. * @return string the content
  236. */
  237. public function removeNodes($content)
  238. {
  239. return preg_replace($this->_patterns['node'], '', $content);
  240. }
  241. }