PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/system/cms/libraries/Template.php

https://github.com/asalem/pyrocms
PHP | 1012 lines | 475 code | 172 blank | 365 comment | 66 complexity | 6beb1b192583eb544ff11a13b4969203 MD5 | raw file
Possible License(s): CC-BY-3.0, BSD-3-Clause, CC0-1.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, MIT
  1. <?php defined('BASEPATH') OR exit('No direct script access allowed');
  2. /**
  3. * CodeIgniter Template Class
  4. *
  5. * Build your CodeIgniter pages much easier with partials, breadcrumbs, layouts and themes
  6. *
  7. * @package CodeIgniter
  8. * @subpackage Libraries
  9. * @category Libraries
  10. * @author Philip Sturgeon
  11. * @license http://philsturgeon.co.uk/code/dbad-license
  12. * @link http://philsturgeon.co.uk/code/codeigniter-template
  13. */
  14. class Template
  15. {
  16. private $_module = '';
  17. private $_controller = '';
  18. private $_method = '';
  19. private $_theme = null;
  20. private $_theme_path = null;
  21. private $_layout = false; // By default, dont wrap the view with anything
  22. private $_layout_subdir = ''; // Layouts and partials will exist in views/layouts
  23. // but can be set to views/foo/layouts with a subdirectory
  24. private $_title = '';
  25. private $_metadata = array();
  26. private $_partials = array();
  27. private $_breadcrumbs = array();
  28. private $_title_separator = ' | ';
  29. private $_parser_enabled = true;
  30. private $_parser_body_enabled = true;
  31. private $_minify_enabled = false;
  32. private $_theme_locations = array();
  33. private $_is_mobile = false;
  34. private $_stream = array();
  35. // Seconds that cache will be alive for
  36. private $cache_lifetime = 0;//7200;
  37. private $_ci;
  38. private $_data = array();
  39. /**
  40. * Override Values
  41. *
  42. * These are values that will override existing
  43. * values in the template library (if they are)
  44. * set already.
  45. *
  46. * These values are added right before the template
  47. * build process, so they can be used any time up until
  48. * the site is rendered.
  49. */
  50. private $_override_title;
  51. private $_override_meta = array();
  52. private $_override_breadcrumbs = array();
  53. /**
  54. * Constructor - Sets Preferences
  55. *
  56. * The constructor can be passed an array of config values
  57. */
  58. public function __construct($config = array())
  59. {
  60. $this->_ci =& get_instance();
  61. if ( ! empty($config)) {
  62. $this->initialize($config);
  63. }
  64. log_message('debug', 'Template class Initialized');
  65. }
  66. // --------------------------------------------------------------------
  67. /**
  68. * Initialize preferences
  69. *
  70. * @param array $config
  71. * @return void
  72. */
  73. public function initialize($config = array())
  74. {
  75. foreach ($config as $key => $val) {
  76. if ($key == 'theme' and $val != '') {
  77. $this->set_theme($val);
  78. continue;
  79. }
  80. $this->{'_'.$key} = $val;
  81. }
  82. // No locations set in config?
  83. if ($this->_theme_locations === array()) {
  84. // Let's use this obvious default
  85. $this->_theme_locations = array(APPPATH . 'themes/');
  86. }
  87. // If the parse is going to be used, best make sure it's loaded
  88. if ($this->_parser_enabled === true) {
  89. $this->_ci->load->library('parser');
  90. }
  91. // Modular Separation / Modular Extensions has been detected
  92. if (method_exists( $this->_ci->router, 'fetch_module' )) {
  93. $this->_module = $this->_ci->router->fetch_module();
  94. }
  95. // What controllers or methods are in use
  96. $this->_controller = $this->_ci->router->fetch_class();
  97. $this->_method = $this->_ci->router->fetch_method();
  98. // Load user agent library if not loaded
  99. $this->_ci->load->library('user_agent');
  100. // We'll want to know this later
  101. $this->_is_mobile = $this->_ci->agent->is_mobile();
  102. }
  103. // --------------------------------------------------------------------
  104. /**
  105. * Set the module manually. Used when getting results from
  106. * another module with Modules::run('foo/bar')
  107. *
  108. * @param string $module The module slug
  109. * @return mixed
  110. */
  111. public function set_module($module)
  112. {
  113. $this->_module = $module;
  114. return $this;
  115. }
  116. // --------------------------------------------------------------------
  117. /**
  118. * Magic Get function to get data
  119. *
  120. * @param string $name
  121. * @return mixed
  122. */
  123. public function __get($name)
  124. {
  125. return isset($this->_data[$name]) ? $this->_data[$name] : null;
  126. }
  127. // --------------------------------------------------------------------
  128. /**
  129. * Magic Set function to set data
  130. *
  131. * @param string $name
  132. * @param mixed $value
  133. * @return mixed
  134. */
  135. public function __set($name, $value)
  136. {
  137. $this->_data[$name] = $value;
  138. }
  139. // --------------------------------------------------------------------
  140. /**
  141. * Set data using a chainable metod. Provide two strings or an array of data.
  142. *
  143. * @param string $name
  144. * @param mixed $value
  145. * @return object $this
  146. */
  147. public function set($name, $value = null)
  148. {
  149. // Lots of things! Set them all
  150. if (is_array($name) or is_object($name)) {
  151. foreach ($name as $item => $value) {
  152. $this->_data[$item] = $value;
  153. }
  154. }
  155. // Just one thing, set that
  156. else {
  157. $this->_data[$name] = $value;
  158. }
  159. return $this;
  160. }
  161. // --------------------------------------------------------------------
  162. /**
  163. * Build Template Data
  164. *
  165. * Gathers and builds a $template array
  166. * with basic template data.
  167. *
  168. * @return array
  169. */
  170. public function build_template_data()
  171. {
  172. // If we don't have a title, we'll take our best guess.
  173. // We are doing this before we check the override so
  174. // a user can set the title to blank if they want to.
  175. if (empty($this->_title)) {
  176. $this->_title = $this->_guess_title();
  177. }
  178. // Title override.
  179. $title = ($this->_override_title) ? $this->_override_title : $this->_title;
  180. $template['title'] = strip_tags($title);
  181. $template['page_title'] = $title;
  182. $template['breadcrumbs'] = array_merge($this->_breadcrumbs, $this->_override_breadcrumbs);
  183. $template['metadata'] = $this->get_metadata().Asset::render('extra').$this->get_metadata('late_header');
  184. $template['partials'] = array();
  185. // Load this into our cached vars so plugins
  186. // can use it.
  187. $this->_ci->load->vars(array('template' => $template));
  188. return $template;
  189. }
  190. // --------------------------------------------------------------------
  191. /**
  192. * Build the entire HTML output combining partials, layouts and views.
  193. *
  194. * @param string $view
  195. * @param array $data
  196. * @param bool $return
  197. * @param bool $IE_cache
  198. * @param bool $pre_parsed_view Did we already parse our view?
  199. * @return string
  200. */
  201. public function build($view, $data = array(), $return = false, $IE_cache = true, $pre_parsed_view = false, $template = array())
  202. {
  203. // Set whatever values are given. These will be available to all view files
  204. is_array($data) OR $data = (array) $data;
  205. // Merge in what we already have set
  206. $this->_data = array_merge($this->_data, $data);
  207. // We don't need you any more buddy
  208. unset($data);
  209. // If you want, you can use the build_template_data()
  210. // to pre-build this template data. This is an edge case so you'll
  211. // probably always just leave it to array(), but it's here if
  212. // you need it.
  213. if ( ! $template) {
  214. $template = $this->build_template_data();
  215. }
  216. $this->_data['template'] =& $template;
  217. // Process partials.
  218. foreach ($this->_partials as $name => $partial) {
  219. // We can only work with data arrays
  220. is_array($partial['data']) or $partial['data'] = (array) $partial['data'];
  221. // If it uses a view, load it
  222. if (isset($partial['view'])) {
  223. $template['partials'][$name] = $this->_find_view($partial['view'], $partial['data']);
  224. }
  225. // Otherwise the partial must be a string
  226. else {
  227. if ($this->_parser_enabled === true) {
  228. $partial['string'] = $this->_ci->parser->parse_string($partial['string'], $this->_data + $partial['data'], true, true);
  229. }
  230. $template['partials'][$name] = $partial['string'];
  231. }
  232. }
  233. // Disable sodding IE7's constant cacheing!!
  234. // This is in a conditional because otherwise it errors when output is returned instead of output to browser.
  235. if ($IE_cache) {
  236. $this->_ci->output->set_header('Expires: Sat, 01 Jan 2000 00:00:01 GMT');
  237. $this->_ci->output->set_header('Cache-Control: no-store, no-cache, must-revalidate');
  238. $this->_ci->output->set_header('Cache-Control: post-check=0, pre-check=0, max-age=0');
  239. $this->_ci->output->set_header('Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
  240. $this->_ci->output->set_header('Pragma: no-cache');
  241. }
  242. // Let CI do the caching instead of the browser
  243. $this->cache_lifetime > 0 && $this->_ci->output->cache($this->cache_lifetime);
  244. // Set the _body var. If we have pre-parsed our
  245. // view, then our work is done. Otherwise, we will
  246. // find the view and parse it.
  247. if ($pre_parsed_view) {
  248. $this->_body = $view;
  249. } else {
  250. $this->_body = $this->_find_view($view, array(), $this->_parser_body_enabled);
  251. }
  252. // Want this file wrapped with a layout file?
  253. if ($this->_layout) {
  254. // Added to $this->_data['template'] by refference
  255. $template['body'] = $this->_body;
  256. if ($this->_parser_enabled) {
  257. // Persistent tags is an experiment to parse some tags after
  258. // parsing of all other tags, so the tag persistent should be:
  259. //
  260. // a) Defined only if depends of others tags
  261. // b) Plugin that is a callback, so could retrieve runtime data.
  262. // c) Returned with a content parsed
  263. $this->_data['_tags']['persistent_tags'][] = 'template:metadata';
  264. }
  265. // Find the main body and 3rd param means parse if its a theme view (only if parser is enabled)
  266. $this->_body = self::_load_view('layouts/'.$this->_layout, $this->_data, true, self::_find_view_folder());
  267. }
  268. if ($this->_minify_enabled && function_exists('process_data_jmr1')) {
  269. $this->_body = process_data_jmr1($this->_body);
  270. }
  271. // Now that *all* parsing is sure to be done we inject the {{ noparse }} contents back into the output
  272. if (class_exists('Lex\Parser')) {
  273. $this->_body = Lex\Parser::injectNoparse($this->_body);
  274. }
  275. // Want it returned or output to browser?
  276. if ( ! $return) {
  277. // Run the profiler if user is admin and _debug is in the query string
  278. if (ci()->current_user and ci()->current_user->isSuperUser() and is_array($_GET) and array_key_exists('_debug', $_GET)) {
  279. unset($_GET['_debug']);
  280. // Get the Illuminate query log
  281. $query_log = ci()->pdb->getQueryLog();
  282. // Log all queries using the profiler
  283. foreach ($query_log as $query) {
  284. // Insert bindings into query
  285. $query['query'] = str_replace(array('%', '?'), array('%%', '%s'), $query['query']);
  286. $query['query'] = vsprintf($query['query'], $query['bindings']);
  287. ci()->profiler->log->query($query['query'], $query['time']);
  288. }
  289. // Append the profiler to the body
  290. $this->_body .= ci()->profiler;
  291. }
  292. $this->_ci->output->set_output($this->_body);
  293. }
  294. $this->_stream = array();
  295. return $this->_body;
  296. }
  297. /**
  298. * Build the entire JSON output, setting the headers for response.
  299. *
  300. * @param array $data
  301. * @return void
  302. */
  303. public function build_json($data = array())
  304. {
  305. $this->_ci->output->set_header('Content-Type: application/json; charset=utf-8');
  306. $this->_ci->output->set_output(json_encode((object) $data));
  307. }
  308. /**
  309. * Set the title of the page
  310. *
  311. * @return object $this
  312. */
  313. public function title()
  314. {
  315. // If we have some segments passed
  316. if ($title_segments = func_get_args()) {
  317. $this->_title = implode($this->_title_separator, $title_segments);
  318. }
  319. return $this;
  320. }
  321. public function override_title()
  322. {
  323. // If we have some segments passed
  324. if ($title_segments = func_get_args()) {
  325. $this->_override_title = implode($this->_title_separator, $title_segments);
  326. }
  327. }
  328. /**
  329. * Put extra javascipt, css, meta tags, etc before all other head data
  330. *
  331. * @param string $line The line being added to head
  332. * @return object $this
  333. */
  334. public function prepend_metadata($line, $place = 'header')
  335. {
  336. // we need to declare all new key's in _metadata as an
  337. // array for the unshift function to work
  338. if ( ! isset($this->_metadata[$place])) {
  339. $this->_metadata[$place] = array();
  340. }
  341. array_unshift($this->_metadata[$place], $line);
  342. return $this;
  343. }
  344. /**
  345. * Put extra javascipt, css, meta tags, etc after other head data
  346. *
  347. * @param string $line The line being added to head
  348. * @return object $this
  349. */
  350. public function append_metadata($line, $place = 'header')
  351. {
  352. $this->_metadata[$place][] = $line;
  353. return $this;
  354. }
  355. /**
  356. * Put extra javascipt, css, meta tags, etc after other head data
  357. *
  358. * @param string $line The line being added to head
  359. * @return object $this
  360. */
  361. public function append_css($files, $min_file = null, $group = 'extra')
  362. {
  363. Asset::css($files, $min_file, $group);
  364. return $this;
  365. }
  366. public function append_js($files, $min_file = null, $group = 'extra')
  367. {
  368. Asset::js($files, $min_file, $group);
  369. return $this;
  370. }
  371. /**
  372. * Set Stream
  373. *
  374. * This function allows you to identify
  375. * a variable loop in your view that needs
  376. * to be parsed by the special streams parser.
  377. *
  378. * This simply sets the stream loop data, the actual
  379. * parsing is done in the build function.
  380. *
  381. * @param string $stream_slug The name of the stream
  382. * @param string $stream_namespace The stream namespace
  383. * @param string [$id_name] Override for the id name (see build function for more info)
  384. * @return void
  385. */
  386. public function set_stream($stream_slug, $stream_namespace, $id_name = null)
  387. {
  388. $this->_stream = array('stream' => $stream_slug,
  389. 'namespace' => $stream_namespace, 'id_name' => $id_name);
  390. return $this;
  391. }
  392. /**
  393. * Set metadata for output later
  394. *
  395. * @param string $name keywords, description, etc
  396. * @param string $content The content of meta data
  397. * @param string $type Meta-data comes in a few types, links for example
  398. * @param string [$place] Defaults to 'header'
  399. * @param bool [$override] Should we save this to the meta overrides instead of the
  400. * main meta array?
  401. * @return object $this
  402. */
  403. public function set_metadata($name, $content, $type = 'meta', $place = 'header', $override = false)
  404. {
  405. $name = htmlspecialchars(strip_tags($name));
  406. $content = trim(htmlspecialchars(strip_tags($content)));
  407. // Keywords with no comments? ARG! comment them
  408. if ($name == 'keywords' and ! strpos($content, ',')) {
  409. $content = preg_replace('/[\s]+/', ', ', trim($content));
  410. }
  411. switch($type) {
  412. case 'meta':
  413. $meta = '<meta name="'.$name.'" content="'.$content.'" />';
  414. if ($override) {
  415. $this->_override_meta[$place][$name] = $meta;
  416. } else {
  417. $this->_metadata[$place][$name] = $meta;
  418. }
  419. break;
  420. case 'link':
  421. $link = '<link rel="'.$name.'" href="'.$content.'" />';
  422. if ($override) {
  423. $this->_override_meta[$place][$content] = $link;
  424. } else {
  425. $this->_metadata[$place][$content] = $link;
  426. }
  427. break;
  428. case 'og':
  429. $meta = '<meta property="'.$name.'" content="'.$content.'" />';
  430. if ($override) {
  431. $this->_override_meta[$place][md5($name.$content)] = $meta;
  432. } else {
  433. $this->_metadata[$place][md5($name.$content)] = $meta;
  434. }
  435. break;
  436. }
  437. return $this;
  438. }
  439. /**
  440. * Which theme are we using here?
  441. *
  442. * @param string $theme Set a theme for the template library to use
  443. * @return object $this
  444. */
  445. public function set_theme($theme = null)
  446. {
  447. $this->_theme = $theme;
  448. foreach ($this->_theme_locations as $location) {
  449. if ($this->_theme and file_exists($location.$this->_theme)) {
  450. $this->_theme_path = rtrim($location.$this->_theme.'/');
  451. break;
  452. }
  453. }
  454. return $this;
  455. }
  456. /**
  457. * Get the current theme path
  458. *
  459. * @return string The current theme path
  460. */
  461. public function get_theme_path()
  462. {
  463. return $this->_theme_path;
  464. }
  465. /**
  466. * Get the current view path
  467. *
  468. * @param bool Set if should be returned the view path full (with theme path) or the view relative the theme path
  469. * @return string The current view path
  470. */
  471. public function get_views_path($relative = false)
  472. {
  473. return $relative ? substr($this->_find_view_folder(), strlen($this->get_theme_path())) : $this->_find_view_folder();
  474. }
  475. /**
  476. * Which theme layout should we using here?
  477. *
  478. * @param string $view
  479. * @param string $layout_subdir
  480. * @return object $this
  481. */
  482. public function set_layout($view, $layout_subdir = null)
  483. {
  484. $this->_layout = $view;
  485. if ($layout_subdir !== null) {
  486. $this->_layout_subdir = $layout_subdir;
  487. }
  488. return $this;
  489. }
  490. /**
  491. * Set a view partial
  492. *
  493. * @param string $name
  494. * @param string $view
  495. * @param array $data
  496. * @return object $this
  497. */
  498. public function set_partial($name, $view, $data = array())
  499. {
  500. $this->_partials[$name] = array('view' => $view, 'data' => $data);
  501. return $this;
  502. }
  503. /**
  504. * Set a view partial
  505. *
  506. * @param string $name
  507. * @param string $string
  508. * @param array $data
  509. * @return object $this
  510. */
  511. public function inject_partial($name, $string, $data = array())
  512. {
  513. $this->_partials[$name] = array('string' => $string, 'data' => $data);
  514. return $this;
  515. }
  516. /**
  517. * Helps build custom breadcrumb trails
  518. *
  519. * @param string $name What will appear as the link text
  520. * @param string $uri The URL segment
  521. * @return object $this
  522. */
  523. public function set_breadcrumb($name, $uri = '', $reset = false, $override = false)
  524. {
  525. // perhaps they want to start over
  526. if ($reset) {
  527. $this->_breadcrumbs = array();
  528. if ($override) {
  529. $this->_override_breadcrumbs = array();
  530. }
  531. }
  532. if ($override) {
  533. $this->_override_breadcrumbs[] = array('name' => $name, 'uri' => $uri);
  534. } else {
  535. $this->_breadcrumbs[] = array('name' => $name, 'uri' => $uri);
  536. }
  537. return $this;
  538. }
  539. /**
  540. * Set a the cache lifetime
  541. *
  542. * @param int $seconds
  543. * @return object $this
  544. */
  545. public function set_cache($seconds = 0)
  546. {
  547. $this->cache_lifetime = $seconds;
  548. return $this;
  549. }
  550. /**
  551. * enable_minify
  552. * Should be minify used or the output html files just delivered normally?
  553. *
  554. * @param bool $bool
  555. * @return object $this
  556. */
  557. public function enable_minify($bool)
  558. {
  559. $this->_minify_enabled = $bool;
  560. return $this;
  561. }
  562. /**
  563. * enable_parser
  564. * Should be parser be used or the view files just loaded normally?
  565. *
  566. * @param bool $bool
  567. * @return object $this
  568. */
  569. public function enable_parser($bool)
  570. {
  571. $this->_parser_enabled = $bool;
  572. return $this;
  573. }
  574. /**
  575. * enable_parser_body
  576. * Should be parser be used or the body view files just loaded normally?
  577. *
  578. * @param bool $bool
  579. * @return object $this
  580. */
  581. public function enable_parser_body($bool)
  582. {
  583. $this->_parser_body_enabled = $bool;
  584. return $this;
  585. }
  586. /**
  587. * theme_locations
  588. * List the locations where themes may be stored
  589. *
  590. * @return array
  591. */
  592. public function theme_locations()
  593. {
  594. return $this->_theme_locations;
  595. }
  596. /**
  597. * add_theme_location
  598. * Set another location for themes to be looked in
  599. *
  600. * @access public
  601. * @param string $location
  602. * @return array
  603. */
  604. public function add_theme_location($location)
  605. {
  606. $this->_theme_locations[] = $location;
  607. }
  608. /**
  609. * theme_exists
  610. * Check if a theme exists
  611. *
  612. * @param string $theme
  613. * @return bool
  614. */
  615. public function theme_exists($theme = null)
  616. {
  617. $theme OR $theme = $this->_theme;
  618. foreach ($this->_theme_locations as $location) {
  619. if (is_dir($location.$theme)) {
  620. return true;
  621. }
  622. }
  623. return false;
  624. }
  625. /**
  626. * get_layouts
  627. * Get all current layouts (if using a theme you'll get a list of theme layouts)
  628. *
  629. * @return array
  630. */
  631. public function get_layouts()
  632. {
  633. $layouts = array();
  634. foreach(glob(self::_find_view_folder().'layouts/*.*') as $layout) {
  635. $layouts[] = pathinfo($layout, PATHINFO_BASENAME);
  636. }
  637. return $layouts;
  638. }
  639. /**
  640. * Get Metadata
  641. *
  642. * @param string $place
  643. * @return string
  644. */
  645. public function get_metadata($place = 'header')
  646. {
  647. // We are going to set this to a blank array if this
  648. // does not exist in the right format, since we are going to
  649. // see if any overrides are in place that we can use as well.
  650. if ( ! isset($this->_metadata[$place]) or ! is_array($this->_metadata[$place])) {
  651. $this->_metadata[$place] = array();
  652. }
  653. // Go through any 'header' place overrides
  654. if (isset($this->_override_meta[$place])) {
  655. foreach ($this->_override_meta[$place] as $key => $meta) {
  656. // If this already exists, unset it.
  657. if (isset($this->_metadata[$place][$key])) {
  658. unset($this->_metadata[$place][$key]);
  659. }
  660. $this->_metadata[$place][$key] = $this->_override_meta[$place][$key];
  661. }
  662. }
  663. // Still nothing? Now we can return null.
  664. if ( ! $this->_metadata[$place]) {
  665. return null;
  666. }
  667. return implode("\n\t\t", $this->_metadata[$place]);
  668. }
  669. /**
  670. * get_layouts
  671. * Get all current layouts (if using a theme you'll get a list of theme layouts)
  672. *
  673. * @param string $theme
  674. * @return array
  675. */
  676. public function get_theme_layouts($theme = null)
  677. {
  678. $theme OR $theme = $this->_theme;
  679. $layouts = array();
  680. foreach ($this->_theme_locations as $location) {
  681. // Get special web layouts
  682. if( is_dir($location.$theme.'/views/web/layouts/') ) {
  683. foreach(glob($location.$theme . '/views/web/layouts/*.*') as $layout) {
  684. $layouts[] = pathinfo($layout, PATHINFO_BASENAME);
  685. }
  686. break;
  687. }
  688. // So there are no web layouts, assume all layouts are web layouts
  689. if(is_dir($location.$theme.'/views/layouts/')) {
  690. foreach(glob($location.$theme . '/views/layouts/*.*') as $layout) {
  691. $layouts[] = pathinfo($layout, PATHINFO_BASENAME);
  692. }
  693. break;
  694. }
  695. }
  696. return $layouts;
  697. }
  698. /**
  699. * layout_exists
  700. * Check if a theme layout exists
  701. *
  702. * @param string $layout
  703. * @return bool
  704. */
  705. public function layout_exists($layout)
  706. {
  707. // If there is a theme, check it exists in there
  708. if ( ! empty($this->_theme) and in_array($layout, self::get_theme_layouts())) {
  709. return true;
  710. }
  711. // Otherwise look in the normal places
  712. return file_exists(self::_find_view_folder().'layouts/' . $layout . self::_ext($layout));
  713. }
  714. /**
  715. * layout_is
  716. * Check if the current theme layout is equal the $layout argument
  717. *
  718. * @param string $layout
  719. * @return bool
  720. */
  721. public function layout_is($layout)
  722. {
  723. return $layout === $this->_layout;
  724. }
  725. // find layout files, they could be mobile or web
  726. private function _find_view_folder()
  727. {
  728. if (isset($this->_ci->load->_ci_cached_vars['template_views'])) {
  729. return $this->_ci->load->_ci_cached_vars['template_views'];
  730. }
  731. // Base view folder
  732. $view_folder = APPPATH.'views/';
  733. // Using a theme? Put the theme path in before the view folder
  734. if ( ! empty($this->_theme)) {
  735. $view_folder = $this->_theme_path.'views/';
  736. }
  737. // Would they like the mobile version?
  738. if ($this->_is_mobile === true and is_dir($view_folder.'mobile/')) {
  739. // Use mobile as the base location for views
  740. $view_folder .= 'mobile/';
  741. }
  742. // Use the web version
  743. else if (is_dir($view_folder.'web/')) {
  744. $view_folder .= 'web/';
  745. }
  746. // Things like views/admin/web/view admin = subdir
  747. if ($this->_layout_subdir) {
  748. $view_folder .= $this->_layout_subdir.'/';
  749. }
  750. // If using themes store this for later, available to all views
  751. return $this->_ci->load->_ci_cached_vars['template_views'] = $view_folder;
  752. }
  753. /**
  754. * Wrapper function for _find_view()
  755. * so we can manually get a theme view
  756. * that can be overriden.
  757. */
  758. public function load_view($view, array $data, $parse_view = true)
  759. {
  760. return $this->_find_view($view, $data, $parse_view);
  761. }
  762. // A module view file can be overriden in a theme
  763. private function _find_view($view, array $data, $parse_view = true)
  764. {
  765. // Only bother looking in themes if there is a theme
  766. if ( ! empty($this->_theme)) {
  767. $location = $this->get_theme_path();
  768. $theme_views = array(
  769. $this->get_views_path(true) . 'modules/' . $this->_module . '/' . $view,
  770. // This allows build('pages/page') to still overload same as build('page')
  771. $this->get_views_path(true) . 'modules/' . $view,
  772. $this->get_views_path(true) . $view
  773. );
  774. foreach ($theme_views as $theme_view) {
  775. if (file_exists($location . $theme_view . self::_ext($theme_view))) {
  776. return self::_load_view($theme_view, $this->_data + $data, $parse_view, $location);
  777. }
  778. }
  779. }
  780. // Not found it yet? Just load, its either in the module or root view
  781. return self::_load_view($view, $data + $this->_data, $parse_view);
  782. }
  783. private function _load_view($view, array $data, $parse_view = true, $override_view_path = null)
  784. {
  785. // Severe hackery to load views from custom places AND maintain compatibility with Modular Extensions
  786. if ($override_view_path !== null) {
  787. if ($this->_parser_enabled === true and $parse_view === true) {
  788. // Load content and pass through the parser
  789. $content = $this->_ci->parser->parse_string($this->_ci->load->_ci_load(array(
  790. '_ci_path' => $override_view_path.$view.self::_ext($view),
  791. '_ci_vars' => $data,
  792. '_ci_return' => true
  793. )), $data, true, false, $this->_stream);
  794. } else {
  795. // Load it directly, bypassing $this->load->view() as ME resets _ci_view
  796. $content = $this->_ci->load->_ci_load(array(
  797. '_ci_path' => $override_view_path.$view.self::_ext($view),
  798. '_ci_vars' => $data,
  799. '_ci_return' => true
  800. ));
  801. }
  802. }
  803. // Can just run as usual
  804. else {
  805. // Grab the content of the view (parsed or loaded)
  806. $content = ($this->_parser_enabled === true AND $parse_view === true)
  807. // Parse that bad boy
  808. ? $this->_ci->parser->parse($view, $data, true, false, $this->_stream)
  809. // None of that fancy stuff for me!
  810. : $this->_ci->load->view($view, $data, true);
  811. }
  812. return $content;
  813. }
  814. private function _guess_title()
  815. {
  816. $this->_ci->load->helper('inflector');
  817. // Obviously no title, lets get making one
  818. $title_parts = array();
  819. // If the method is something other than index, use that
  820. if ($this->_method != 'index') {
  821. $title_parts[] = $this->_method;
  822. }
  823. // Make sure controller name is not the same as the method name
  824. if ( ! in_array($this->_controller, $title_parts)) {
  825. $title_parts[] = $this->_controller;
  826. }
  827. // Is there a module? Make sure it is not named the same as the method or controller
  828. if ( ! empty($this->_module) and !in_array($this->_module, $title_parts)) {
  829. $title_parts[] = $this->_module;
  830. }
  831. // Glue the title pieces together using the title separator setting
  832. $title = humanize(implode($this->_title_separator, $title_parts));
  833. return $title;
  834. }
  835. private function _ext($file)
  836. {
  837. return pathinfo($file, PATHINFO_EXTENSION) ? '' : '.php';
  838. }
  839. }
  840. // END Template class