PageRenderTime 55ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/Croogo/View/Helper/LayoutHelper.php

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