1
0
www.mikescher.com/framework/web/renderers/CPradoViewRenderer.php

305 lines
8.9 KiB
PHP

<?php
/**
* CPradoViewRenderer class file.
*
* @author Steve Heyns http://customgothic.com/
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008-2013 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
/**
* CPradoViewRenderer implements a view renderer that allows users to use a template syntax similar to PRADO templates.
*
* To use CPradoViewRenderer, configure it as an application component named "viewRenderer" in the application configuration:
* <pre>
* array(
* 'components'=>array(
* ......
* 'viewRenderer'=>array(
* 'class'=>'CPradoViewRenderer',
* ),
* ),
* )
* </pre>
*
* CPradoViewRenderer allows you to write view files with the following syntax:
* <pre>
* // PHP tags:
* <%= expression %>
* // <?php echo expression ?>
* <% statement %>
* // <?php statement ?></li>
*
* // component tags:
* <com:WigetClass name1="value1" name2='value2' name3={value3} >
* // <?php $this->beginWidget('WigetClass',
* // array('name1'=>"value1", 'name2'=>'value2', 'name3'=>value3)); ?>
* </com:WigetClass >
* // <?php $this->endWidget('WigetClass'); ?>
* <com:WigetClass name1="value1" name2='value2' name3={value3} />
* // <?php $this->widget('WigetClass',
* // array('name1'=>"value1", 'name2'=>'value2', 'name3'=>value3)); ?>
*
* // cache tags:
* <cache:fragmentID name1="value1" name2='value2' name3={value3} >
* // <?php if($this->beginCache('fragmentID',
* // array('name1'=>"value1", 'name2'=>'value2', 'name3'=>value3))): ?>
* </cache:fragmentID >
* // <?php $this->endCache('fragmentID'); endif; ?>
*
* // clip tags:
* <clip:clipID >
* // <?php $this->beginClip('clipID'); ?>
* </clip:clipID >
* // <?php $this->endClip('clipID'); ?>
*
* // comment tags:
* <!--- comments --->
* // the whole tag will be stripped off
* </pre>
*
* @author Steve Heyns http://customgothic.com/
* @author Qiang Xue <qiang.xue@gmail.com>
* @package system.web.renderers
* @since 1.0
*/
class CPradoViewRenderer extends CViewRenderer
{
private $_input;
private $_output;
private $_sourceFile;
/**
* Parses the source view file and saves the results as another file.
* This method is required by the parent class.
* @param string $sourceFile the source view file path
* @param string $viewFile the resulting view file path
*/
protected function generateViewFile($sourceFile,$viewFile)
{
static $regexRules=array(
'<%=?\s*(.*?)\s*%>', // PHP statements or expressions
'<\/?(com|cache|clip):([\w\.]+)\s*((?:\s*\w+\s*=\s*\'.*?(?<!\\\\)\'|\s*\w+\s*=\s*".*?(?<!\\\\)"|\s*\w+\s*=\s*\{.*?\})*)\s*\/?>', // component tags
'<!---.*?--->', // template comments
);
$this->_sourceFile=$sourceFile;
$this->_input=file_get_contents($sourceFile);
$n=preg_match_all('/'.implode('|',$regexRules).'/msS',$this->_input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
$textStart=0;
$this->_output="<?php /* source file: $sourceFile */ ?>\n";
for($i=0;$i<$n;++$i)
{
$match=&$matches[$i];
$str=$match[0][0];
$matchStart=$match[0][1];
$matchEnd=$matchStart+strlen($str)-1;
if($matchStart>$textStart)
$this->_output.=substr($this->_input,$textStart,$matchStart-$textStart);
$textStart=$matchEnd+1;
if(strpos($str,'<com:')===0) // opening component tag
{
$type=$match[3][0];
if($str[strlen($str)-2]!=='/') // open tag
$this->_output.=$this->processBeginWidget($type,$match[4][0],$match[2][1]);
else
$this->_output.=$this->processWidget($type,$match[4][0],$match[2][1]);
}
elseif(strpos($str,'</com:')===0) // closing component tag
$this->_output.=$this->processEndWidget($match[3][0],$match[2][1]);
elseif(strpos($str,'<cache:')===0) // opening cache tag
{
$id=$match[3][0];
if($str[strlen($str)-2]!=='/') // open tag
$this->_output.=$this->processBeginCache($id,$match[4][0],$match[2][1]);
else
$this->_output.=$this->processCache($id,$match[4][0],$match[2][1]);
}
elseif(strpos($str,'</cache:')===0) // closing cache tag
$this->_output.=$this->processEndCache($match[3][0],$match[2][1]);
elseif(strpos($str,'<clip:')===0) // opening clip tag
{
$id=$match[3][0];
if($str[strlen($str)-2]!=='/') // open tag
$this->_output.=$this->processBeginClip($id,$match[4][0],$match[2][1]);
else
$this->_output.=$this->processClip($id,$match[4][0],$match[2][1]);
}
elseif(strpos($str,'</clip:')===0) // closing clip tag
$this->_output.=$this->processEndClip($match[3][0],$match[2][1]);
elseif(strpos($str,'<%=')===0) // expression
$this->_output.=$this->processExpression($match[1][0],$match[1][1]);
elseif(strpos($str,'<%')===0) // statement
$this->_output.=$this->processStatement($match[1][0],$match[1][1]);
}
if($textStart<strlen($this->_input))
$this->_output.=substr($this->_input,$textStart);
file_put_contents($viewFile,$this->_output);
}
/*
* @param string $type type
* @param string $attributes attributes
* @param string $offset offset
*/
private function processWidget($type,$attributes,$offset)
{
$attrs=$this->processAttributes($attributes);
if(empty($attrs))
return $this->generatePhpCode("\$this->widget('$type');",$offset);
else
return $this->generatePhpCode("\$this->widget('$type', array($attrs));",$offset);
}
/*
* @param string $type type
* @param string $attributes attributes
* @param string $offset offset
*/
private function processBeginWidget($type,$attributes,$offset)
{
$attrs=$this->processAttributes($attributes);
if(empty($attrs))
return $this->generatePhpCode("\$this->beginWidget('$type');",$offset);
else
return $this->generatePhpCode("\$this->beginWidget('$type', array($attrs));",$offset);
}
/*
* @param string $type type
* @param string $offset offset
*/
private function processEndWidget($type,$offset)
{
return $this->generatePhpCode("\$this->endWidget('$type');",$offset);
}
/*
* @param string $id id
* @param string $attributes attributes
* @param string $offset offset
*/
private function processCache($id,$attributes,$offset)
{
return $this->processBeginCache($id,$attributes,$offset) . $this->processEndCache($id,$offset);
}
/*
* @param string $id id
* @param string $attributes attributes
* @param string $offset offset
*/
private function processBeginCache($id,$attributes,$offset)
{
$attrs=$this->processAttributes($attributes);
if(empty($attrs))
return $this->generatePhpCode("if(\$this->beginCache('$id')):",$offset);
else
return $this->generatePhpCode("if(\$this->beginCache('$id', array($attrs))):",$offset);
}
/*
* @param string $id id
* @param string $offset offset
*/
private function processEndCache($id,$offset)
{
return $this->generatePhpCode("\$this->endCache('$id'); endif;",$offset);
}
/*
* @param string $id id
* @param string $attributes attributes
* @param string $offset offset
*/
private function processClip($id,$attributes,$offset)
{
return $this->processBeginClip($id,$attributes,$offset) . $this->processEndClip($id,$offset);
}
/*
* @param string $id id
* @param string $attributes attributes
* @param string $offset offset
*/
private function processBeginClip($id,$attributes,$offset)
{
$attrs=$this->processAttributes($attributes);
if(empty($attrs))
return $this->generatePhpCode("\$this->beginClip('$id');",$offset);
else
return $this->generatePhpCode("\$this->beginClip('$id', array($attrs));",$offset);
}
/*
* @param string $id id
* @param string $offset offset
*/
private function processEndClip($id,$offset)
{
return $this->generatePhpCode("\$this->endClip('$id');",$offset);
}
/*
* @param string $expression expression
* @param string $offset offset
*/
private function processExpression($expression,$offset)
{
return $this->generatePhpCode('echo '.$expression,$offset);
}
/*
* @param string $statement statement
* @param string $offset offset
*/
private function processStatement($statement,$offset)
{
return $this->generatePhpCode($statement,$offset);
}
/*
* @param string $code code
* @param string $offset offset
*/
private function generatePhpCode($code,$offset)
{
$line=$this->getLineNumber($offset);
$code=str_replace('__FILE__',var_export($this->_sourceFile,true),$code);
return "<?php /* line $line */ $code ?>";
}
/*
* @param string $str str
*/
private function processAttributes($str)
{
static $pattern='/(\w+)\s*=\s*(\'.*?(?<!\\\\)\'|".*?(?<!\\\\)"|\{.*?\})/msS';
$attributes=array();
$n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER);
for($i=0;$i<$n;++$i)
{
$match=&$matches[$i];
$name=$match[1];
$value=$match[2];
if($value[0]==='{')
$attributes[]="'$name'=>".str_replace('__FILE__',$this->_sourceFile,substr($value,1,-1));
else
$attributes[]="'$name'=>$value";
}
return implode(', ',$attributes);
}
/*
* @param string $offset offset
*/
private function getLineNumber($offset)
{
return count(explode("\n",substr($this->_input,0,$offset)));
}
}