PageRenderTime 66ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/myth/Controllers/ThemedController.php

https://gitlab.com/digitalpoetry/xlt
PHP | 391 lines | 157 code | 63 blank | 171 comment | 23 complexity | fc7d17ccbbc13d9d62d7c8a09a2aab3f MD5 | raw file
  1. <?php namespace Myth\Controllers;
  2. /**
  3. * Sprint
  4. *
  5. * A set of power tools to enhance the CodeIgniter framework and provide consistent workflow.
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. * THE SOFTWARE.
  24. *
  25. * @package Sprint
  26. * @author Lonnie Ezell
  27. * @copyright Copyright 2014-2015, New Myth Media, LLC (http://newmythmedia.com)
  28. * @license http://opensource.org/licenses/MIT (MIT)
  29. * @link http://sprintphp.com
  30. * @since Version 1.0
  31. */
  32. use Myth\Themers\MetaCollection;
  33. use Zend\Escaper\Escaper;
  34. require_once dirname(__FILE__) .'/../Themers/escape.php';
  35. /**
  36. * Class ThemedController
  37. *
  38. * @package Myth\Controllers
  39. */
  40. class ThemedController extends BaseController
  41. {
  42. /**
  43. * Stores data variables to be sent to the view.
  44. * @var array
  45. */
  46. protected $vars = array();
  47. /**
  48. * Stores current status message.
  49. * @var
  50. */
  51. protected $message;
  52. /**
  53. * The UIKit to make available to the template views.
  54. * @var string
  55. */
  56. protected $uikit = '';
  57. /**
  58. * An instance of an active Themer to use.
  59. * @var null
  60. */
  61. protected $themer = null;
  62. /**
  63. * Allows per-controller override of theme.
  64. * @var null
  65. */
  66. protected $theme = null;
  67. /**
  68. * Per-controller override of the current layout file.
  69. * @var null
  70. */
  71. protected $layout = null;
  72. /**
  73. * Stores an array of javascript files.
  74. * @var array
  75. */
  76. protected $external_scripts = array();
  77. /**
  78. * Stores an array of CSS stylesheets.
  79. * @var array
  80. */
  81. protected $stylesheets = array();
  82. /**
  83. * A MenuCollection instance
  84. * @var
  85. */
  86. protected $meta;
  87. /**
  88. * Whether set() should escape the output...
  89. * @var bool
  90. */
  91. protected $auto_escape = null;
  92. /**
  93. * An instance of ZendFrameworks Escaper
  94. * @var null
  95. */
  96. protected $escaper = null;
  97. /**
  98. * Constructor takes care of getting the template engine up and running
  99. * and bound to our DI object, as well as any other preliminary needs,
  100. * like detecting the variant to use, etc.
  101. */
  102. public function __construct()
  103. {
  104. parent::__construct();
  105. // Setup our Template Engine
  106. $themer = config_item('active_themer');
  107. if (empty($themer)) {
  108. throw new \RuntimeException( lang('no_themer') );
  109. }
  110. $this->themer = new $themer( get_instance() );
  111. // Register our paths with the themer
  112. $paths = config_item('theme.paths');
  113. foreach ($paths as $key => $path) {
  114. $this->themer->addThemePath($key, $path);
  115. }
  116. // Set our default theme.
  117. $this->themer->setDefaultTheme( config_item('theme.default_theme') );
  118. // Register our variants with the engine.
  119. $variants = config_item('theme.variants');
  120. foreach ($variants as $key => $value) {
  121. $this->themer->addVariant($key, $value);
  122. }
  123. $this->detectVariant();
  124. // Ensure that our UIKit is loaded up if we're using one.
  125. $uikit = config_item('theme.uikit');
  126. if ($uikit)
  127. {
  128. $this->uikit = new $uikit();
  129. }
  130. // Load up our meta collection
  131. $this->meta = new MetaCollection( get_instance() );
  132. /**
  133. * Set Theme html classes
  134. *
  135. * @todo Find the correct place to put the below 2 lines.
  136. */
  137. $this->setVar('containerClass', 'container');
  138. $this->setVar('navbar_style', 'navbar-static-top');
  139. // Should we autoescape vars?
  140. if (is_null($this->auto_escape))
  141. {
  142. $this->auto_escape = config_item( 'theme.auto_escape' );
  143. }
  144. }
  145. /**
  146. * Provides a common interface with the other rendering methods to
  147. * set the output of the method. Uses the current instance of $this->template.
  148. * Ensures that any data we've stored through $this->setVar() are present
  149. * and includes the status messages into the data.
  150. *
  151. * @param array $data
  152. * @param int $cache_time
  153. */
  154. public function render($data = array(), $cache_time=0)
  155. {
  156. if ($cache_time > 0)
  157. {
  158. $this->output->cache( (int)$cache_time );
  159. }
  160. // Determine the correct theme to use
  161. $theme = ! empty($this->theme) ? $this->theme : config_item('theme.default_theme');
  162. $this->themer->setTheme($theme);
  163. // Determine the correct layout to use
  164. $layout = !empty($this->layout) ? $this->layout : null;
  165. $this->themer->setLayout($layout);
  166. // Merge any saved vars into the data
  167. // But first, escape the data if needed
  168. if ($this->auto_escape)
  169. {
  170. $data = esc($data, 'html');
  171. }
  172. $data = array_merge($data, $this->vars);
  173. // Make sure the MetaCollection is available in the view.
  174. $data['html_meta'] = $this->meta;
  175. // Include our UIKit so views can use it
  176. if (! empty($this->uikit)) {
  177. $data['uikit'] = $this->uikit;
  178. }
  179. // Build our notices from the theme's view file.
  180. $data['notice'] = $this->themer->display($this->themer->theme() . ':notice', ["notice" => $this->message()]);
  181. // Make sure any scripts/stylesheets are available to the view
  182. $data['external_scripts'] = $this->external_scripts;
  183. $data['stylesheets'] = $this->stylesheets;
  184. $this->themer->set($data);
  185. $this->output->set_content_type('html')
  186. ->set_output($this->themer->render());
  187. }
  188. /**
  189. * Sets a data variable to be sent to the view during the render() method.
  190. * Will auto-escape data on the way in, unless specifically told not to.
  191. *
  192. * Uses ZendFramework's Escaper to handle the data escaping,
  193. * based on context. Valid contexts are:
  194. * - html
  195. * - htmlAttr
  196. * - js
  197. * - css
  198. * - url
  199. *
  200. * @param string $name
  201. * @param mixed $value
  202. * @param string $context
  203. * @param bool $do_escape
  204. */
  205. public function setVar($name, $value = null, $context='html', $do_escape=null)
  206. {
  207. $escape = $do_escape == true ? true : $this->auto_escape;
  208. if (is_null($this->escaper))
  209. {
  210. $this->escaper = new Escaper(config_item('charset'));
  211. }
  212. if (is_array($name))
  213. {
  214. foreach ($name as $k => $v)
  215. {
  216. $this->vars[$k] = $escape ? esc($v, $context, $this->escaper) : $v;
  217. }
  218. }
  219. else
  220. {
  221. $this->vars[$name] = $escape ? esc($value, $context, $this->escaper) : $value;
  222. }
  223. }
  224. /*
  225. * Status Messages
  226. */
  227. /**
  228. * Sets a status message (for displaying small success/error messages).
  229. * This is used in place of the session->flashdata functions since you
  230. * don't always want to have to refresh the page to show the message.
  231. *
  232. * @param string $message The message to save.
  233. * @param string $type The string to be included as the CSS class of the containing div.
  234. */
  235. public function setMessage($message = '', $type = 'info')
  236. {
  237. if (! empty($message)) {
  238. if (isset($this->session)) {
  239. $this->session->set_flashdata('message', $type . '::' . $message);
  240. }
  241. $this->message = array(
  242. 'type' => $type,
  243. 'message' => $message
  244. );
  245. }
  246. }
  247. /**
  248. * Retrieves the status message to display (if any).
  249. *
  250. * @param string $message [description]
  251. * @param string $type [description]
  252. * @return array
  253. */
  254. public function message($message = '', $type = 'info')
  255. {
  256. $return = array(
  257. 'message' => $message,
  258. 'type' => $type
  259. );
  260. // Does session data exist?
  261. if (empty($message) && class_exists('CI_Session')) {
  262. $message = $this->session->flashdata('message');
  263. if (! empty($message)) {
  264. // Split out our message parts
  265. $temp_message = explode('::', $message);
  266. $return['type'] = $temp_message[0];
  267. $return['message'] = $temp_message[1];
  268. unset($temp_message);
  269. }
  270. }
  271. // If message is empty, we need to check our own storage.
  272. if (empty($message)) {
  273. if (empty($this->message['message'])) {
  274. return '';
  275. }
  276. $return = $this->message;
  277. }
  278. // Clear our session data so we don't get extra messages on rare occasions.
  279. if (class_exists('CI_Session')) {
  280. $this->session->set_flashdata('message', '');
  281. }
  282. return $return;
  283. }
  284. /*
  285. * Utility Methods
  286. */
  287. /**
  288. * Detects whether the item is being displayed on a desktop, phone,
  289. * or tablet device.
  290. */
  291. protected function detectVariant()
  292. {
  293. // Variant Detection and setup
  294. if (config_item('autodetect_variant') === true) {
  295. $detect = new \Mobile_Detect();
  296. if ($detect->isMobile()) {
  297. $this->template->setVariant('phone');
  298. } else if ($detect->isTablet()) {
  299. $this->template->setVariant('tablet');
  300. }
  301. }
  302. }
  303. /*
  304. * 'Asset' functions
  305. */
  306. /**
  307. * Adds an external javascript file to the 'external_scripts' array.
  308. *
  309. * @param [type] $filename [description]
  310. */
  311. public function addScript($filename)
  312. {
  313. if (strpos($filename, 'http') === FALSE) {
  314. $filename = base_url() . 'assets/js/' . $filename;
  315. }
  316. $this->external_scripts[] = $filename;
  317. }
  318. /**
  319. * Adds an external stylesheet file to the 'stylesheets' array.
  320. */
  321. public function addStyle($filename)
  322. {
  323. if (strpos($filename, 'http') === FALSE) {
  324. $filename = base_url() . 'assets/css/' . $filename;
  325. }
  326. $this->stylesheets[] = $filename;
  327. }
  328. }