PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/Croogo/View/Helper/LayoutHelper.php

https://github.com/kareypowell/croogo
PHP | 513 lines | 306 code | 30 blank | 177 comment | 45 complexity | 7ff7a0c50681209b7c08c7d37b3e896c MD5 | raw file
  1. <?php
  2. App::uses('AppHelper', 'View/Helper');
  3. /**
  4. * Layout Helper
  5. *
  6. * @category Helper
  7. * @package Croogo.Croogo.View.Helper
  8. * @version 1.0
  9. * @author Fahad Ibnay Heylaal <contact@fahad19.com>
  10. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  11. * @link http://www.croogo.org
  12. */
  13. class LayoutHelper extends AppHelper {
  14. /**
  15. * Other helpers used by this helper
  16. *
  17. * @var array
  18. * @access public
  19. */
  20. public $helpers = array(
  21. 'Croogo.Croogo',
  22. 'Html',
  23. 'Form',
  24. 'Session',
  25. 'Js',
  26. );
  27. /**
  28. * Core helpers
  29. *
  30. * Extra supported callbacks, like beforeNodeInfo() and afterNodeInfo(),
  31. * won't be called for these helpers.
  32. *
  33. * @var array
  34. * @access public
  35. */
  36. public $coreHelpers = array(
  37. // CakePHP
  38. 'Ajax',
  39. 'Cache',
  40. 'Form',
  41. 'Html',
  42. 'Javascript',
  43. 'JqueryEngine',
  44. 'Js',
  45. 'MootoolsEngine',
  46. 'Number',
  47. 'Paginator',
  48. 'PrototypeEngine',
  49. 'Rss',
  50. 'Session',
  51. 'Text',
  52. 'Time',
  53. 'Xml',
  54. // Croogo
  55. 'Filemanager',
  56. 'Image',
  57. 'Layout',
  58. 'Recaptcha',
  59. );
  60. /**
  61. * Provides backward compatibility for deprecated methods
  62. */
  63. public function __call($method, $params) {
  64. $mapMethods = array(
  65. 'meta' => array('Meta.Meta', 'meta'),
  66. 'metaField' => array('Meta.Meta', 'field'),
  67. 'blocks' => array('Blocks.Regions', 'blocks'),
  68. 'regionIsEmpty' => array('Blocks.Regions', 'isEmpty'),
  69. 'linkStringToArray' => array('Menus.Menus', 'linkStringToArray'),
  70. 'menu' => array('Menus.Menus', 'menu'),
  71. 'nestedLinks' => array('Menus.Menus', 'nestedLinks'),
  72. 'nestedTerms' => array('Taxonomy.Taxonomies', 'nestedTerms'),
  73. 'vocabulary' => array('Taxonomy.Taxonomies', 'vocabulary'),
  74. 'node' => array('Nodes.Nodes', 'field'),
  75. 'nodeBody' => array('Nodes.Nodes', 'body'),
  76. 'nodeExcerpt' => array('Nodes.Nodes', 'excerpt'),
  77. 'nodeInfo' => array('Nodes.Nodes', 'info'),
  78. 'nodeList' => array('Nodes.Nodes', 'nodeList'),
  79. 'nodeMoreInfo' => array('Nodes.Nodes', 'moreInfo'),
  80. 'setNode' => array('Nodes.Nodes', 'set'),
  81. 'setNodeField' => array('Nodes.Nodes', 'field'),
  82. 'adminRowActions' => array('Croogo', 'adminRowActions'),
  83. 'adminTabs' => array('Croogo', 'adminTabs'),
  84. 'adminMenus' => array('Croogo', 'adminMenus'),
  85. );
  86. if (!isset($mapMethods[$method])) {
  87. trigger_error(__d('croogo', 'Method %1$s::%2$s does not exist', get_class($this), $method), E_USER_WARNING);
  88. return;
  89. }
  90. $mapped = $mapMethods[$method];
  91. list($helper, $method) = $mapped;
  92. list($plugin, $helper) = pluginSplit($helper, true);
  93. if (!$this->{$helper}) {
  94. if (!$this->_View->Helpers->loaded($helper)) {
  95. $this->_View->Helpers->load($helper);
  96. }
  97. $this->{$helper} = $this->_View->{$helper};
  98. }
  99. return call_user_func_array(array($this->{$helper}, $method), $params);
  100. }
  101. /**
  102. * Provides backward compatibility for deprecated properties
  103. */
  104. public function __get($name) {
  105. switch ($name) {
  106. case 'node':
  107. return $this->_View->Nodes->node;
  108. default:
  109. return parent::__get($name);
  110. }
  111. }
  112. /**
  113. * Provides backward compatibility for deprecated properties
  114. */
  115. public function __set($name, $val) {
  116. switch ($name) {
  117. case 'node':
  118. return $this->_View->Nodes->node = $val;
  119. default:
  120. return parent::__set($name, $val);
  121. }
  122. }
  123. /**
  124. * Javascript variables
  125. *
  126. * Shows croogo.js file along with useful information like the applications's basePath, etc.
  127. *
  128. * Also merges Configure::read('Js') with the Croogo js variable.
  129. * So you can set javascript info anywhere like Configure::write('Js.my_var', 'my value'),
  130. * and you can access it like 'Croogo.my_var' in your javascript.
  131. *
  132. * @return string
  133. */
  134. public function js() {
  135. $croogo = array();
  136. if (isset($this->request->params['locale'])) {
  137. $croogo['basePath'] = Router::url('/' . $this->request->params['locale'] . '/');
  138. } else {
  139. $croogo['basePath'] = Router::url('/');
  140. }
  141. $validKeys = array(
  142. 'plugin' => null,
  143. 'controller' => null,
  144. 'action' => null,
  145. 'named' => null,
  146. );
  147. $croogo['params'] = array_intersect_key(
  148. array_merge($validKeys, $this->request->params),
  149. $validKeys
  150. );
  151. if (is_array(Configure::read('Js'))) {
  152. $croogo = Hash::merge($croogo, Configure::read('Js'));
  153. }
  154. return $this->Html->scriptBlock('var Croogo = ' . $this->Js->object($croogo) . ';');
  155. }
  156. /**
  157. * Status
  158. *
  159. * instead of 0/1, show tick/cross
  160. *
  161. * @param integer $value 0 or 1
  162. * @return string formatted img tag
  163. */
  164. public function status($value) {
  165. if ($value == 1) {
  166. $icon = 'ok';
  167. $class = 'green';
  168. } else {
  169. $icon = 'remove';
  170. $class = 'red';
  171. }
  172. if (method_exists($this->Html, 'icon')) {
  173. return $this->Html->icon($icon, compact('class'));
  174. } else {
  175. if (empty($this->_View->CroogoHtml)) {
  176. $this->_View->Helpers->load('Croogo.CroogoHtml');
  177. }
  178. return $this->_View->CroogoHtml->icon($icon, compact('class'));
  179. }
  180. }
  181. /**
  182. * Display value from $item array
  183. *
  184. * @param $item array of values
  185. * @param $model string model alias
  186. * @param $field string field name
  187. * @param $options array
  188. * @return string
  189. */
  190. public function displayField($item, $model, $field, $options = array()) {
  191. extract(array_intersect_key($options, array(
  192. 'type' => null,
  193. 'url' => array(),
  194. 'options' => array(),
  195. )));
  196. switch ($type) {
  197. case 'boolean':
  198. $out = $this->status($item[$model][$field]);
  199. break;
  200. default:
  201. $out = h($item[$model][$field]);
  202. break;
  203. }
  204. if (!empty($url)) {
  205. if (isset($url['pass'])) {
  206. $passVars = is_string($url['pass']) ? array($url['pass']) : $url['pass'];
  207. foreach ($passVars as $passField) {
  208. $url[] = $item[$model][$passField];
  209. }
  210. unset($url['pass']);
  211. }
  212. if (isset($url['named'])) {
  213. $namedVars = is_string($url['named']) ? array($url['named']) : $url['named'];
  214. foreach ($namedVars as $namedField) {
  215. $url[$namedField] = $item[$model][$namedField];
  216. }
  217. unset($url['named']);
  218. }
  219. $out = $this->Html->link($out, $url, $options);
  220. }
  221. return $out;
  222. }
  223. /**
  224. * Show flash message
  225. *
  226. * @return string
  227. */
  228. public function sessionFlash() {
  229. $messages = $this->Session->read('Message');
  230. $output = '';
  231. if (is_array($messages)) {
  232. foreach (array_keys($messages) as $key) {
  233. $output .= $this->Session->flash($key);
  234. }
  235. }
  236. return $output;
  237. }
  238. /**
  239. * isLoggedIn
  240. *
  241. * if User is logged in
  242. *
  243. * @return boolean
  244. */
  245. public function isLoggedIn() {
  246. if ($this->Session->check('Auth.User.id')) {
  247. return true;
  248. } else {
  249. return false;
  250. }
  251. }
  252. /**
  253. * Feed
  254. *
  255. * RSS feeds
  256. *
  257. * @param boolean $returnUrl if true, only the URL will be returned
  258. * @return string
  259. */
  260. public function feed($returnUrl = false) {
  261. if (Configure::read('Site.feed_url')) {
  262. $url = Configure::read('Site.feed_url');
  263. } else {
  264. /*$url = Router::url(array(
  265. 'controller' => 'nodes',
  266. 'action' => 'index',
  267. 'type' => 'blog',
  268. 'ext' => 'rss',
  269. ));*/
  270. $url = '/promoted.rss';
  271. }
  272. if ($returnUrl) {
  273. $output = $url;
  274. } else {
  275. $url = Router::url($url);
  276. $output = '<link href="' . $url . '" type="application/rss+xml" rel="alternate" title="RSS 2.0" />';
  277. return $output;
  278. }
  279. return $output;
  280. }
  281. /**
  282. * Get Role ID
  283. *
  284. * @return integer
  285. */
  286. public function getRoleId() {
  287. if ($this->isLoggedIn()) {
  288. $roleId = $this->Session->read('Auth.User.role_id');
  289. } else {
  290. // Public
  291. $roleId = 3;
  292. }
  293. return $roleId;
  294. }
  295. /**
  296. * Creates a special type of link for use in admin area.
  297. *
  298. * Clicking the link will automatically check a corresponding checkbox
  299. * where element id is equal to $url parameter and immediately submit the form
  300. * it's on. This works in tandem with Admin.processLink() in javascript.
  301. *
  302. * @deprecated Will be removed in the future. See CroogoHelper::adminRowAction()
  303. */
  304. public function processLink($title, $url = null, $options = array(), $confirmMessage = false) {
  305. if (!empty($confirmMessage)) {
  306. $options['data-confirm-message'] = $confirmMessage;
  307. }
  308. if (isset($options['icon'])) {
  309. $options['iconInline'] = true;
  310. }
  311. $output = $this->Html->link($title, $url, $options);
  312. return $output;
  313. }
  314. /**
  315. * Filter content
  316. *
  317. * Replaces bbcode-like element tags
  318. *
  319. * @param string $content content
  320. * @return string
  321. */
  322. public function filter($content, $options = array()) {
  323. Croogo::dispatchEvent('Helper.Layout.beforeFilter', $this->_View, array(
  324. 'content' => &$content,
  325. 'options' => $options,
  326. ));
  327. $content = $this->filterElements($content, $options);
  328. Croogo::dispatchEvent('Helper.Layout.afterFilter', $this->_View, array(
  329. 'content' => &$content,
  330. 'options' => $options,
  331. ));
  332. return $content;
  333. }
  334. /**
  335. * Filter content for elements
  336. *
  337. * Original post by Stefan Zollinger: http://bakery.cakephp.org/articles/view/element-helper
  338. * [element:element_name] or [e:element_name]
  339. *
  340. * @param string $content
  341. * @return string
  342. */
  343. public function filterElements($content, $options = array()) {
  344. preg_match_all('/\[(element|e):([A-Za-z0-9_\-\/]*)(.*?)\]/i', $content, $tagMatches);
  345. $validOptions = array('plugin', 'cache', 'callbacks');
  346. for ($i = 0, $ii = count($tagMatches[1]); $i < $ii; $i++) {
  347. $regex = '/([\w-]+)=[\'"]?((?:.(?![\'"]?\s+(?:\S+)=|[>\'"]))*.)[\'"]?/i';
  348. preg_match_all($regex, $tagMatches[3][$i], $attributes);
  349. $element = $tagMatches[2][$i];
  350. $data = $options = array();
  351. for ($j = 0, $jj = count($attributes[0]); $j < $jj; $j++) {
  352. if (in_array($attributes[1][$j], $validOptions)) {
  353. $options = Hash::merge($options, array($attributes[1][$j] => $attributes[2][$j]));
  354. } else {
  355. $data[$attributes[1][$j]] = $attributes[2][$j];
  356. }
  357. }
  358. if (!empty($this->_View->viewVars['block'])) {
  359. $data['block'] = $this->_View->viewVars['block'];
  360. }
  361. $content = str_replace($tagMatches[0][$i], $this->_View->element($element, $data, $options), $content);
  362. }
  363. return $content;
  364. }
  365. /**
  366. * Hook
  367. *
  368. * Used for calling hook methods from other HookHelpers
  369. *
  370. * @param string $methodName
  371. * @return string
  372. */
  373. public function hook($methodName) {
  374. $output = '';
  375. foreach ($this->_View->helpers as $helper => $settings) {
  376. if (!is_string($helper) || in_array($helper, $this->coreHelpers)) {
  377. continue;
  378. }
  379. list(, $helper) = pluginSplit($helper);
  380. if (isset($this->_View->{$helper}) && method_exists($this->_View->{$helper}, $methodName)) {
  381. $output .= $this->_View->{$helper}->$methodName();
  382. }
  383. }
  384. return $output;
  385. }
  386. /**
  387. * Gets a value of view variables based on path
  388. *
  389. * @param string $name Variable name to retrieve from View::viewVars
  390. * @param string $path Extraction path following the Hash path syntax
  391. * @return array
  392. */
  393. public function valueOf($name, $path, $options = array()) {
  394. if (!isset($this->_View->viewVars[$name])) {
  395. $this->log(sprintf('Invalid viewVars "%s"', $name));
  396. return array();
  397. }
  398. $result = Hash::extract($this->_View->viewVars[$name], $path);
  399. $result = isset($result[0]) ? $result[0] : $result;
  400. return $result;
  401. }
  402. /**
  403. * Compute default options for snippet()
  404. *
  405. * @param string $type Type
  406. * @return array Array of options
  407. */
  408. private function __snippetDefaults($type) {
  409. $varName = strtolower(Inflector::pluralize($type)) . '_for_layout';
  410. $modelAlias = Inflector::classify($type);
  411. $checkField = 'alias';
  412. $valueField = 'body';
  413. $filter = true;
  414. $format = '{s}.{n}.%s[%s=%s].%s';
  415. switch ($type) {
  416. case 'type':
  417. $valueField = 'description';
  418. $format = '{s}.%s[%s=%s].%s';
  419. break;
  420. case 'vocabulary':
  421. $valueField = 'title';
  422. $format = '{s}.%s[%s=%s].%s';
  423. break;
  424. case 'menu':
  425. $valueField = 'title';
  426. $format = '{s}.%s[%s=%s].%s';
  427. break;
  428. case 'node':
  429. $checkField = 'slug';
  430. break;
  431. }
  432. return compact('checkField', 'filter', 'format', 'modelAlias', 'valueField', 'varName');
  433. }
  434. /**
  435. * Simple method to retrieve value from view variables using Hash path format
  436. *
  437. * Example:
  438. *
  439. * // display the 'about' block
  440. * echo $this->Layout->snippet('about');
  441. * // display the 'hello world' node
  442. * echo $this->Layout->snippet('hello-world', 'node');
  443. *
  444. * You can customize the return value by supplying a custom path:
  445. * // display the 'main' menu array
  446. * echo $this->Layout->snippet('main', 'menu', array(
  447. * 'format' => '{s}.%s[%s=%s].%s',
  448. * ));
  449. * // display the 'main' menu description field
  450. * echo $this->Layout->snippet('main', 'menu', array(
  451. * 'valueField' => 'description',
  452. * 'format' => '{s}.%s[%s=%s].%s',
  453. * ));
  454. *
  455. * Options:
  456. * - checkField Field name that will be checked against $name
  457. * - filter Filter view data. Defaults to true
  458. * - format Hash path format
  459. * - modelAlias Model alias
  460. * - valueField Field name that will be returned if data is found
  461. * - varName Variable name as it is stored in viewVars
  462. *
  463. * @param string $name Identifier
  464. * @param string $type String of `block`, `nodes`, `node`
  465. * @param array $options Options array
  466. * @return string
  467. */
  468. public function snippet($name, $type = 'block', $options = array()) {
  469. $options = array_merge($this->__snippetDefaults($type), $options);
  470. extract($options);
  471. $path = sprintf($format, $modelAlias, $checkField, $name, $valueField);
  472. $result = $this->valueOf($options['varName'], $path);
  473. if ($result) {
  474. if ($options['filter'] === true && is_string($result)) {
  475. return $this->filter($result, $options);
  476. } else {
  477. return $result;
  478. }
  479. } else {
  480. return null;
  481. }
  482. }
  483. }