Created
September 28, 2012 23:56
-
-
Save og-shawn-crigger/3802666 to your computer and use it in GitHub Desktop.
Lex Parser for Bonfire
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* The Lex Autoloader (this is case-sensative) | |
*/ | |
class Lex_Autoloader | |
{ | |
protected static $load_path = './'; | |
/** | |
* Registers the Autoloader | |
* | |
* @return void | |
*/ | |
public static function register() | |
{ | |
self::$load_path = dirname(dirname(__FILE__)).'/'; | |
ini_set('unserialize_callback_func', 'spl_autoload_call'); | |
spl_autoload_register('Lex_Autoloader::load'); | |
} | |
/** | |
* Autoloads the Lex classes, if it is not a Lex class it simply | |
* returns. | |
* | |
* @param string $class class name | |
* @return bool | |
*/ | |
static public function load($class) | |
{ | |
if (strpos($class, 'Lex') !== 0) | |
{ | |
return false; | |
} | |
$file = self::$load_path.str_replace(array('_', "\0"), array('/', ''), $class).'.php'; | |
$file = str_replace('/', DIRECTORY_SEPARATOR, $file); | |
if (is_file($file)) | |
{ | |
require $file; | |
return true; | |
} | |
return false; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php defined('BASEPATH') OR exit('No direct script access allowed'); | |
/** | |
* CodeIgniter Dwoo Parser Class | |
* | |
* @package Bonfire\Core\Libraries | |
* @category Parser | |
* @author Avinash Kundaliya | |
* @link http://cibonfire.com | |
*/ | |
class MY_Parser extends CI_Parser | |
{ | |
/** | |
* An instance of the CI super object. | |
* | |
* @access private | |
* | |
* @var object | |
*/ | |
private $ci; | |
// ------------------------------------------------------------------------ | |
/** | |
* Load dependacies and sets CI major object. | |
* | |
* @return void | |
*/ | |
function __construct() | |
{ | |
//include the lex parser class | |
if ( ! class_exists('Lex_Autoloader')) | |
{ | |
include APPPATH.'/libraries/Lex/Autoloader.php'; | |
} | |
$this->ci =& get_instance(); | |
} | |
// ------------------------------------------------------------------------ | |
/** | |
* Parses Template or String and does the Mojo! | |
* | |
* @param string $template View File or String to Parse | |
* @param array $data Array of Data to be Parsed | |
* @param boolean $return | |
* @param boolean $load_view | |
* @return mixed | |
*/ | |
public function parse($template = '', $data = array(), $return = FALSE, $load_view = TRUE) | |
{ | |
// Ready Set Go! | |
$this->ci->benchmark->mark('parse_start'); | |
// Convert from object to array | |
is_array($data) or $data = (array) $data; | |
$data = array_merge($data, $this->ci->load->_ci_cached_vars); | |
//if load_view is false, we parse the string | |
$parseString = $template; | |
//else load the view to parse | |
if($load_view) | |
{ | |
$parseString = $this->ci->load->view($template, $data, TRUE); | |
} | |
Lex_Autoloader::register(); | |
$parser = new Lex_Parser(); | |
$parser->scope_glue(':'); | |
$parsed = $parser->parse($parseString, $data, array($this, 'parser_callback')); | |
// Time's Up! | |
$this->ci->benchmark->mark('parse_end'); | |
if ( ! $return) | |
{ | |
$this->ci->output->append_output($parsed); | |
return; | |
} | |
return $parsed; | |
} | |
// ------------------------------------------------------------------------ | |
/** | |
* Parser Callback | |
* | |
* @param string $module | |
* @param string $attribute | |
* @param string $content | |
* | |
* @return mixed | |
*/ | |
public function parser_callback($module, $attribute, $content) | |
{ | |
$return_view = NULL; | |
$parsed_return = ''; | |
$output = self::get_view($module,$attribute); | |
$return_view = $output; | |
//loop it up, if its array no use in the template, gotta work it here. | |
if(is_array($output)) | |
{ | |
// Need to make sure we have a array and no objects inside the array too. | |
$parser = new Lex_Parser(); | |
$parser->scope_glue(':'); | |
foreach($output as $result) | |
{ | |
$parsed_return .= $parser->parse($content, $result, array($this, 'parser_callback')); | |
} | |
unset($parser); | |
$return_view = $parsed_return; | |
} | |
return $return_view; | |
} | |
// ------------------------------------------------------------------------ | |
/** | |
* Runs module or library callback methods. | |
* | |
* @access private | |
* | |
* @param string $module Module Class Name | |
* @param array $attribute Attributes to run Method with | |
* @param string $method Method to call. | |
* | |
* @return mixed | |
*/ | |
private function get_view($module = '', $attribute = array(), $method = 'index') | |
{ | |
$return_view = false; | |
// Get the required module | |
$module = str_replace(':','/',$module); | |
if(($pos = strrpos($module, '/')) != FALSE) | |
{ | |
$method = substr($module, $pos + 1); | |
$module = substr($module, 0, $pos); | |
} | |
if($class = $this->ci->load->module($module)) | |
{ | |
//if the method is callable | |
if (method_exists($class, $method)) | |
{ | |
ob_start(); | |
$output = call_user_func_array(array($class, $method), $attribute); | |
$buffer = ob_get_clean(); | |
$output = ($output !== NULL) ? $output : $buffer; | |
$return_view = $output; | |
} | |
} | |
//maybe it is a library | |
else if(!$return_view && strpos($module,'/') === FALSE) | |
{ | |
if(class_exists($module)) | |
{ | |
ob_start(); | |
$output = call_user_func_array(array($module, $method), $attribute); | |
$buffer = ob_get_clean(); | |
$output = ($output !== NULL) ? $output : $buffer; | |
$return_view = $output; | |
} | |
} | |
return $return_view; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Part of the Lex Template Parser. | |
* | |
* @author Dan Horrigan | |
* @license MIT License | |
* @copyright 2011 Dan Horrigan | |
*/ | |
class LexParsingException extends Exception { } | |
class Lex_Parser | |
{ | |
protected $allow_php = false; | |
protected $regex_setup = false; | |
protected $scope_glue = '.'; | |
protected $tag_regex = ''; | |
protected $cumulative_noparse = false; | |
protected $in_condition = false; | |
protected $variable_regex = ''; | |
protected $variable_loop_regex = ''; | |
protected $variable_tag_regex = ''; | |
protected $callback_tag_regex = ''; | |
protected $callback_loop_tag_regex = ''; | |
protected $noparse_regex = ''; | |
protected $conditional_regex = ''; | |
protected $conditional_else_regex = ''; | |
protected $conditional_end_regex = ''; | |
protected $conditional_data = array(); | |
protected static $extractions = array( | |
'noparse' => array(), | |
); | |
protected static $data = null; | |
protected static $callback_data = array(); | |
/** | |
* The main Lex parser method. Essentially acts as dispatcher to | |
* all of the helper parser methods. | |
* | |
* @param string $text Text to parse | |
* @param array|object $data Array or object to use | |
* @param mixed $callback Callback to use for Callback Tags | |
* @return string | |
*/ | |
public function parse($text, $data = array(), $callback = false, $allow_php = false) | |
{ | |
$this->setup_regex(); | |
$this->allow_php = $allow_php; | |
// Is this the first time parse() is called? | |
if (Lex_Parser::$data === null) | |
{ | |
// Let's store the local data array for later use. | |
Lex_Parser::$data = $data; | |
} | |
else | |
{ | |
// Let's merge the current data array with the local scope variables | |
// So you can call local variables from within blocks. | |
$data = array_merge(Lex_Parser::$data, $data); | |
// Since this is not the first time parse() is called, it's most definately a callback, | |
// let's store the current callback data with the the local data | |
// so we can use it straight after a callback is called. | |
Lex_Parser::$callback_data = $data; | |
} | |
// The parse_conditionals method executes any PHP in the text, so clean it up. | |
if ( ! $allow_php) | |
{ | |
$text = str_replace(array('<?', '?>'), array('<?', '?>'), $text); | |
} | |
$text = $this->parse_comments($text); | |
$text = $this->extract_noparse($text); | |
$text = $this->extract_looped_tags($text, $data, $callback); | |
// Order is important here. We parse conditionals first as to avoid | |
// unnecessary code from being parsed and executed. | |
$text = $this->parse_conditionals($text, $data, $callback); | |
$text = $this->inject_extractions($text, 'looped_tags'); | |
$text = $this->parse_variables($text, $data, $callback); | |
$text = $this->inject_extractions($text, 'callback_blocks'); | |
if ($callback) | |
{ | |
$text = $this->parse_callback_tags($text, $data, $callback); | |
} | |
// To ensure that {{ noparse }} is never parsed even during consecutive parse calls | |
// set $cumulative_noparse to true and use Lex_Parser::inject_noparse($text); immediately | |
// before the final output is sent to the browser | |
if ( ! $this->cumulative_noparse) | |
{ | |
$text = $this->inject_extractions($text); | |
} | |
return $text; | |
} | |
/** | |
* Removes all of the comments from the text. | |
* | |
* @param string $text Text to remove comments from | |
* @return string | |
*/ | |
public function parse_comments($text) | |
{ | |
$this->setup_regex(); | |
return preg_replace('/\{\{#.*?#\}\}/s', '', $text); | |
} | |
/** | |
* Recursivly parses all of the variables in the given text and | |
* returns the parsed text. | |
* | |
* @param string $text Text to parse | |
* @param array|object $data Array or object to use | |
* @return string | |
*/ | |
public function parse_variables($text, $data, $callback = null) | |
{ | |
$this->setup_regex(); | |
/** | |
* $data_matches[][0][0] is the raw data loop tag | |
* $data_matches[][0][1] is the offset of raw data loop tag | |
* $data_matches[][1][0] is the data variable (dot notated) | |
* $data_matches[][1][1] is the offset of data variable | |
* $data_matches[][2][0] is the content to be looped over | |
* $data_matches[][2][1] is the offset of content to be looped over | |
*/ | |
if (preg_match_all($this->variable_loop_regex, $text, $data_matches, PREG_SET_ORDER + PREG_OFFSET_CAPTURE)) | |
{ | |
foreach ($data_matches as $index => $match) | |
{ | |
if ($loop_data = $this->get_variable($match[1][0], $data)) | |
{ | |
$looped_text = ''; | |
foreach ($loop_data as $item_data) | |
{ | |
$str = $this->parse_conditionals($match[2][0], $item_data, $callback); | |
$str = $this->parse_variables($str, $item_data, $callback); | |
if ($callback !== null) | |
{ | |
$str = $this->parse_callback_tags($str, $item_data, $callback); | |
} | |
$looped_text .= $str; | |
} | |
$text = preg_replace('/'.preg_quote($match[0][0], '/').'/m', addcslashes($looped_text, '\\$'), $text, 1); | |
} | |
else // It's a callback block. | |
{ | |
// Let's extract it so it doesn't conflict | |
// with the local scope variables in the next step. | |
$text = $this->create_extraction('callback_blocks', $match[0][0], $match[0][0], $text); | |
} | |
} | |
} | |
/** | |
* $data_matches[0] is the raw data tag | |
* $data_matches[1] is the data variable (dot notated) | |
*/ | |
if (preg_match_all($this->variable_tag_regex, $text, $data_matches)) | |
{ | |
foreach ($data_matches[1] as $index => $var) | |
{ | |
if (($val = $this->get_variable($var, $data, '__lex_no_value__')) !== '__lex_no_value__') | |
{ | |
$text = str_replace($data_matches[0][$index], $val, $text); | |
} | |
} | |
} | |
return $text; | |
} | |
/** | |
* Parses all Callback tags, and sends them through the given $callback. | |
* | |
* @param string $text Text to parse | |
* @param mixed $callback Callback to apply to each tag | |
* @param bool $in_conditional Whether we are in a conditional tag | |
* @return string | |
*/ | |
public function parse_callback_tags($text, $data, $callback) | |
{ | |
$this->setup_regex(); | |
$in_condition = $this->in_condition; | |
if ($in_condition) | |
{ | |
$regex = '/\{\s*('.$this->variable_regex.')(\s+.*?)?\s*\}/ms'; | |
} | |
else | |
{ | |
$regex = '/\{\{\s*('.$this->variable_regex.')(\s+.*?)?\s*\}\}/ms'; | |
} | |
/** | |
* $match[0][0] is the raw tag | |
* $match[0][1] is the offset of raw tag | |
* $match[1][0] is the callback name | |
* $match[1][1] is the offset of callback name | |
* $match[2][0] is the parameters | |
* $match[2][1] is the offset of parameters | |
*/ | |
while (preg_match($regex, $text, $match, PREG_OFFSET_CAPTURE)) | |
{ | |
$parameters = array(); | |
$tag = $match[0][0]; | |
$start = $match[0][1]; | |
$name = $match[1][0]; | |
if (isset($match[2])) | |
{ | |
$cb_data = $data; | |
if ( !empty(Lex_Parser::$callback_data)) | |
{ | |
$cb_data = array_merge(Lex_Parser::$callback_data, (array) $data); | |
} | |
$raw_params = $this->inject_extractions($match[2][0], '__cond_str'); | |
$parameters = $this->parse_parameters($raw_params, $cb_data, $callback); | |
} | |
$content = ''; | |
$temp_text = substr($text, $start + strlen($tag)); | |
if (preg_match('/\{\{\s*\/'.preg_quote($name, '/').'\s*\}\}/m', $temp_text, $match, PREG_OFFSET_CAPTURE)) | |
{ | |
$content = substr($temp_text, 0, $match[0][1]); | |
$tag .= $content.$match[0][0]; | |
// Is there a nested block under this one existing with the same name? | |
$nested_regex = '/\{\{\s*('.preg_quote($name, '/').')(\s.*?)\}\}(.*?)\{\{\s*\/\1\s*\}\}/ms'; | |
if (preg_match($nested_regex, $content.$match[0][0], $nested_matches)) | |
{ | |
$nested_content = preg_replace('/\{\{\s*\/'.preg_quote($name, '/').'\s*\}\}/m', '', $nested_matches[0]); | |
$content = $this->create_extraction('nested_looped_tags', $nested_content, $nested_content, $content); | |
} | |
} | |
$replacement = call_user_func_array($callback, array($name, $parameters, $content)); | |
$replacement = $this->parse_recursives($replacement, $content, $callback); | |
if ($in_condition) | |
{ | |
$replacement = $this->value_to_literal($replacement); | |
} | |
$text = preg_replace('/'.preg_quote($tag, '/').'/m', addcslashes($replacement, '\\$'), $text, 1); | |
$text = $this->inject_extractions($text, 'nested_looped_tags'); | |
} | |
return $text; | |
} | |
/** | |
* Parses all conditionals, then executes the conditionals. | |
* | |
* @param string $text Text to parse | |
* @param mixed $data Data to use when executing conditionals | |
* @param mixed $callback The callback to be used for tags | |
* @return string | |
*/ | |
public function parse_conditionals($text, $data, $callback) | |
{ | |
$this->setup_regex(); | |
preg_match_all($this->conditional_regex, $text, $matches, PREG_SET_ORDER); | |
$this->conditional_data = $data; | |
/** | |
* $matches[][0] = Full Match | |
* $matches[][1] = Either 'if', 'unless', 'elseif', 'unlessif' | |
* $matches[][2] = Condition | |
*/ | |
foreach ($matches as $match) | |
{ | |
$this->in_condition = true; | |
$condition = $match[2]; | |
// Extract all literal string in the conditional to make it easier | |
if (preg_match_all('/(["\']).*?(?<!\\\\)\1/', $condition, $str_matches)) | |
{ | |
foreach ($str_matches[0] as $m) | |
{ | |
$condition = $this->create_extraction('__cond_str', $m, $m, $condition); | |
} | |
} | |
$condition = preg_replace_callback('/\b('.$this->variable_regex.')\b/', array($this, 'process_condition_var'), $condition); | |
if ($callback) | |
{ | |
$condition = preg_replace('/\b(?!\{\s*)('.$this->callback_name_regex.')(?!\s+.*?\s*\})\b/', '{$1}', $condition); | |
$condition = $this->parse_callback_tags($condition, $data, $callback); | |
} | |
// Re-inject any strings we extracted | |
$condition = $this->inject_extractions($condition, '__cond_str'); | |
$conditional = '<?php '.$match[1].' ('.$condition.'): ?>'; | |
$text = preg_replace('/'.preg_quote($match[0], '/').'/m', addcslashes($conditional, '\\$'), $text, 1); | |
} | |
$text = preg_replace($this->conditional_else_regex, '<?php else: ?>', $text); | |
$text = preg_replace($this->conditional_end_regex, '<?php endif; ?>', $text); | |
$text = $this->parse_php($text); | |
$this->in_condition = false; | |
return $text; | |
} | |
/** | |
* Goes recursively through a callback tag with a passed child array. | |
* | |
* @param string $text - The replaced text after a callback. | |
* @param string $orig_text - The original text, before a callback is called. | |
* @param mixed $callback | |
* @return string $text | |
*/ | |
public function parse_recursives($text, $orig_text, $callback) | |
{ | |
// Is there a {{ *recursive [array_key]* }} tag here, let's loop through it. | |
if (preg_match($this->recursive_regex, $text, $match)) | |
{ | |
$array_key = $match[1]; | |
$tag = $match[0]; | |
$next_tag = null; | |
$children = Lex_Parser::$callback_data[$array_key]; | |
$child_count = count($children); | |
$count = 1; | |
// Is the array not multi-dimensional? Let's make it multi-dimensional. | |
if ($child_count == count($children, COUNT_RECURSIVE)) | |
{ | |
$children = array($children); | |
$child_count = 1; | |
} | |
foreach ($children as $child) | |
{ | |
$has_children = true; | |
// If this is a object let's convert it to an array. | |
is_array($child) OR $child = (array) $child; | |
// Does this child not contain any children? | |
// Let's set it as empty then to avoid any errors. | |
if ( ! array_key_exists($array_key, $child)) | |
{ | |
$child[$array_key] = array(); | |
$has_children = false; | |
} | |
$replacement = $this->parse($orig_text, $child, $callback, $this->allow_php); | |
// If this is the first loop we'll use $tag as reference, if not | |
// we'll use the previous tag ($next_tag) | |
$current_tag = ($next_tag !== null) ? $next_tag : $tag; | |
// If this is the last loop set the next tag to be empty | |
// otherwise hash it. | |
$next_tag = ($count == $child_count) ? '' : md5($tag.$replacement); | |
$text = str_replace($current_tag, $replacement.$next_tag, $text); | |
if ($has_children) | |
{ | |
$text = $this->parse_recursives($text, $orig_text, $callback); | |
} | |
$count++; | |
} | |
} | |
return $text; | |
} | |
/** | |
* Gets or sets the Scope Glue | |
* | |
* @param string|null $glue The Scope Glue | |
* @return string | |
*/ | |
public function scope_glue($glue = null) | |
{ | |
if ($glue !== null) | |
{ | |
$this->regex_setup = false; | |
$this->scope_glue = $glue; | |
} | |
return $glue; | |
} | |
/** | |
* Sets the noparse style. Immediate or cumulative. | |
* | |
* @param bool $mode | |
* @return void | |
*/ | |
public function cumulative_noparse($mode) | |
{ | |
$this->cumulative_noparse = $mode; | |
} | |
/** | |
* Injects noparse extractions. | |
* | |
* This is so that multiple parses can store noparse | |
* extractions and all noparse can then be injected right | |
* before data is displayed. | |
* | |
* @param string $text Text to inject into | |
* @return string | |
*/ | |
public function inject_noparse($text) | |
{ | |
if (isset(Lex_Parser::$extractions['noparse'])) | |
{ | |
foreach (Lex_Parser::$extractions['noparse'] AS $hash => $replacement) | |
{ | |
if (strpos($text, "noparse_{$hash}") !== FALSE) | |
{ | |
$text = str_replace("noparse_{$hash}", $replacement, $text); | |
} | |
} | |
} | |
return $text; | |
} | |
/** | |
* This is used as a callback for the conditional parser. It takes a variable | |
* and returns the value of it, properly formatted. | |
* | |
* @param array $match A match from preg_replace_callback | |
* @return string | |
*/ | |
protected function process_condition_var($match) | |
{ | |
$var = is_array($match) ? $match[0] : $match; | |
if (in_array(strtolower($var), array('true', 'false', 'null', 'or', 'and')) or | |
strpos($var, '__cond_str') === 0 or | |
is_numeric($var)) | |
{ | |
return $var; | |
} | |
$value = $this->get_variable($var, $this->conditional_data, '__process_condition_var__'); | |
if ($value === '__process_condition_var__') | |
{ | |
return $this->in_condition ? $var : 'null'; | |
} | |
return $this->value_to_literal($value); | |
} | |
/** | |
* This is used as a callback for the conditional parser. It takes a variable | |
* and returns the value of it, properly formatted. | |
* | |
* @param array $match A match from preg_replace_callback | |
* @return string | |
*/ | |
protected function process_param_var($match) | |
{ | |
return $match[1].$this->process_condition_var($match[2]); | |
} | |
/** | |
* Takes a value and returns the literal value for it for use in a tag. | |
* | |
* @param string $value Value to convert | |
* @return string | |
*/ | |
protected function value_to_literal($value) | |
{ | |
if ($value === null) | |
{ | |
return "null"; | |
} | |
elseif ($value === true) | |
{ | |
return "true"; | |
} | |
elseif ($value === false) | |
{ | |
return "false"; | |
} | |
elseif (is_numeric($value)) | |
{ | |
return '"'.$value.'"'; | |
} | |
elseif (is_string($value)) | |
{ | |
return '"'.addslashes($value).'"'; | |
} | |
elseif (is_object($value) and is_callable(array($value, '__toString'))) | |
{ | |
return '"'.addslashes((string) $value).'"'; | |
} | |
elseif (is_array($value)) | |
{ | |
return !empty($value) ? "true" : "false"; | |
} | |
else | |
{ | |
return $value; | |
} | |
} | |
/** | |
* Sets up all the global regex to use the correct Scope Glue. | |
* | |
* @return void | |
*/ | |
protected function setup_regex() | |
{ | |
if ($this->regex_setup) | |
{ | |
return; | |
} | |
$glue = preg_quote($this->scope_glue, '/'); | |
$this->variable_regex = $glue === '\\.' ? '[a-zA-Z0-9_'.$glue.']+' : '[a-zA-Z0-9_\.'.$glue.']+'; | |
$this->callback_name_regex = $this->variable_regex.$glue.$this->variable_regex; | |
$this->variable_loop_regex = '/\{\{\s*('.$this->variable_regex.')\s*\}\}(.*?)\{\{\s*\/\1\s*\}\}/ms'; | |
$this->variable_tag_regex = '/\{\{\s*('.$this->variable_regex.')\s*\}\}/m'; | |
$this->callback_block_regex = '/\{\{\s*('.$this->variable_regex.')(\s.*?)\}\}(.*?)\{\{\s*\/\1\s*\}\}/ms'; | |
$this->recursive_regex = '/\{\{\s*\*recursive\s*('.$this->variable_regex.')\*\s*\}\}/ms'; | |
$this->noparse_regex = '/\{\{\s*noparse\s*\}\}(.*?)\{\{\s*\/noparse\s*\}\}/ms'; | |
$this->conditional_regex = '/\{\{\s*(if|elseif)\s*((?:\()?(.*?)(?:\))?)\s*\}\}/ms'; | |
$this->conditional_else_regex = '/\{\{\s*else\s*\}\}/ms'; | |
$this->conditional_end_regex = '/\{\{\s*(\/if|endif)\s*\}\}/ms'; | |
$this->regex_setup = true; | |
} | |
/** | |
* Extracts the noparse text so that it is not parsed. | |
* | |
* @param string $text The text to extract from | |
* @return string | |
*/ | |
protected function extract_noparse($text) | |
{ | |
/** | |
* $matches[][0] is the raw noparse match | |
* $matches[][1] is the noparse contents | |
*/ | |
if (preg_match_all($this->noparse_regex, $text, $matches, PREG_SET_ORDER)) | |
{ | |
foreach ($matches as $match) | |
{ | |
$text = $this->create_extraction('noparse', $match[0], $match[1], $text); | |
} | |
} | |
return $text; | |
} | |
/** | |
* Extracts the looped tags so that we can parse conditionals then re-inject. | |
* | |
* @param string $text The text to extract from | |
* @return string | |
*/ | |
protected function extract_looped_tags($text, $data = array(), $callback = null) | |
{ | |
/** | |
* $matches[][0] is the raw match | |
*/ | |
if (preg_match_all($this->callback_block_regex, $text, $matches, PREG_SET_ORDER)) | |
{ | |
foreach ($matches as $match) | |
{ | |
// Does this callback block contain parameters? | |
if ($this->parse_parameters($match[2], $data, $callback)) | |
{ | |
// Let's extract it so it doesn't conflict with local variables when | |
// parse_variables() is called. | |
$text = $this->create_extraction('callback_blocks', $match[0], $match[0], $text); | |
} | |
else | |
{ | |
$text = $this->create_extraction('looped_tags', $match[0], $match[0], $text); | |
} | |
} | |
} | |
return $text; | |
} | |
/** | |
* Extracts text out of the given text and replaces it with a hash which | |
* can be used to inject the extractions replacement later. | |
* | |
* @param string $type Type of extraction | |
* @param string $extraction The text to extract | |
* @param string $replacement Text that will replace the extraction when re-injected | |
* @param string $text Text to extract out of | |
* @return string | |
*/ | |
protected function create_extraction($type, $extraction, $replacement, $text) | |
{ | |
$hash = md5($replacement); | |
Lex_Parser::$extractions[$type][$hash] = $replacement; | |
return str_replace($extraction, "{$type}_{$hash}", $text); | |
} | |
/** | |
* Injects all of the extractions. | |
* | |
* @param string $text Text to inject into | |
* @return string | |
*/ | |
protected function inject_extractions($text, $type = null) | |
{ | |
if ($type === null) | |
{ | |
foreach (Lex_Parser::$extractions as $type => $extractions) | |
{ | |
foreach ($extractions as $hash => $replacement) | |
{ | |
if (strpos($text, "{$type}_{$hash}") !== false) | |
{ | |
$text = str_replace("{$type}_{$hash}", $replacement, $text); | |
unset(Lex_Parser::$extractions[$type][$hash]); | |
} | |
} | |
} | |
} | |
else | |
{ | |
if ( ! isset(Lex_Parser::$extractions[$type])) | |
{ | |
return $text; | |
} | |
foreach (Lex_Parser::$extractions[$type] as $hash => $replacement) | |
{ | |
if (strpos($text, "{$type}_{$hash}") !== false) | |
{ | |
$text = str_replace("{$type}_{$hash}", $replacement, $text); | |
unset(Lex_Parser::$extractions[$type][$hash]); | |
} | |
} | |
} | |
return $text; | |
} | |
/** | |
* Takes a dot-notated key and finds the value for it in the given | |
* array or object. | |
* | |
* @param string $key Dot-notated key to find | |
* @param array|object $data Array or object to search | |
* @param mixed $default Default value to use if not found | |
* @return mixed | |
*/ | |
protected function get_variable($key, $data, $default = null) | |
{ | |
if (strpos($key, $this->scope_glue) === false) | |
{ | |
$parts = explode('.', $key); | |
} | |
else | |
{ | |
$parts = explode($this->scope_glue, $key); | |
} | |
foreach ($parts as $key_part) | |
{ | |
if (is_array($data)) | |
{ | |
if ( ! array_key_exists($key_part, $data)) | |
{ | |
return $default; | |
} | |
$data = $data[$key_part]; | |
} | |
elseif (is_object($data)) | |
{ | |
if ( ! isset($data->{$key_part})) | |
{ | |
return $default; | |
} | |
$data = $data->{$key_part}; | |
} | |
else | |
{ | |
return $default; | |
} | |
} | |
return $data; | |
} | |
/** | |
* Evaluates the PHP in the given string. | |
* | |
* @param string $text Text to evaluate | |
* @return string | |
*/ | |
protected function parse_php($text) | |
{ | |
ob_start(); | |
$result = eval('?>'.$text.'<?php '); | |
if (($result === false) and (ENVIRONMENT === PYRO_DEVELOPMENT)) | |
{ | |
echo '<br />You have a syntax error in your Lex tags. The snippet of text that contains the error has been output below:<br />'; | |
exit(str_replace(array('?>', '<?php '), '', $text)); | |
} | |
elseif ($result === false) | |
{ | |
log_message('error', str_replace(array('?>', '<?php '), '', $text)); | |
echo '<br />You have a syntax error in your Lex tags: The snippet of text that contains the error has been output to your application\'s log file.<br />'; | |
} | |
return ob_get_clean(); | |
} | |
/** | |
* Parses a parameter string into an array | |
* | |
* @param string The string of parameters | |
* @return array | |
*/ | |
protected function parse_parameters($parameters, $data, $callback) | |
{ | |
$this->conditional_data = $data; | |
$this->in_condition = true; | |
// Extract all literal string in the conditional to make it easier | |
if (preg_match_all('/(["\']).*?(?<!\\\\)\1/', $parameters, $str_matches)) | |
{ | |
foreach ($str_matches[0] as $m) | |
{ | |
$parameters = $this->create_extraction('__param_str', $m, $m, $parameters); | |
} | |
} | |
$parameters = preg_replace_callback( | |
'/(.*?\s*=\s*(?!__))('.$this->variable_regex.')/is', | |
array($this, 'process_param_var'), | |
$parameters | |
); | |
if ($callback) | |
{ | |
$parameters = preg_replace('/(.*?\s*=\s*(?!\{\s*)(?!__))('.$this->callback_name_regex.')(?!\s*\})\b/', '$1{$2}', $parameters); | |
$parameters = $this->parse_callback_tags($parameters, $data, $callback); | |
} | |
// Re-inject any strings we extracted | |
$parameters = $this->inject_extractions($parameters, '__param_str'); | |
$this->in_condition = false; | |
if (preg_match_all('/(.*?)\s*=\s*(\'|"|&#?\w+;)(.*?)(?<!\\\\)\2/s', trim($parameters), $matches)) | |
{ | |
$return = array(); | |
foreach ($matches[1] as $i => $attr) | |
{ | |
$return[trim($matches[1][$i])] = stripslashes($matches[3][$i]); | |
} | |
return $return; | |
} | |
return array(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php if (!defined('BASEPATH')) exit('No direct script access allowed'); | |
/** | |
* Bonfire | |
* | |
* An open source project to allow developers get a jumpstart their development of CodeIgniter applications | |
* | |
* @package Bonfire | |
* @author Bonfire Dev Team | |
* @copyright Copyright (c) 2011 - 2012, Bonfire Dev Team | |
* @license http://guides.cibonfire.com/license.html | |
* @link http://cibonfire.com | |
* @since Version 1.0 | |
* @filesource | |
*/ | |
// ------------------------------------------------------------------------ | |
/** | |
* Template | |
* | |
* The Template class makes the creation of consistently themed web pages across your | |
* entire site simple and as automatic as possible. | |
* | |
* It supports parent/child themes, controller-named automatic overrides, and more. | |
* | |
* @package Bonfire | |
* @subpackage Libraries | |
* @category Libraries | |
* @author Bonfire Dev Team | |
* @version 3.0 | |
* @link http://cibonfire.com/docs/guides/views.html | |
* | |
*/ | |
class Template | |
{ | |
/** | |
* Set the debug mode on the template to output messages | |
* | |
* @access private | |
* @static | |
* | |
* @var bool | |
*/ | |
private static $debug = false; | |
/** | |
* Stores the name of the active theme (folder) with a trailing slash. | |
* | |
* @access protected | |
* @static | |
* | |
* @var string | |
*/ | |
protected static $active_theme = ''; | |
/** | |
* Stores the default theme from the config file for a slight performance increase. | |
* | |
* @access protected | |
* @static | |
* | |
* @var string | |
*/ | |
protected static $default_theme = ''; | |
/** | |
* The view to load. Normally not set unless you need to bypass the automagic. | |
* | |
* @access protected | |
* @static | |
* | |
* @var string | |
*/ | |
protected static $current_view; | |
/** | |
* The layout to render the views into. | |
* | |
* @access public | |
* @static | |
* | |
* @var string | |
*/ | |
public static $layout; | |
/** | |
* If TRUE, CodeIgniter's Template Parser will be used to | |
* parse the view. If FALSE, the view is displayed with | |
* no parsing. Used by the yield() and block() | |
* | |
* @access public | |
* @static | |
* | |
* @var bool | |
*/ | |
public static $parse_views = FALSE; | |
/** | |
* The data to be passed into the views. The keys are the names of the variables | |
* and the values are the values. | |
* | |
* @access protected | |
* @static | |
* | |
* @var array | |
*/ | |
protected static $data = array(); | |
/** | |
* An array of blocks. The key is the name to reference it by, and the value is the file. | |
* The class will loop through these, parse them, and push them into the layout. | |
* | |
* @access public | |
* @static | |
* | |
* @var array | |
*/ | |
public static $blocks = array(); | |
/** | |
* Holds a simple array to store the status Message | |
* that gets displayed using the message() function. | |
* | |
* @access protected | |
* @static | |
* | |
* @var string | |
*/ | |
protected static $message; | |
/** | |
* An array of paths to look for themes. | |
* | |
* @access protected | |
* @static | |
* | |
* @var array | |
*/ | |
protected static $theme_paths = array(); | |
/** | |
* The full server path to the site root. | |
* | |
* @access public | |
* @static | |
* | |
* @var string | |
*/ | |
public static $site_path; | |
/** | |
* Stores CI's default view path. | |
* | |
* @access protected | |
* @static | |
* | |
* @var string | |
*/ | |
protected static $orig_view_path; | |
/** | |
* An instance of the CI super object. | |
* | |
* @access private | |
* @static | |
* | |
* @var object | |
*/ | |
private static $ci; | |
//-------------------------------------------------------------------- | |
/** | |
* This constructor is here purely for CI's benefit, as this is a static class. | |
* | |
* @return void | |
*/ | |
public function __construct() | |
{ | |
self::$ci =& get_instance(); | |
self::init(); | |
}//end __construct() | |
//-------------------------------------------------------------------- | |
/** | |
* Grabs an instance of the CI superobject, loads the Ocular config | |
* file, and sets our default layout. | |
* | |
* @access public | |
* @static | |
* | |
* @return void | |
*/ | |
public static function init() | |
{ | |
// If the application config file hasn't been loaded, do it now | |
if (!self::$ci->config->item('template.theme_paths')) | |
{ | |
self::$ci->config->load('application'); | |
} | |
// Store our settings | |
self::$site_path = self::$ci->config->item('template.site_path'); | |
self::$theme_paths = self::$ci->config->item('template.theme_paths'); | |
self::$layout = self::$ci->config->item('template.default_layout'); | |
self::$default_theme = self::$ci->config->item('template.default_theme'); | |
self::$parse_views = self::$ci->config->item('template.parse_views'); | |
// Store our orig view path, so we can reset it | |
//self::$orig_view_path = self::$ci->load->_ci_view_path; | |
log_message('debug', 'Template library loaded'); | |
}//end init() | |
//-------------------------------------------------------------------- | |
/** | |
* Renders out the specified layout, which starts the process | |
* of rendering the page content. Also determines the correct | |
* view to use based on the current controller/method. | |
* | |
* @access public | |
* @static | |
* | |
* @global object $OUT Core CodeIgniter Output object | |
* @param string $layout The name of the a layout to use. This overrides any current or default layouts set. | |
* | |
* @return void | |
*/ | |
public static function render($layout=NULL) | |
{ | |
$output = ''; | |
$controller = self::$ci->router->class; | |
// We need to know which layout to render | |
$layout = empty($layout) ? self::$layout : $layout; | |
// Is it in an AJAX call? If so, override the layout | |
if (self::$ci->input->is_ajax_request()) | |
{ | |
$layout = self::$ci->config->item('template.ajax_layout'); | |
self::$ci->output->set_header("Cache-Control: no-store, no-cache, must-revalidate"); | |
self::$ci->output->set_header("Cache-Control: post-check=0, pre-check=0"); | |
self::$ci->output->set_header("Pragma: no-cache"); | |
self::$ci->output->set_header('Content-Type: text/html'); | |
$controller = NULL; | |
} | |
// Grab our current view name, based on controller/method | |
// which routes to views/controller/method. | |
if (empty(self::$current_view)) | |
{ | |
self::$current_view = self::$ci->router->class . '/' . self::$ci->router->method; | |
} | |
// | |
// Time to render the layout | |
// | |
self::load_view($layout, self::$data, $controller, TRUE, $output); | |
if (empty($output)) { show_error('Unable to find theme layout: '. $layout); } | |
Events::trigger('after_layout_render', $output); | |
global $OUT; | |
$OUT->set_output($output); | |
// Reset the original view path | |
//self::$ci->load->_ci_view_path = self::$orig_view_path; | |
}//end render() | |
//-------------------------------------------------------------------- | |
/** | |
* Renders the current page into the layout. | |
* | |
* Uses a view based on the controller/function being run. (See __constructor). | |
* | |
* @access public | |
* @static | |
* | |
* @return string A string containing the output of the render process. | |
*/ | |
public static function yield() | |
{ | |
$output = ''; | |
if (self::$debug) { echo 'Current View = '. self::$current_view; } | |
self::load_view(self::$current_view, NULL, self::$ci->router->class .'/'. self::$ci->router->method, FALSE, $output); | |
Events::trigger('after_page_render', $output); | |
return $output; | |
}//end yield() | |
//-------------------------------------------------------------------- | |
//-------------------------------------------------------------------- | |
// !BLOCKS | |
//-------------------------------------------------------------------- | |
/** | |
* Stores the block named $name in the blocks array for later rendering. | |
* The $current_view variable is the name of an existing view. If it is empty, | |
* your script should still function as normal. | |
* | |
* @access public | |
* @static | |
* | |
* @param string $block_name The name of the block. Must match the name in the block() method. | |
* @param string $view_name The name of the view file to render. | |
* | |
* @return void | |
*/ | |
public static function set_block($block_name='', $view_name='') | |
{ | |
if (!empty($block_name)) | |
{ | |
self::$blocks[$block_name] = $view_name; | |
} | |
}//end set_block() | |
//-------------------------------------------------------------------- | |
/** | |
* Renders a "block" to the view. | |
* | |
* A block is a partial view contained in a view file in the | |
* application/views folder. It can be used for sidebars, | |
* headers, footers, or any other recurring element within | |
* a site. It is recommended to set a default when calling | |
* this function within a layout. The default will be rendered | |
* if no methods override the view (using the set_block() method). | |
* | |
* @access public | |
* @static | |
* | |
* @param string $block_name The name of the block to render. | |
* @param string $default_view The view to render if no other view has been set with the set_block() method. | |
* @param array $data An array of data to pass to the view. | |
* @param bool $themed Whether we should look in the themes or standard view locations. | |
* | |
* @return void | |
*/ | |
public static function block($block_name='', $default_view='', $data=array(), $themed=FALSE) | |
{ | |
if (empty($block_name)) | |
{ | |
logit('[Template] No block name provided.'); | |
return; | |
} | |
if (empty($block_name) && empty($default_view)) | |
{ | |
logit('[Template] No default block provided for `' . $block_name . '`'); | |
return; | |
} | |
// If a block has been set previously use that | |
if (isset(self::$blocks[$block_name])) | |
{ | |
$block_name = self::$blocks[$block_name]; | |
} | |
// Otherwise, use the default view. | |
else | |
{ | |
$block_name = $default_view; | |
} | |
if (self::$debug) { echo "Looking for block: <b>{$block_name}</b>."; } | |
self::load_view($block_name, $data, FALSE, $themed, $output); | |
$block_data = array('block'=>$block_name, 'output'=>$output); | |
Events::trigger('after_block_render', $block_data ); | |
echo $output; | |
}//end block() | |
//-------------------------------------------------------------------- | |
//-------------------------------------------------------------------- | |
// !THEME PATHS | |
//-------------------------------------------------------------------- | |
/** | |
* Theme paths allow you to have multiple locations for themes to be | |
* stored. This might be used for separating themes for different sub- | |
* applications, or a core theme and user-submitted themes. | |
* | |
* @access public | |
* @static | |
* | |
* @param string $path A new path where themes can be found. | |
* | |
* @return bool | |
*/ | |
public static function add_theme_path($path=NULL) | |
{ | |
if (empty($path) || !is_string($path)) | |
{ | |
return FALSE; | |
} | |
// Make sure the path has a '/' at the end. | |
if (substr($path, -1) != '/') | |
{ | |
$path .= '/'; | |
} | |
// If the path already exists, we're done here. | |
if (isset(self::$theme_paths[$path])) | |
{ | |
return TRUE; | |
} | |
// Make sure the folder actually exists | |
if (is_dir(FCPATH . $path)) | |
{ | |
array_push(self::$theme_paths, $path); | |
return FALSE; | |
} | |
else | |
{ | |
logit("[Template] Cannot add theme folder: $path does not exist"); | |
return FALSE; | |
} | |
}//end add_theme_path() | |
//-------------------------------------------------------------------- | |
/** | |
* Remove the theme path | |
* | |
* @access public | |
* @static | |
* | |
* @param string $path The path to remove from the theme paths. | |
* | |
* @return void | |
*/ | |
public static function remove_theme_path($path=NULL) | |
{ | |
if (empty($path) || !is_string($path)) | |
{ | |
return; | |
} | |
if (isset(self::$theme_paths[$path])) | |
{ | |
unset(self::$theme_paths[$path]); | |
} | |
}//end remove_theme_path() | |
//-------------------------------------------------------------------- | |
/** | |
* Stores the name of the active theme to use. This theme should be | |
* relative to one of the 'template.theme_paths' folders. | |
* | |
* @access public | |
* @static | |
* | |
* @param string $theme The name of the active theme. | |
* @param string $default_theme (Optional) The name of the desired default theme. | |
* | |
* @return void | |
*/ | |
public static function set_theme($theme=NULL, $default_theme=NULL) | |
{ | |
if (empty($theme) || !is_string($theme)) | |
{ | |
return; | |
} | |
// Make sure a trailing slash is there | |
if (substr($theme, -1) !== '/') | |
{ | |
$theme .= '/'; | |
} | |
self::$active_theme = $theme; | |
// Default theme? | |
if (!empty($default_theme) && is_string($default_theme)) | |
{ | |
self::set_default_theme($default_theme); | |
} | |
}//end set_theme() | |
//-------------------------------------------------------------------- | |
/** | |
* Stores the name of the default theme to use. This theme should be | |
* relative to one of the template.theme_paths folders. | |
* | |
* @access public | |
* @static | |
* | |
* @param string $theme The name of the desired default theme to use. | |
* | |
* @return void | |
*/ | |
public static function set_default_theme($theme=NULL) | |
{ | |
if (empty($theme) || !is_string($theme)) | |
{ | |
return; | |
} | |
// Make sure a trailing slash is there | |
if (substr($theme, -1) !== '/') | |
{ | |
$theme .= '/'; | |
} | |
self::$default_theme = $theme; | |
}//end set_default_theme() | |
//-------------------------------------------------------------------- | |
/** | |
* Returns the active theme. | |
* | |
* @access public | |
* @static | |
* | |
* @return string The name of the active theme. | |
*/ | |
public static function theme() | |
{ | |
return ( ! empty(self::$active_theme)) ? self::$active_theme : self::$default_theme; | |
}//end theme() | |
//-------------------------------------------------------------------- | |
/** | |
* Returns the full url to a file in the currently active theme. | |
* | |
* @access public | |
* @static | |
* | |
* @param string $resource Path to a resource in the theme | |
* | |
* @return string The full url (including http://) to the resource. | |
*/ | |
public static function theme_url($resource='') | |
{ | |
$url = base_url(); | |
// Add theme path | |
$url .= self::$theme_paths[0] .'/'; | |
// Add theme | |
$url .= empty(self::$active_theme) ? self::$default_theme : self::$active_theme; | |
// Cleanup, just to be safe | |
$url = str_replace('//', '/', $url); | |
$url = str_replace(':/', '://', $url); | |
return $url . $resource; | |
}//end theme_url() | |
//-------------------------------------------------------------------- | |
/** | |
* Set the current view to render. | |
* | |
* @access public | |
* @static | |
* | |
* @param string $view The name of the view file to render as content. | |
* | |
* @return void | |
*/ | |
public static function set_view($view=NULL) | |
{ | |
if (empty($view) || !is_string($view)) | |
{ | |
return; | |
} | |
self::$current_view = $view; | |
}//end set_view() | |
//-------------------------------------------------------------------- | |
/** | |
* Makes it easy to save information to be rendered within the views. | |
* As of 3.0, can also set any of the class properties. | |
* | |
* @param string $var_name The name of the variable to set | |
* @param mixed $value The value to set it to. | |
* | |
* @return void | |
*/ | |
public static function set($var_name='', $value='') | |
{ | |
// Added by dkenzik | |
// 20101001 | |
// Easier migration when $data is scaterred all over your project | |
// | |
if(is_array($var_name) && $value=='') | |
{ | |
foreach($var_name as $key => $value) | |
{ | |
self::$data[$key] = $value; | |
} | |
} | |
else | |
{ | |
// Is it a class property? | |
if (isset(self::$$var_name)) | |
{ | |
self::$$var_name = $value; | |
} | |
else | |
{ | |
self::$data[$var_name] = $value; | |
} | |
}//end if | |
}//end set() | |
//-------------------------------------------------------------------- | |
/** | |
* Returns a variable that has been previously set, or FALSE if not exists. | |
* As of 3.0, will also return class properties. | |
* | |
* @access public | |
* @static | |
* | |
* @param string $var_name The name of the data item to return. | |
* | |
* @return mixed The value of the class property or view data. | |
*/ | |
public static function get($var_name=NULL) | |
{ | |
if (empty($var_name)) | |
{ | |
return FALSE; | |
} | |
// First, is it a class property? | |
if (isset(self::$$var_name)) | |
{ | |
return self::$$var_name; | |
} | |
else if (isset(self::$data[$var_name])) | |
{ | |
return self::$data[$var_name]; | |
} | |
return FALSE; | |
}//end get() | |
//-------------------------------------------------------------------- | |
/** | |
* Set whether or not the views will be passed through CI's parser. | |
* | |
* @access public | |
* | |
* @param bool $parse Boolean value. Should we parse views? | |
*/ | |
public function parse_views($parse = FALSE) | |
{ | |
self::$parse_views = (bool) $parse; | |
}//end parse_views() | |
//-------------------------------------------------------------------- | |
/** | |
* Sets a status message (for displaying small success/error messages). | |
* This function is used in place of the session->flashdata function, | |
* because you don't always want to have to refresh the page to get the | |
* message to show up. | |
* | |
* @access public | |
* @static | |
* | |
* @param string $message A string with the message to save. | |
* @param string $type A string to be included as the CSS class of the containing div. | |
* | |
* @return void | |
*/ | |
public static function set_message($message='', $type='info') | |
{ | |
if (!empty($message)) | |
{ | |
if (isset(self::$ci->session)) | |
{ | |
self::$ci->session->set_flashdata('message', $type.'::'.$message); | |
} | |
self::$message = array('type'=>$type, 'message'=>$message); | |
} | |
}//end set_message() | |
//--------------------------------------------------------------- | |
/** | |
* Displays a status message (small success/error messages). | |
* If data exists in 'message' session flashdata, that will | |
* override any other messages. The renders the message based | |
* on the template provided in the config file ('OCU_message_template'). | |
* | |
* @access public | |
* @static | |
* | |
* @param string $message A string to be the message. (Optional) If included, will override any other messages in the system. | |
* @param string $type The class to attached to the div. (i.e. 'information', 'attention', 'error', 'success') | |
* | |
* @return string A string with the results of inserting the message into the message template. | |
*/ | |
public static function message($message='', $type='information') | |
{ | |
// Does session data exist? | |
if (empty($message) && class_exists('CI_Session')) | |
{ | |
$message = self::$ci->session->flashdata('message'); | |
if (!empty($message)) | |
{ | |
// Split out our message parts | |
$temp_message = explode('::', $message); | |
$type = $temp_message[0]; | |
$message = $temp_message[1]; | |
unset($temp_message); | |
} | |
}//end if | |
// If message is empty, we need to check our own storage. | |
if (empty($message)) | |
{ | |
if (empty(self::$message['message'])) | |
{ | |
return ''; | |
} | |
$message = self::$message['message']; | |
$type = self::$message['type']; | |
} | |
// Grab out message template and replace the placeholders | |
$template = str_replace('{type}', $type, self::$ci->config->item('template.message_template')); | |
$template = str_replace('{message}', $message, $template); | |
// Clear our session data so we don't get extra messages. | |
// (This was a very rare occurence, but clearing should resolve the problem. | |
if (class_exists('CI_Session')) | |
{ | |
self::$ci->session->set_flashdata('message', ''); | |
} | |
return $template; | |
}//end message() | |
//--------------------------------------------------------------- | |
/** | |
* Returns a javascript solution for page redirection. This is especially | |
* handy when you want to redirect out of an ajax request to a standard | |
* http request. | |
* | |
* @access public | |
* @static | |
* | |
* @param string $url The url to redirect to. If not a full url, will wrap it in site_url(). | |
* | |
* @return void | |
*/ | |
public static function redirect($url=NULL) | |
{ | |
$url = strpos($url, 'http') === FALSE ? site_url($url) : $url; | |
echo "<script>window.location='{$url}'</script>"; | |
exit(); | |
}//end redirect() | |
//-------------------------------------------------------------------- | |
/** | |
* Loads a view based on the current themes. | |
* | |
* @access public | |
* @static | |
* | |
* @param string $view The view to load. | |
* @param array $data An array of data elements to be made available to the views | |
* @param string $override The name of a view to check for first (used for controller-based layouts) | |
* @param bool $is_themed Whether it should check in the theme folder first. | |
* @param object $output A pointer to the variable to store the output of the loaded view into. | |
* | |
* @return void | |
*/ | |
public static function load_view($view=NULL, $data=NULL, $override='', $is_themed=TRUE, &$output) | |
{ | |
if (empty($view)) return ''; | |
// If no active theme is present, use the default theme. | |
$theme = empty(self::$active_theme) ? self::$default_theme : self::$active_theme; | |
if ($is_themed) | |
{ | |
// First check for the overriden file... | |
$output = self::find_file($override, $data, $theme); | |
// If we didn't find it, try the standard view | |
if (empty($output)) | |
{ | |
$output = self::find_file($view, $data, $theme); | |
} | |
} | |
// Just a normal view (possibly from a module, though.) | |
else | |
{ | |
// First check within our themes... | |
$output = self::find_file($view, $data, $theme); | |
// if $output is empty, no view was overriden, so go for the default | |
if (empty($output)) | |
{ | |
self::$ci->load->_ci_view_path = self::$orig_view_path; | |
if (self::$parse_views === TRUE) | |
{ | |
if (!class_exists('CI_Parser')) | |
{ | |
self::$ci->load->library('parser'); | |
} | |
// $output = self::$ci->load->_ci_load(array('_ci_path' => $view.'.php','_ci_vars' => $data,'_ci_return' => TRUE)); | |
$data = self::$ci->load->_ci_cached_vars; | |
if (count($data) > 0) | |
{ | |
$temp = array(); | |
foreach($data as $key => $value) | |
{ | |
if (is_object($value) && count($value) > 0) | |
// if (count($value) > 0) | |
{ | |
$value = (array) $value; | |
} | |
$temp[$key] = $value; | |
} | |
$data = array(); | |
$data = $temp; | |
unset($temp); | |
} | |
// $output = self::$ci->load->view($view, $data, TRUE); | |
$output = self::$ci->parser->parse($view, $data, TRUE, TRUE); | |
} | |
else | |
{ | |
$output = self::$ci->load->view($view, $data, TRUE); | |
} | |
} | |
self::$ci->load->_ci_view_path = self::$orig_view_path; | |
}//end if | |
// Put our ci view path back to normal | |
//self::$ci->load->_ci_view_path = self::$orig_view_path; | |
unset($theme, $orig_view_path); | |
}//end load_view() | |
//-------------------------------------------------------------------- | |
//-------------------------------------------------------------------- | |
// !PRIVATE METHODS | |
//-------------------------------------------------------------------- | |
/** | |
* Searches through the the active theme and the default theme to try to find | |
* a view file. If found, it returns the rendered view. | |
* | |
* @access private | |
* | |
* @param string $view The name of the view to find. | |
* @param array $data An array of key/value pairs to pass to the views. | |
* | |
* @return string The content of the file, if found, else empty. | |
*/ | |
private function find_file($view=NULL, $data=NULL) | |
{ | |
if (empty($view)) | |
{ | |
return FALSE; | |
} | |
$output = ''; // Stores the final output | |
$view_path = ''; // Used to store the location of the file. | |
if (!empty($data)) | |
{ | |
$data = (array)$data; | |
} | |
// If there are multiple theme locations, we need to search through all of them. | |
foreach (self::$theme_paths as $path) | |
{ | |
/* | |
First, check the active theme | |
*/ | |
if (self::$debug) { echo "[Find File] Looking for view in active theme: <b>". self::$site_path . $path .'/'. self::$active_theme . $view .'.php</b><br/>'; } | |
if (!empty(self::$active_theme) && is_file(self::$site_path . $path .'/'. self::$active_theme . $view .'.php')) | |
{ | |
if (self::$debug) { echo 'Found <b>'. $view .'</b> in Active Theme.<br/>'; } | |
$view_path = self::$site_path . $path .'/'. self::$active_theme; | |
} | |
/* | |
If not in the active theme, then try the default theme | |
*/ | |
if (self::$debug) { echo "[Find File] Looking for view in default theme: <b>". self::$site_path . $path .'/'. self::$default_theme . $view .'.php</b><br/>'; } | |
if (empty($view_path) && is_file(self::$site_path . $path .'/'. self::$default_theme . $view .'.php')) | |
{ | |
if (self::$debug) { echo 'Found <b>'. $view .'</b> in Default Theme.<br/>'; } | |
$view_path = self::$site_path . $path .'/'. self::$default_theme; | |
} | |
} | |
// If the view was found, it's path is stored in the $view_path var. So parse or render it | |
// based on user settings. | |
if (!empty($view_path)) | |
{ | |
$view_path = str_replace('//', '/', $view_path); | |
// Set CI's view path to point to the right location. | |
//self::$ci->load->_ci_view_path = $view_path; | |
if (self::$debug) { echo '[Find File] Rendering file at: '. $view_path . $view .'.php<br/><br/>'; } | |
// Grab the output of the view. | |
if (self::$parse_views === TRUE) | |
{ | |
$data = array_merge((array)$data,self::$ci->load->_ci_cached_vars); | |
$output = self::$ci->load->_ci_load(array('_ci_path' => $view_path . $view .'.php', '_ci_vars' => $data, '_ci_return' => TRUE)); | |
//This caused Parsing to die if parsing entire template file. | |
//$output = self::$ci->parser->parse($view_path.$view, $data, TRUE, TRUE); | |
} else | |
{ | |
$output = self::$ci->load->_ci_load(array('_ci_path' => $view_path . $view .'.php', '_ci_vars' => $data, '_ci_return' => TRUE)); | |
} | |
// Put CI's view path back to the original | |
//self::$ci->load->_ci_view_path = self::$orig_view_path; | |
}//end if | |
return $output; | |
}//end find_file() | |
//-------------------------------------------------------------------- | |
}//end class | |
//-------------------------------------------------------------------- | |
/** | |
* A shorthand method that allows views (from the current/default themes) | |
* to be included in any other view. | |
* | |
* This function also allows for a very simple form of mobile templates. If being | |
* viewed from a mobile site, it will attempt to load a file whose name is prefixed | |
* with 'mobile_'. If that file is not found it will load the regular view. | |
* | |
* @access public | |
* @example Rendering a view named 'index', the mobile version would be 'mobile_index'. | |
* | |
* @param string $view The name of the view to render. | |
* @param array $data An array of data to pass to the view. | |
* @param bool $ignore_mobile If TRUE, will not change the view name based on mobile viewing. If FALSE, will attempt to load a file prefixed with 'mobile_' | |
* | |
* @return string | |
*/ | |
function theme_view($view=NULL, $data=NULL, $ignore_mobile=FALSE) | |
{ | |
if (empty($view)) return ''; | |
$ci =& get_instance(); | |
$output =''; | |
// If we're allowed, try to load the mobile version | |
// of the file. | |
if (!$ignore_mobile) | |
{ | |
$ci->load->library('user_agent'); | |
if ($ci->agent->is_mobile()) | |
{ | |
Template::load_view('mobile_'. $view, $data, NULL, TRUE, $output); | |
} | |
} | |
// If output is empty, then either no mobile file was found | |
// or we weren't looking for one to begin with. | |
if (empty($output)) | |
{ | |
Template::load_view($view, $data, NULL, TRUE, $output); | |
} | |
return $output; | |
}//end theme_view() | |
//-------------------------------------------------------------------- | |
/** | |
* A simple helper method for checking menu items against the current | |
* class that is running. | |
* | |
* <code> | |
* <a href="<?php echo site_url(SITE_AREA . '/content'); ?>" <?php echo check_class(SITE_AREA . '/content'); ?> > | |
* Admin Home | |
* </a> | |
* | |
* </code> | |
* @access public | |
* | |
* @param string $item The name of the class to check against. | |
* @param bool $class_only If TRUE, will only return 'active'. If FALSE, will return 'class="active"'. | |
* | |
* @return string Either <b>class="active"</b> or an empty string. | |
*/ | |
function check_class($item='', $class_only=FALSE) | |
{ | |
$ci =& get_instance(); | |
if (strtolower($ci->router->fetch_class()) == strtolower($item)) | |
{ | |
return $class_only ? 'active' : 'class="active"'; | |
} | |
return ''; | |
}//end check_class() | |
//-------------------------------------------------------------------- | |
/** | |
* A simple helper method for checking menu items against the current | |
* class' method that is being executed (as far as the Router knows.) | |
* | |
* @access public | |
* | |
* @param string $item The name of the method to check against. Can be an array of names. | |
* | |
* @return string Either <b>class="active"</b> or an empty string. | |
*/ | |
function check_method($item) | |
{ | |
$ci =& get_instance(); | |
$items = array(); | |
if (!is_array($item)) | |
{ | |
$items[] = $item; | |
} | |
else | |
{ | |
$items = $item; | |
} | |
if (in_array($ci->router->fetch_method(), $items)) | |
{ | |
return 'class="active"'; | |
} | |
return ''; | |
}//end check_method() | |
//-------------------------------------------------------------------- | |
/** | |
* Will create a breadcrumb from either the uri->segments or | |
* from a key/value paired array passed into it. | |
* | |
* @access public | |
* | |
* @param array $my_segments (optional) Array of Key/Value to make Breadcrumbs from | |
* @param bool $wrap (boolean) Set to TRUE to wrap in un-ordered list | |
* @param bool $echo (boolean) Set to TRUE to echo the output, set to FALSE to return it. | |
* | |
* @return string A Breadcrumb of your page structure. | |
*/ | |
function breadcrumb($my_segments=NULL, $wrap=FALSE, $echo=TRUE) | |
{ | |
$ci =& get_instance(); | |
$output = ''; | |
if (!class_exists('CI_URI')) | |
{ | |
$ci->load->library('uri'); | |
} | |
if ( $ci->config->item('template.breadcrumb_symbol') == '' ) | |
{ | |
$seperator = '/'; | |
} | |
else | |
{ | |
$seperator = $ci->config->item('template.breadcrumb_symbol'); | |
} | |
if ($wrap === TRUE) | |
{ | |
$seperator = '<span class="divider">' . $seperator . '</span>' . PHP_EOL; | |
} | |
if (empty($my_segments) || !is_array($my_segments)) | |
{ | |
$segments = $ci->uri->segment_array(); | |
$total = $ci->uri->total_segments(); | |
} | |
else | |
{ | |
$segments = $my_segments; | |
$total = count($my_segments); | |
} | |
$in_admin = (bool) (is_array($segments) && in_array(SITE_AREA, $segments)); | |
if ( $in_admin == TRUE ) | |
{ | |
$home_link = site_url(SITE_AREA); | |
} | |
else | |
{ | |
$home_link = site_url(); | |
} | |
if ($wrap === TRUE) | |
{ | |
$output = '<ul class="breadcrumb">' . PHP_EOL; | |
$output .= '<li><a href="'.$home_link.'"><i class="icon-home"> </i></a> '.$seperator.'</li>' . PHP_EOL; | |
} | |
else | |
{ | |
$output = '<a href="'.$home_link.'">home</a> '.$seperator; | |
} | |
$url = ''; | |
$count = 0; | |
// URI BASED BREADCRUMB | |
if (empty($my_segments) || !is_array($my_segments)) | |
{ | |
foreach ($segments as $segment) | |
{ | |
$url .= '/'. $segment; | |
$count += 1; | |
if ($count == $total) | |
{ | |
if ($wrap === TRUE) | |
{ | |
$output .= '<li class="active">' . ucfirst(str_replace('_', ' ', $segment)) . '</li>' . PHP_EOL; | |
} | |
else | |
{ | |
$output .= ucfirst(str_replace('_', ' ', $segment)) . PHP_EOL; | |
} | |
} | |
else | |
{ | |
if ($wrap === TRUE) | |
{ | |
$output .= '<li><a href="'. $url .'">'. str_replace('_', ' ', ucfirst(mb_strtolower($segment))) .'</a>' . $seperator . '</li>' . PHP_EOL; | |
} | |
else | |
{ | |
$output .= '<a href="'. $url .'">'. str_replace('_', ' ', ucfirst(mb_strtolower($segment))) .'</a>' . $seperator . PHP_EOL; | |
} | |
} | |
} | |
} | |
else | |
{ | |
// USER-SUPPLIED BREADCRUMB | |
foreach ($my_segments as $title => $uri) | |
{ | |
$url .= '/'. $uri; | |
$count += 1; | |
if ($count == $total) | |
{ | |
if ($wrap === TRUE) | |
{ | |
$output .= '<li class="active">' . str_replace('_', ' ', $title) . '</li>' . PHP_EOL; | |
} | |
else | |
{ | |
$output .= str_replace('_', ' ', $title); | |
} | |
} | |
else | |
{ | |
if ($wrap === TRUE) | |
{ | |
$output .= '<li><a href="'. $url .'">'. str_replace('_', ' ', ucfirst(mb_strtolower($title))) .'</a>' . $seperator . '</li>' . PHP_EOL; | |
} | |
else | |
{ | |
$output .= '<a href="'. $url .'">'. str_replace('_', ' ', ucfirst(mb_strtolower($title))) .'</a>' . $seperator . PHP_EOL; | |
} | |
} | |
} | |
} | |
if ($wrap === TRUE) | |
{ | |
$output .= PHP_EOL . '</ul>' . PHP_EOL; | |
} | |
unset($in_admin, $seperator, $url, $wrap); | |
if ($echo === TRUE) | |
{ | |
echo $output; | |
unset ($output); | |
} | |
else | |
{ | |
return $output; | |
} | |
}//end breadcrumb() | |
//--------------------------------------------------------------- | |
/* End of file template.php */ | |
/* Location: ./application/libraries/template.php */ |
Thanks 🍺
Thanks 🍺
Hello, this is a awesome work, just one thing. when I load the view from the themes folder is not parsed.
I want my view from themes> mytheme> pages> view.php
When the view is loaded from modules> pages> views> view.php works well.
How to fix this?
thanks for you help...
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Lex Parser for Bonfire Template library.
Add MY_Parser.php and template.php into bonfire/application/libraries/
Create a directory inside of libraries named Lex and place the other 2 files there.
Turn Parsing on with
Enjoy
Credits goto @hardfire and the @pyrocms team a lot of this was borrowed from both.
Enjoy and Cheers 🍺