YView.class.php
15.5 KB
<?php/**
* 路由处理
*
* @name Framework_YView
* @package framework
* @version 0.2 (2012-12-14 17:14:29) <fei.hong@yoho.cn>
* @since 0.1 (2012-6-25) xiaoma
*/class Framework_YView {
/**
* 视图文件根目录
*
* @var string
*/
protected $_basePath = '';
/**
* 视图脚本存放目录
*
* @var string
*/
protected $_scriptPath = '';
/**
* 当前使用的分析器
*
* @var object
*/
protected $_viewParser;
/**
* 视图
*
* @var string
*/
protected $_viewname = '';
/**
* 模板变量
*
* @var array
*/
protected $_view = array();
/**
* 构造函数
*/
public function __construct()
{
$this->cleanVars();
}
/**
* 设置视图名称
*
* @param string $viewname
* @return Framework_YView
*/
public function setViewname($viewname)
{
$this->_viewname = $viewname;
return $this;
}
/**
* 设置视图根目录
*
* @param string $path (视图根目录)
* @return Framework_YView
*/
public function setBasePath($path)
{
$this->_basePath = $path;
return $this;
}
/**
* 设置视图脚本目录
*
* @param string $path (视图脚本目录 )
* @return Framework_YView
*/
public function setScriptPath($path)
{
$this->_scriptPath = $path;
return $this;
}
/**
* 设置视图的解析器
*
* @param Framework_YView_Parser $parser (视图解析器)
* @return Framework_YView
*/
public function setViewParser(Framework_YView_Parser $parser)
{
$this->_viewParser = new $parser();
return $this;
}
/**
* 指定模板变量
*
* @param string | array $key
* @param mixed $value
* @return Framework_YView
*/
public function assign($key, $value = null)
{
if (is_array($key))
{
$this->_view = array_merge($this->_view, $key);
}
else
{
$this->_view[$key] = $value;
}
return $this;
}
/**
* 清除所有模板变量
*
* @return Framework_YView
*/
public function cleanVars()
{
$context = Framework_YHttpRequest::instance();
$this->_vars = array(
'_ctx' => $context,
'_BASE_DIR' => $context->baseDir(),
'_BASE_URI' => $context->baseUri(),
'_REQUEST_URI' => $context->requestUri(),
);
return $this;
}
/**
* 部分渲染视图
*
* (直接包含方式, 不解析页面)
*
* @param string $viewname (视图名称)
* @param mixed $params (向视图传递的参数)
* @return string
* @since 0.2
*/
public function renderPartial($viewname = null, $params = null, $display = true)
{
$output = '';
if (null !== $viewname)
{
$viewname = $this->_basePath . $this->_scriptPath . DS . $viewname . '.php';
if (file_exists($viewname))
{
// 页面缓存
ob_start();
ob_implicit_flush(0);
if (is_array($params))
{
extract($params);
}
include $viewname;
// 获取并清空缓存
$output = ob_get_clean();
}
}
if ($display)
{
echo $output;
}
else
{
return $output;
}
}
/**
* 渲染视图并返回渲染结果
*
* @param string $viewname
* @param array $params
* @return string
* @since 0.2
*/
public function render($viewname = null, $params = null)
{
// 渲染之前执行
$this->beforeRender();
if (empty($viewname))
{
$viewname = $this->_viewname;
}
$viewname = $this->_basePath . $this->_scriptPath . DS . $viewname . '.php';
if (file_exists($viewname))
{
if (null === $params)
{
$params = $this->_view;
}
// 设置默认的视图解析器
if (is_null($this->_viewParser) || ! is_object($this->_viewParser))
{
$this->_viewParser = new Framework_YView_Parser($this->_basePath, $this->_scriptPath);
}
// 解析视图页面, 返回视图页面内容
$output = $this->_viewParser->assign($params)->parse($viewname);
}
else
{
$output = '';
}
// 渲染之后执行
$this->afterRender($output);
return $output;
}
/**
* 渲染之前调用
*
* 继承类可以覆盖此方法。
*/
protected function beforeRender() {}
/**
* 渲染之后调用
*
* 继承类可以覆盖此方法。
*
* @param string $output
*/
protected function afterRender(& $output) {}
}
/**
* 视图变量对象
*
* @version 0.1 2012-7-24
* @author xiaoma
* @name Framework_YView_Var
*/
class Framework_YView_Var
{
/**
* 当前对象
*
* @var Framework_YView_Var
*/
private static $instance = null ;
/**
* 返回对象
*
* @return Framework_YView_Var
*/
public static function getInstance ()
{
if (is_null(self::$instance))
{
self::$instance = new self();
}
return self::$instance;
}
/**
* 设置视图变量
*
* @param string $name
* @param mixed $value
*/
public function __set($name,$value)
{
$this->$name = $value;
}
/**
* 未定义的属性 返回null
*
* @param string $name
* @return null
*/
public function __get($name)
{
return null;
}
}
/**
* Framework_YView_Parser 类实现了视图的分析
*
* @package mvc
*/
class Framework_YView_Parser
{
/**
* 视图文件扩展名
*
* @var string
*/
protected $_extname = 'php';
/**
* 视图堆栈
*
* @var array
*/
private $_stacks = array();
/**
* 当前处理的视图
*
* @var int
*/
private $_current;
/**
* 视图变量
*
* @var array
*/
protected $_vars;
/**
* 视图文件所在目录
*
* @var string
*/
private $_viewBasePath;
/**
* 视图脚本文件所在目录
*
* @var string
*/
private $_viewScriptPath;
/**
* 变量对象
*
* @var Framework_YView_Var
*/
public $view;
/**
* 构造函数
*/
public function __construct($viewBasePath, $viewScriptPath)
{
$this->_viewBasePath = $viewBasePath;
$this->_viewScriptPath = $viewScriptPath;
$this->view = Framework_YView_Var::getInstance();
}
/**
* 设置分析器已经指定的变量
*
* @param array $vars
*
* @return Framework_YView_Parser
*/
public function assign(array $vars)
{
$this->_vars = $vars;
//将数组转换成对象 方便视图使用
foreach ($vars as $key => $val)
{
if (is_string($val))
{
$this->view->$key = strtr($val, array('<' => '<', '>' => '>',));
}
else
{
$this->view->$key= $val;
}
}
return $this;
}
/**
* 返回视图文件的扩展名
*
* @return string
*/
public function getExtName()
{
return $this->_extname;
}
/**
* 设置视图文件扩展名
*
* @param string $ext
* @since 0.2
*/
public function setExtName($ext)
{
$this->_extname = $ext;
}
/**
* 分析一个视图文件并返回结果
*
* @param string $filename
* @param string $view_id
* @param array $inherited_stack
*
* @return string
*/
public function parse($filename, $view_id = null, array $inherited_stack = null)
{
if (! $view_id)
{
$view_id = mt_rand();
}
$stack = array(
'id' => $view_id,
'contents' => '',
'extends' => '',
'blocks_stacks' => array(),
'blocks' => array(),
'blocks_config' => array(),
'nested_blocks' => array(),
);
array_push($this->_stacks, $stack);
$this->_current = count($this->_stacks) - 1;
unset($stack);
ob_start();
$this->_include($filename);
$stack = $this->_stacks[$this->_current];
$stack['contents'] = ob_get_clean();
// 如果有继承视图,则用继承视图中定义的块内容替换当前视图的块内容
if (is_array($inherited_stack))
{
foreach ($inherited_stack['blocks'] as $block_name => $contents)
{
if (isset($stack['blocks_config'][$block_name]))
{
switch (strtolower($stack['blocks_config'][$block_name]))
{
case 'append':
$stack['blocks'][$block_name] .= $contents;
break;
case 'replace':
default:
$stack['blocks'][$block_name] = $contents;
}
}
else
{
$stack['blocks'][$block_name] = $contents;
}
}
}
// 如果有嵌套 block,则替换内容
while (list($child, $parent) = array_pop($stack['nested_blocks']))
{
$stack['blocks'][$parent] = str_replace("%block_contents_placeholder_{$child}_{$view_id}%",
$stack['blocks'][$child], $stack['blocks'][$parent]
);
unset($stack['blocks'][$child]);
}
// 保存对当前视图堆栈的修改
$this->_stacks[$this->_current] = $stack;
if ($stack['extends'])
{
// 如果有当前视图是从某个视图继承的,则载入继承视图
$filename = "{$this->_viewBasePath}/{$stack['extends']}.$this->_extname";
return $this->parse($filename, $view_id, $this->_stacks[$this->_current]);
}
else
{
// 最后一个视图一定是没有 extends 的
$last = array_pop($this->_stacks);
foreach ($last['blocks'] as $block_name => $contents)
{
$last['contents'] = str_replace("%block_contents_placeholder_{$block_name}_{$last['id']}%",
$contents, $last['contents']
);
}
$this->_stacks = array();
return $last['contents'];
}
}
/**
* 视图的继承
*
* @param string $tplname
*
* @access public
*/
protected function _extends($tplname)
{
$this->_stacks[$this->_current]['extends'] = $tplname;
}
/**
* 开始定义一个区块
*
* @param string $block_name
* @param mixed $config
*
* @access public
*/
protected function _block($block_name, $config = null)
{
$stack = & $this->_stacks[$this->_current];
if (!empty($stack['blocks_stacks']))
{
// 如果存在嵌套的 block,则需要记录下嵌套的关系
$last = $stack['blocks_stacks'][count($stack['blocks_stacks']) - 1];
$stack['nested_blocks'][] = array($block_name, $last);
}
$this->_stacks[$this->_current]['blocks_config'][$block_name] = $config;
array_push($stack['blocks_stacks'], $block_name);
ob_start();
}
/**
* 结束一个区块
*
* @access public
*/
protected function _endblock()
{
$block_name = array_pop($this->_stacks[$this->_current]['blocks_stacks']);
$this->_stacks[$this->_current]['blocks'][$block_name] = ob_get_clean();
echo "%block_contents_placeholder_{$block_name}_{$this->_stacks[$this->_current]['id']}%";
}
/**
* 构造一个组件
*
* @param string $alias (组件路径)
* @param array $params (组件参数)
* @access public
*/
protected function _component($alias, $params = array(), $id = '')
{
$component = new Framework_YComponent($id);
$component->execute($alias, $params);
}
/**
* 载入一个视图片段
*
* @param string $element_name
* @param array $vars
*
* @access public
*/
protected function _widget($element_name, $vars = null)
{
$element_name = str_replace ( '_', DIRECTORY_SEPARATOR, $element_name );
$filename = "{$this->_viewBasePath}/widget/{$element_name}.{$this->_extname}";
$this->_include($filename, $vars);
}
/**
* 载入视图文件
*/
protected function _include($filename, $vars = null)
{
$this->_extname = pathinfo($filename, PATHINFO_EXTENSION);
if (is_array($vars))
{
extract($vars);
}
include $filename;
}
/**
* 引入CSS文件方法
*
* @param unknown_type $group_name
* @param array $styles
*/
protected function _css($group_name='',array $styles = null,$noEchoInGroup=false,$noload=false)
{
$minFile = C('APP.MinFile');
if ($minFile['open'] && $group_name != ''&&$this->_isCombinePage($group_name)&&!isset($_GET['debug']))
{
if(!$noEchoInGroup)
{
echo '<link href="'.$minFile['css'].$group_name.'&site='.$minFile["site"].'" media="screen" rel="stylesheet" type="text/css" />', PHP_EOL;
}
}
else
{
if(!$noload)
{
foreach ($styles as $style)
{
echo '<link href="'.$style.'" media="screen" rel="stylesheet" type="text/css" />', PHP_EOL;
}
}
}
// 压缩组合js,css配置自动生成
if (!$minFile['open']&&isset($_GET['gengroup']))
{
echo '<script type="text/javascript">var groupname_css = "'.$group_name.'"</script>', PHP_EOL;
}
}
/**
* 引入js文件方法
*
* @param unknown_type $group_name
* @param array $js
*/
protected function _js($group_name='',array $js = null,$noEchoInGroup=false,$noload=false)
{
$minFile = C('APP.MinFile');
if ($minFile['open'] && $group_name != ''&&$this->_isCombinePage($group_name)&&!isset($_GET['debug']))
{
if(!$noEchoInGroup)
{
echo '<script type="text/javascript" src="'.$minFile['js'].$group_name.'&site='.$minFile["site"].'"></script>', PHP_EOL;
}
}
else
{
if(!$noload)
{
foreach ($js as $s)
{
echo '<script type="text/javascript" src="',$s,'"></script>', PHP_EOL;
}
}
}
//压缩组合js,css配置自动生成
if (!$minFile['open']&&isset($_GET['gengroup']))
{
echo '<script type="text/javascript">var groupname_js = "'.$group_name.'"</script>', PHP_EOL;
echo '<script type="text/javascript" src="'.SITE_JS.'/group.js"></script>', PHP_EOL;
}
}
private function _isCombinePage($group_name)
{
$combinePage = C('APP.combinePage');
$isCombinePage = false;
foreach($combinePage as $val)
{
if($val==$group_name)
{
$isCombinePage = true;
}
};
return $isCombinePage;
}
}