diff --git a/framework/base/Application.php b/framework/base/Application.php index f64e352..40e8437 100644 --- a/framework/base/Application.php +++ b/framework/base/Application.php @@ -359,6 +359,15 @@ class Application extends Module } /** + * Returns the view renderer. + * @return ViewRenderer the view renderer used by this application. + */ + public function getViewRenderer() + { + return $this->getComponent('viewRenderer'); + } + + /** * Sets default path aliases. */ public function registerDefaultAliases() diff --git a/framework/base/View.php b/framework/base/View.php index dccfb26..cd6e070 100644 --- a/framework/base/View.php +++ b/framework/base/View.php @@ -153,6 +153,59 @@ class View extends Component } /** + * Renders a view file. + * + * @param string $viewFile view file path + * @param array $data data to be extracted and made available to the view + * @param boolean $return whether the rendering result should be returned instead of being echoed + * @return string the rendering result. Null if the rendering result is not required. + * @throws CException if the view file does not exist + */ + public function renderFile($viewFile, $data = null, $return = false) + { + $widgetCount = count($this->_widgetStack); + if (($renderer = Yii::$application->getViewYii::app()->getViewRenderer()) !== null && $renderer->fileExtension === '.' . CFileHelper::getExtension($viewFile)) { + $content = $renderer->renderFile($this, $viewFile, $data, $return); + } else { + $content = $this->renderInternal($viewFile, $data, $return); + } + if (count($this->_widgetStack) === $widgetCount) { + return $content; + } else { + $widget = end($this->_widgetStack); + throw new CException(Yii::t('yii', '{controller} contains improperly nested widget tags in its view "{view}". A {widget} widget does not have an endWidget() call.', + array('{controller}' => get_class($this), '{view}' => $viewFile, '{widget}' => get_class($widget)))); + } + } + + /** + * Renders a view file. + * This method includes the view file as a PHP script + * and captures the display result if required. + * @param string $_viewFile_ view file + * @param array $_data_ data to be extracted and made available to the view file + * @param boolean $_return_ whether the rendering result should be returned as a string + * @return string the rendering result. Null if the rendering result is not required. + */ + public function renderInternal($_viewFile_, $_data_ = null, $_return_ = false) + { + // we use special variable names here to avoid conflict when extracting data + if (is_array($_data_)) { + extract($_data_, EXTR_PREFIX_SAME, 'data'); + } else { + $data = $_data_; + } + if ($_return_) { + ob_start(); + ob_implicit_flush(false); + require($_viewFile_); + return ob_get_clean(); + } else { + require($_viewFile_); + } + } + + /** * Creates a widget. * This method will use [[Yii::createObject()]] to create the widget. * @param string $class the widget class name or path alias diff --git a/framework/base/ViewRenderer.php b/framework/base/ViewRenderer.php new file mode 100644 index 0000000..4044edf --- /dev/null +++ b/framework/base/ViewRenderer.php @@ -0,0 +1,78 @@ + $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'; + } + } +}