MyHelper.php 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. <?php
  2. App::uses('Helper', 'View');
  3. App::uses('Router', 'Routing');
  4. App::uses('UrlCacheManager', 'Tools.Routing');
  5. /**
  6. * Helper enhancements for CakePHP
  7. *
  8. * @author Mark Scherer
  9. * @license MIT
  10. */
  11. class MyHelper extends Helper {
  12. /**
  13. * Manually load helpers.
  14. *
  15. * Also makes sure callbacks are triggered.
  16. *
  17. * @param array $helpers (either strings, or [string => array(config...)])
  18. * @param boolean $callbacks - trigger missed callbacks
  19. * @return void
  20. */
  21. public function loadHelpers($helpers = array(), $callbacks = false) {
  22. foreach ((array)$helpers as $helper => $config) {
  23. if (is_int($helper)) {
  24. $helper = $config;
  25. $config = array();
  26. }
  27. list($plugin, $helperName) = pluginSplit($helper, true);
  28. if (isset($this->{$helperName})) {
  29. continue;
  30. }
  31. App::uses($helperName . 'Helper', $plugin . 'View/Helper');
  32. $helperFullName = $helperName . 'Helper';
  33. $this->{$helperName} = new $helperFullName($this->_View, (array)$config);
  34. if ($callbacks) {
  35. if (method_exists($helper, 'beforeRender')) {
  36. $this->{$helperName}->beforeRender();
  37. }
  38. }
  39. }
  40. }
  41. /**
  42. * Display image tag from blob content.
  43. * Enhancement for HtmlHelper. Defaults to png image
  44. *
  45. * Options:
  46. * - type: png, gif, jpg, ...
  47. *
  48. * @param binary $content
  49. * @param array $options
  50. * @return string html imageTag
  51. */
  52. public function imageFromBlob($content, $options = array()) {
  53. $options += array('type' => 'png');
  54. $mimeType = 'image/' . $options['type'];
  55. $text = 'data:' . $mimeType . ';base64,' . base64_encode($content);
  56. return sprintf($this->_tags['image'], $text, $this->_parseAttributes($options, null, '', ' '));
  57. }
  58. /**
  59. * HTML Helper extension for HTML5 time
  60. * The time element represents either a time on a 24 hour clock,
  61. * or a precise date in the proleptic Gregorian calendar,
  62. * optionally with a time and a time-zone offset.
  63. *
  64. * Options:
  65. * - 'format' STRING: Use the specified TimeHelper method (or format()).
  66. * FALSE: Generate the datetime. NULL: Do nothing.
  67. * - 'datetime' STRING: If 'format' is STRING use as the formatting string.
  68. * FALSE: Don't generate attribute
  69. *
  70. * @param $content string Time
  71. * @param $options array Options
  72. * @return string HTML time tag.
  73. */
  74. public function time($content, $options = array()) {
  75. if (!isset($this->tags['time'])) {
  76. $this->tags['time'] = '<time%s>%s</time>';
  77. }
  78. $options = array_merge(array(
  79. 'datetime' => '%Y-%m-%d %T',
  80. 'pubdate' => false,
  81. 'format' => '%Y-%m-%d %T',
  82. ), $options);
  83. if ($options['format'] !== null) {
  84. if (!isset($this->Time)) {
  85. App::uses('TimeHelper', 'View/Helper');
  86. $this->Time = new TimeHelper($this->_View);
  87. }
  88. }
  89. if ($options['format']) {
  90. if (method_exists($this->Time, $options['format'])) {
  91. $content = $this->Time->$options['format']($content);
  92. } else {
  93. $content = $this->Time->i18nFormat($content, $options['format']);
  94. }
  95. $options['datetime'] = $this->Time->i18nFormat(strtotime($content), $options['datetime']);
  96. } elseif ($options['format'] === false && $options['datetime']) {
  97. $options['datetime'] = $this->Time->i18nFormat(strtotime($content), $options['datetime']);
  98. }
  99. if ($options['pubdate']) {
  100. $pubdate = true;
  101. }
  102. unset($options['format']);
  103. unset($options['pubdate']);
  104. $attributes = $this->_parseAttributes($options, array(0), ' ', '');
  105. if (isset($pubdate)) {
  106. $attributes .= ' pubdate';
  107. }
  108. return sprintf($this->tags['time'], $attributes, $content);
  109. }
  110. /**
  111. * For convenience functions Html::defaultLink() and defaultUrl().
  112. *
  113. * @var array
  114. */
  115. protected $_linkDefaults = null;
  116. /**
  117. * Keep named and query params for pagination/filter after edit etc.
  118. *
  119. * @params same as Html::link($title, $url, $options, $confirmMessage)
  120. * @return string Link
  121. */
  122. public function completeLink($title, $url = null, $options = array(), $confirmMessage = false) {
  123. // Named are deprecated
  124. if (is_array($url)) {
  125. $url += $this->params['named'];
  126. }
  127. if (is_array($url)) {
  128. if (!isset($url['?'])) {
  129. $url['?'] = array();
  130. }
  131. $url['?'] += $this->request->query;
  132. }
  133. return $this->link($title, $url, $options, $confirmMessage);
  134. }
  135. /**
  136. * Keep named and query params for pagination/filter after edit etc.
  137. *
  138. * @params same as Html::url($url, $options, $escape)
  139. * @return string Link
  140. */
  141. public function completeUrl($url = null, $full = false, $escape = true) {
  142. // Named are deprecated
  143. if (is_array($url)) {
  144. $url += $this->params['named'];
  145. }
  146. if (is_array($url)) {
  147. if (!isset($url['?'])) {
  148. $url['?'] = array();
  149. }
  150. $url['?'] += $this->request->query;
  151. }
  152. return $this->url($url, $options, $escape);
  153. }
  154. /**
  155. * Convenience function for normal links.
  156. * Useful for layout links and links inside elements etc if you don't want to
  157. * verbosely reset all parts of it (prefix, plugin, ...).
  158. *
  159. * @params same as Html::link($title, $url, $options, $confirmMessage)
  160. * @return string HTML Link
  161. */
  162. public function defaultLink($title, $url = null, $options = array(), $confirmMessage = false) {
  163. if ($this->_linkDefaults === null) {
  164. if (!class_exists('CommonComponent')) {
  165. App::uses('CommonComponent', 'Tools.Controller/Component');
  166. }
  167. $this->_linkDefaults = CommonComponent::defaultUrlParams();
  168. }
  169. if (!defined('PREFIX_ADMIN')) {
  170. define('PREFIX_ADMIN', 'admin');
  171. }
  172. if ($url !== null && is_array($url)) {
  173. $url = array_merge($this->_linkDefaults, $url);
  174. if (!empty($url[PREFIX_ADMIN])) {
  175. $options['rel'] = 'nofollow';
  176. }
  177. } elseif (is_array($title)) {
  178. $title = array_merge($this->_linkDefaults, $title);
  179. if (!empty($title[PREFIX_ADMIN])) {
  180. $options['rel'] = 'nofollow';
  181. }
  182. }
  183. //$this->log($url, '404');
  184. return $this->link($title, $url, $options, $confirmMessage);
  185. }
  186. /**
  187. * Convenience function for normal urls.
  188. * Useful for layout links and links inside elements etc if you don't want to
  189. * verbosely reset all parts of it (prefix, plugin, ...).
  190. *
  191. * @params same as Html::url($url, $full)
  192. * @return string URL
  193. */
  194. public function defaultUrl($url = null, $full = false) {
  195. if ($this->_linkDefaults === null) {
  196. if (!class_exists('CommonComponent')) {
  197. App::uses('CommonComponent', 'Tools.Controller/Component');
  198. }
  199. $this->_linkDefaults = CommonComponent::defaultUrlParams();
  200. }
  201. if ($url !== null && is_array($url)) {
  202. $url = array_merge($this->_linkDefaults, $url);
  203. }
  204. return $this->url($url, $full);
  205. }
  206. /**
  207. * Enhancement to htmlHelper which allows the crumbs protected array
  208. * to be cleared so that more than one set of crumbs can be generated in the same view.
  209. *
  210. * @return void
  211. */
  212. public function resetCrumbs() {
  213. $this->_crumbs = array();
  214. }
  215. /**
  216. * This function is responsible for setting up the Url cache before the application starts generating urls in views
  217. *
  218. * @return void
  219. */
  220. public function beforeRender($viewFile) {
  221. if (!Configure::read('UrlCache.active') || Configure::read('UrlCache.runtime.beforeRender')) {
  222. return;
  223. }
  224. # todo: maybe lazy load with HtmlHelper::url()?
  225. UrlCacheManager::init($this->_View);
  226. Configure::write('UrlCache.runtime.beforeRender', true);
  227. }
  228. /**
  229. * This method will store the current generated urls into a persistent cache for next use
  230. *
  231. * @return void
  232. */
  233. public function afterLayout($layoutFile) {
  234. if (!Configure::read('UrlCache.active') || Configure::read('UrlCache.runtime.afterLayout')) {
  235. return;
  236. }
  237. UrlCacheManager::finalize();
  238. Configure::write('UrlCache.runtime.afterLayout', true);
  239. }
  240. /**
  241. * Intercepts the parent url function to first look if the cache was already generated for the same params
  242. *
  243. * @param mixed $url url to generate using cakephp array syntax
  244. * @param boolean|array $full whether to generate a full url or not (http scheme). As array: full, escape.
  245. * @return string
  246. * @see Helper::url()
  247. */
  248. public function url($url = null, $full = false) {
  249. if (is_array($full)) {
  250. $escape = isset($full['ecape']) ? $full['escape'] : true;
  251. $full = isset($full['full']) ? $full['full'] : false;
  252. } else {
  253. $escape = true;
  254. }
  255. if (Configure::read('UrlCache.active')) {
  256. if ($cachedUrl = UrlCacheManager::get($url, $full)) {
  257. return $cachedUrl;
  258. }
  259. }
  260. if (!$escape) {
  261. $routerUrl = Router::url($url, $full);
  262. } else {
  263. $routerUrl = parent::url($url, $full);
  264. }
  265. if (Configure::read('UrlCache.active')) {
  266. UrlCacheManager::set($routerUrl);
  267. }
  268. return $routerUrl;
  269. }
  270. /**
  271. * Generate url for given asset file. Depending on options passed provides full url with domain name.
  272. * Also calls Helper::assetTimestamp() to add timestamp to local files.
  273. * Uses Configure::read('App.assetBaseUrl') for CDN setup.
  274. *
  275. * @param string|array Path string or url array
  276. * @param array $options Options array. Possible keys:
  277. * `fullBase` Return full url with domain name
  278. * `pathPrefix` Path prefix for relative URLs
  279. * `ext` Asset extension to append
  280. * `plugin` False value will prevent parsing path as a plugin
  281. * @return string Generated url
  282. */
  283. public function assetUrl($path, $options = array()) {
  284. if (!Configure::read('App.assetBaseUrl')) {
  285. return parent::assetUrl($path, $options);
  286. }
  287. if (is_array($path)) {
  288. return $this->url($path, !empty($options['fullBase']));
  289. }
  290. if (strpos($path, '://') !== false) {
  291. return $path;
  292. }
  293. if (!array_key_exists('plugin', $options) || $options['plugin'] !== false) {
  294. list($plugin, $path) = $this->_View->pluginSplit($path, false);
  295. }
  296. if (!empty($options['pathPrefix']) && $path[0] !== '/') {
  297. $path = $options['pathPrefix'] . $path;
  298. }
  299. if (
  300. !empty($options['ext']) &&
  301. strpos($path, '?') === false &&
  302. substr($path, -strlen($options['ext'])) !== $options['ext']
  303. ) {
  304. $path .= $options['ext'];
  305. }
  306. if (isset($plugin)) {
  307. $path = Inflector::underscore($plugin) . '/' . $path;
  308. }
  309. $path = $this->_encodeUrl($this->assetTimestamp($this->webroot($path)));
  310. $path = rtrim(Configure::read('App.assetBaseUrl'), '/') . '/' . ltrim($path, '/');
  311. return $path;
  312. }
  313. }