<?php
/**
* Zula Framework View
* A simple tag replacement engine that also allows for PHP code
*
* @License: http://www.gnu.org/copyleft/gpl.html GNU/GPL 2
* @Author Alex Cartwright
* @Date 2007-03-11
*/
class View {
/**
* Full absolute path to the view file
* @var string
*/
protected $view_path = '';
/**
* The module this is for (for locale)
* @var string
*/
protected $module = '';
/**
* Holds the raw view contents
* @var string
*/
protected $raw_contents = '';
/**
* Holds a modified version of the view contents
* @var string
*/
protected $final_contents = null;
/**
* Assigned tags that will replace tags with different content
* @var array
*/
protected $assigned_tags = array();
/**
* Constructor function
* Attempts to load the view file and sets which module this is for
*
* @param string $view_file
* [@param string $module]
*/
public function __construct( $view_file, $module='' ) {
$this->module = $module;
$this->view_path = trim( $view_file );
if ( !file_exists( $this->view_path ) ) {
$new_path = Zula::get_dir( 'views' ).'/'.$view_file;
if ( !file_exists( $new_path ) ) {
Error::report( 'View file could not be loaded', 'view file is missing or not readable ('.$new_path.')', Error::_WARNING );
}
$this->view_path = $new_path;
}
}
/**
* Returns every tag that is assigned to the view file
*
* @return array
*/
public function get_assigned_tags() {
return $this->assigned_tags;
}
/**
* Assigns a new tag to use that will get replaced
*
* @param array $tags
* [@param bool $overwrite] If a tag already exists, should it be overwriten or appended?
* [@param bool $uppercase] Toggle if to set the tags to upper case
* [@param bool $allow_html] should HTML be allowed in the tag value?
* @return bool
*/
public function assign( $tags, $overwrite=true, $uppercase=true, $allow_html=false ) {
if ( !is_array( $tags ) ) {
return false;
}
foreach( $tags as $tag=>$val ) {
if ( $allow_html == false ) {
$val = $this->clean_tag_value( $val );
}
if ( $uppercase == true ) {
$tag = strtoupper( $tag );
}
$tags[ $this->clean_tag( $tag ) ] = $val;
}
if ( empty( $this->assigned_tags ) ) {
$this->assigned_tags = $tags;
return true;
} else if ( $overwrite == false ) {
/**
* Patch that allows tags that have been assigned more than once
* to be appended onto the end, instead of overwriting the old tag
*/
foreach( $tags as $key=>$val ) {
if ( !is_array( $val ) && isset( $this->assigned_tags[ $key ] ) ) {
$this->assigned_tags[ $key ] .= $val;
} else if ( isset( $this->assigned_tags[ $key ] ) ) {
$this->assigned_tags[ $key ] = array_merge( $this->assigned_tags, $val );
} else {
$this->assigned_tags[ $key ] = $val;
}
}
return true;
} else {
$this->assigned_tags = array_merge( $this->assigned_tags, $tags );
return true;
}
}
/**
* Assigns a new tag but do allow HTML
*
* @param array $tags
* [@param bool $uppercase] Toggle if to set the tags to upper case
* [@param bool $overwrite] If a tag already exists, should it be overwriten or appended?
* @return bool
*/
public function assign_html( $tags, $uppercase=true, $overwrite=true ) {
return $this->assign( $tags, $uppercase, $overwrite, true );
}
/**
* Cleans up a tag to make it Alphanumeric and a few others only
*
* @param string $tag
* @return string
*/
public function clean_tag( $tag ) {
return preg_replace( '/[^A-Za-z0-9_\- ]/', '', $tag );
}
/**
* Cleans up a tag value by recursingly removing HTML
*
* @param mixed $value
* @return mixed
*/
public function clean_tag_value( $value ) {
if ( is_array( $value ) ) {
foreach( $value as $key=>$val ) {
if ( is_array( $val ) ) {
$value[ $this->clean_tag( $key ) ] = $this->clean_tag_value( $val );
} else {
$value[ $this->clean_tag( $key ) ] = htmlspecialchars( strip_tags($val) );
}
}
return $value;
} else {
return htmlspecialchars( strip_tags($value) );
}
}
/**
* Checks if a tag has been assigned to this view file
*
* @return bool
*/
public function is_assigned( $val ) {
return isset( $this->assigned_tags[ $val ] );
}
/**
* This is the actual Tag Replacement method
* First it assigns the default tags that need to be used and then prepars the Tags that
* will be used in the PHP 'Jail' class. All of the Tags for PHP use are convertd to lowercase
*
* After all PHP is run it gets the output from the class and goes about replacing the normal
* {TAGS} in the view file. All language tags are also found and assigned, they appear at the start
* of the assigned tags array
*
* @return string
*/
public function get_output() {
$this->assign_default_tags();
# Prepare the tags for the PHP class
$php_tags = array();
foreach( $this->assigned_tags as $tag=>$val ) {
$php_tags[ strtolower( $tag ) ] = $val;
}
$tmp_view = new View_OB( $php_tags, $this->view_path );
$tmp_view_content = $tmp_view->get_output(); # Return content of the parsed PHP view file
# Gather all language tags and merge them into the final tag array
$language_tags = $this->language_tags( $tmp_view_content );
$this->assigned_tags = array_merge( $language_tags, $this->assigned_tags );
preg_match_all( '@{(.*?)}@', $tmp_view_content, $template_tags );
if ( empty( $template_tags[0] ) ) {
$this->final_contents = $tmp_view_content;
return $this->final_contents;
}
foreach( $template_tags[0] as $key=>$tag ) {
if ( substr( $tag, 0, 4 ) == '{L_[' ) {
# Replace the langauge tags without splitting the tag into .. tokens?
$tmp_view_content = $this->replace_tag( $template_tags[1][ $key ], $tmp_view_content );
} else {
$tag_tokens = explode( '.', $template_tags[1][ $key ] );
if ( count( $tag_tokens ) <= 1 ) {
$tmp_view_content = $this->replace_tag( $template_tags[1][ $key ], $tmp_view_content );
} else {
# Tag is in the format of {FOO.BAR.CAR}
$tmp_view_content = $this->replace_tag( $tag_tokens, $tmp_view_content );
}
}
}
$this->final_contents = $tmp_view_content;
return $this->final_contents;
}
/**
* Replaces a tag in a string, but also checks if that tag is assigned first.
* This function allows for an array as the tag, in the case it will then
* ... 'Follow' the assigned tags array down the tree until it finds the value
* it needs.
*
* @param string $tag
* @param string $content
* @return string
*/
private function replace_tag( $tag, $content ) {
if ( is_array( $tag ) ) {
#Zula::debug_print( $tag );
$str_tag = implode( '.', $tag );
foreach( $tag as $key=>$val ) {
if ( !isset( $tmp_tag_value ) && isset( $this->assigned_tags[ $val ] ) ) {
$tmp_tag_value = $this->assigned_tags[ $val ];
} else if ( isset( $tmp_tag_value ) ) {
$val = strtolower( $val );
if ( isset( $tmp_tag_value[ $val ] ) ) {
$tmp_tag_value = $tmp_tag_value[ $val ];
} else {
Error::report( 'view tag "'.$str_tag.'" could not be replaced for view "'.$this->view_path.'"', 'tag has no assigned value', Error::_WARNING );
return $content;
}
} else {
Error::report( 'view tag "'.$str_tag.'" could not be replaced for view "'.$this->view_path.'"', 'tag has no assigned value', Error::_WARNING );
return $content;
}
}
$value = $tmp_tag_value;
$tag = $str_tag;
} else if ( $this->is_assigned( $tag ) ) {
$value = $this->assigned_tags[ $tag ];
} else {
Error::report( 'view tag "'.$tag.'" could not be replaced for view "'.$this->view_path.'"', 'tag has no assigned value', Error::_WARNING );
return $content;
}
if ( is_array( $value ) ) {
Error::report( 'view tag "'.$tag.'" has invalid assigned value', 'tag wants to get replaced with an array', Error::_WARNING );
return $content;
} else {
return str_replace( '{'.$tag.'}', $value, $content );
}
}
/**
* Provides the Zula Framework with Language Support for View Files
* It searches the view file via reg-ex to find all tags that in the format
* of {L_[Phrase]} and fills a new array which each of the new tags and langauge string
* It also updates the text domain to the current module, if we have one set.
* then resets it back afterwards
*
* @param string $content
* @return array
*/
private function language_tags( $content ) {
/*locale = Registry::get( 'locale' );*/
if ( !empty( $this->module ) ) {
/*$locale->update_text_domain( 'messages', Zula::get_dir( 'controllers' ).'/'.$this->module.'/locale' ); */
}
preg_match_all( '@{L_\[(.[^\]]*)]}@', $content, $tags);
if ( !empty( $tags[0] ) ) {
$language_tags = array();
foreach( $tags[0] as $key=>$tag ) {
$tag = trim( $tag, '{} ' );
#$value = $tags[1][ $key ];
/*$value = $locale->translate( $tags[1][ $key ] );*/
/*$language_tags[ $tag ] = $value;*/
}
/*$locale->update_text_domain();*/
return $language_tags;
} else {
return array();
}
}
/**
* Provides some common, default tags that can be used in every view file
*
* @return bool
*/
private function assign_default_tags() {
$settings = Registry::get( 'settings' );
$default_tags = array(
'TCM_DIR_THEME' => Zula::get_dir( 'themes', true ),
'TCM_DIR_BASE' => Zula::get_base_dir(),
'TCM_META_KEYWORDS' => $settings->get( 'meta/keywords' ),
'TCM_META_DESCRIPTION' => $settings->get( 'meta/description' ),
'TCM_URL_ADMIN' => Router::make_url( null, null, null, 'admin' ),
'TCM_SITE_TITLE' => $settings->get( 'config/title' ),
);
return $this->assign( $default_tags );
}
}
?>