diff options
Diffstat (limited to 'framework/web/renderers')
| -rw-r--r-- | framework/web/renderers/CPradoViewRenderer.php | 305 | ||||
| -rw-r--r-- | framework/web/renderers/CViewRenderer.php | 97 |
2 files changed, 402 insertions, 0 deletions
diff --git a/framework/web/renderers/CPradoViewRenderer.php b/framework/web/renderers/CPradoViewRenderer.php new file mode 100644 index 0000000..343a78b --- /dev/null +++ b/framework/web/renderers/CPradoViewRenderer.php @@ -0,0 +1,305 @@ +<?php +/** + * CPradoViewRenderer class file. + * + * @author Steve Heyns http://customgothic.com/ + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 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> + * @version $Id: CPradoViewRenderer.php 2799 2011-01-01 19:31:13Z qiang.xue $ + * @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]); + } + else if(strpos($str,'</com:')===0) // closing component tag + $this->_output.=$this->processEndWidget($match[3][0],$match[2][1]); + else if(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]); + } + else if(strpos($str,'</cache:')===0) // closing cache tag + $this->_output.=$this->processEndCache($match[3][0],$match[2][1]); + else if(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]); + } + else if(strpos($str,'</clip:')===0) // closing clip tag + $this->_output.=$this->processEndClip($match[3][0],$match[2][1]); + else if(strpos($str,'<%=')===0) // expression + $this->_output.=$this->processExpression($match[1][0],$match[1][1]); + else if(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))); + } +} diff --git a/framework/web/renderers/CViewRenderer.php b/framework/web/renderers/CViewRenderer.php new file mode 100644 index 0000000..093c3bb --- /dev/null +++ b/framework/web/renderers/CViewRenderer.php @@ -0,0 +1,97 @@ +<?php +/** + * CViewRenderer class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CViewRenderer is the base class for view renderer classes. + * + * A view renderer is an application component that renders views written + * in a customized syntax. + * + * Once installing a view renderer as a 'viewRenderer' application component, + * the normal view rendering process will be intercepted by the renderer. + * The renderer will first parse the source view file and then render the + * the resulting view file. + * + * Parsing results are saved as temporary files that may be stored + * under the application runtime directory or together with the source view file. + * + * @author Steve Heyns http://customgothic.com/ + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CViewRenderer.php 3515 2011-12-28 12:29:24Z mdomba $ + * @package system.web.renderers + * @since 1.0 + */ +abstract class CViewRenderer extends CApplicationComponent implements IViewRenderer +{ + /** + * @var boolean whether to store the parsing results in the application's + * runtime directory. Defaults to true. If false, the parsing results will + * be saved as files under the same directory as the source view files and the + * file names will be the source file names appended with letter 'c'. + */ + public $useRuntimePath=true; + /** + * @var integer the chmod permission for temporary directories and files + * generated during parsing. Defaults to 0755 (owner rwx, group rx and others rx). + */ + public $filePermission=0755; + /** + * @var string the extension name of the view file. Defaults to '.php'. + */ + public $fileExtension='.php'; + + /** + * Parses the source view file and saves the results as another file. + * @param string $sourceFile the source view file path + * @param string $viewFile the resulting view file path + */ + abstract protected function generateViewFile($sourceFile,$viewFile); + + /** + * Renders a view file. + * This method is required by {@link IViewRenderer}. + * @param CBaseController $context the controller or widget who is rendering the view file. + * @param string $sourceFile the view file path + * @param mixed $data the data to be passed to the view + * @param boolean $return whether the rendering result should be returned + * @return mixed the rendering result, or null if the rendering result is not needed. + */ + public function renderFile($context,$sourceFile,$data,$return) + { + if(!is_file($sourceFile) || ($file=realpath($sourceFile))===false) + throw new CException(Yii::t('yii','View file "{file}" does not exist.',array('{file}'=>$sourceFile))); + $viewFile=$this->getViewFile($sourceFile); + if(@filemtime($sourceFile)>@filemtime($viewFile)) + { + $this->generateViewFile($sourceFile,$viewFile); + @chmod($viewFile,$this->filePermission); + } + return $context->renderInternal($viewFile,$data,$return); + } + + /** + * Generates the resulting view file path. + * @param string $file source view file path + * @return string resulting view file path + */ + protected function getViewFile($file) + { + if($this->useRuntimePath) + { + $crc=sprintf('%x', crc32(get_class($this).Yii::getVersion().dirname($file))); + $viewFile=Yii::app()->getRuntimePath().DIRECTORY_SEPARATOR.'views'.DIRECTORY_SEPARATOR.$crc.DIRECTORY_SEPARATOR.basename($file); + if(!is_file($viewFile)) + @mkdir(dirname($viewFile),$this->filePermission,true); + return $viewFile; + } + else + return $file.'c'; + } +} |
