Fixes #2912: Relative view files will be looked for under the directory containing the view currently being rendered

This commit is contained in:
Qiang Xue
2014-03-28 21:54:32 -04:00
parent 48383f9a19
commit 92bd71cd84
10 changed files with 77 additions and 76 deletions

View File

@@ -228,6 +228,7 @@ Yii Framework 2 Change Log
- Removed `yii\web\Controller::getCanonicalUrl`, use `yii\helpers\Url::canonical` instead.
- Chg #2691: Null parameters will not be included in the generated URLs by `UrlManager` (gonimar, qiangxue)
- Chg #2734: `FileCache::keyPrefix` defaults to empty string now (qiangxue)
_ Chg #2912: Relative view files will be looked for under the directory containing the view currently being rendered (qiangxue)
- Chg: Renamed `yii\jui\Widget::clientEventsMap` to `clientEventMap` (qiangxue)
- Chg: Renamed `ActiveRecord::getPopulatedRelations()` to `getRelatedRecords()` (qiangxue)
- Chg: Renamed `attributeName` and `className` to `targetAttribute` and `targetClass` for `UniqueValidator` and `ExistValidator` (qiangxue)

View File

@@ -289,7 +289,7 @@ class Controller extends Component implements ViewContextInterface
*
* If the layout name does not contain a file extension, it will use the default one `.php`.
*
* @param string $view the view name. Please refer to [[findViewFile()]] on how to specify a view name.
* @param string $view the view name.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* These parameters will not be available in the layout.
* @return string the rendering result.
@@ -367,17 +367,6 @@ class Controller extends Component implements ViewContextInterface
return $this->module->getViewPath() . DIRECTORY_SEPARATOR . $this->id;
}
/**
* Finds the view file based on the given view name.
* @param string $view the view name or the path alias of the view file. Please refer to [[render()]]
* on how to specify this parameter.
* @return string the view file path. Note that the file may not exist.
*/
public function findViewFile($view)
{
return $this->getViewPath() . DIRECTORY_SEPARATOR . $view;
}
/**
* Finds the applicable layout file.
* @param View $view the view object to render the layout file.

View File

@@ -98,7 +98,7 @@ class View extends Component
/**
* @var array the view files currently being rendered. There may be multiple view files being
* rendered at a moment because one may render a view file within another.
* rendered at a moment because one view may be rendered within another.
*/
private $_viewFiles = [];
@@ -127,13 +127,17 @@ class View extends Component
* The actual view file will be looked for under the [[Application::viewPath|view path]] of the application.
* - absolute path within current module (e.g. "/site/index"): the view name starts with a single slash.
* The actual view file will be looked for under the [[Module::viewPath|view path]] of [[module]].
* - resolving any other format will be performed via [[ViewContext::findViewFile()]].
* - relative view (e.g. "index"): the view name does not start with `@` or `/`. The corresponding view file will be
* looked for under the [[ViewContextInterface::getViewPath()|view path]] of the view `$context`.
* If `$context` is not given, it will be looked for under the directory containing the view currently
* being rendered (i.e., this happens when rendering a view within another view).
*
* @param string $view the view name. Please refer to [[Controller::findViewFile()]]
* and [[Widget::findViewFile()]] on how to specify this parameter.
* @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file.
* @param object $context the context that the view should use for rendering the view. If null,
* existing [[context]] will be used.
* @param object $context the context to be assigned to the view and can later be accessed via [[context]]
* in the view. If the context implements [[ViewContextInterface]], it may also be used to locate
* the view file corresponding to a relative view name.
* @return string the rendering result
* @throws InvalidParamException if the view cannot be resolved or the view file does not exist.
* @see renderFile()
@@ -148,10 +152,12 @@ class View extends Component
* Finds the view file based on the given view name.
* @param string $view the view name or the path alias of the view file. Please refer to [[render()]]
* on how to specify this parameter.
* @param object $context the context that the view should be used to search the view file. If null,
* existing [[context]] will be used.
* @param object $context the context to be assigned to the view and can later be accessed via [[context]]
* in the view. If the context implements [[ViewContextInterface]], it may also be used to locate
* the view file corresponding to a relative view name.
* @return string the view file path. Note that the file may not exist.
* @throws InvalidCallException if [[context]] is required and invalid.
* @throws InvalidCallException if a relative view name is given while there is no active context to
* determine the corresponding view file.
*/
protected function findViewFile($view, $context = null)
{
@@ -168,16 +174,12 @@ class View extends Component
} else {
throw new InvalidCallException("Unable to locate view file for view '$view': no active controller.");
}
} elseif ($context instanceof ViewContextInterface) {
$file = $context->getViewPath() . DIRECTORY_SEPARATOR . $view;
} elseif (($currentViewFile = $this->getViewFile()) !== false) {
$file = dirname($currentViewFile) . DIRECTORY_SEPARATOR . $view;
} else {
// context required
if ($context === null) {
$context = $this->context;
}
if ($context instanceof ViewContextInterface) {
$file = $context->findViewFile($view);
} else {
throw new InvalidCallException("Unable to locate view file for view '$view': no active view context.");
}
throw new InvalidCallException("Unable to resolve view file for view '$view': no active view context.");
}
if (pathinfo($file, PATHINFO_EXTENSION) !== '') {
@@ -213,6 +215,7 @@ class View extends Component
public function renderFile($viewFile, $params = [], $context = null)
{
$viewFile = Yii::getAlias($viewFile);
if ($this->theme !== null) {
$viewFile = $this->theme->applyTo($viewFile);
}

View File

@@ -10,7 +10,7 @@ namespace yii\base;
/**
* ViewContextInterface is the interface that should implemented by classes who want to support relative view names.
*
* The method [[findViewFile()]] should be implemented to convert a relative view name into a file path.
* The method [[getViewPath()]] should be implemented to return the view path that may be prefixed to a relative view name.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0
@@ -18,9 +18,7 @@ namespace yii\base;
interface ViewContextInterface
{
/**
* Finds the view file corresponding to the specified relative view name.
* @param string $view a relative view name. The name does NOT start with a slash.
* @return string the view file path. Note that the file may not exist.
* @return string the view path that may be prefixed to a relative view name.
*/
public function findViewFile($view);
public function getViewPath();
}

View File

@@ -173,7 +173,7 @@ class Widget extends Component implements ViewContextInterface
*
* If the view name does not contain a file extension, it will use the default one `.php`.
* @param string $view the view name. Please refer to [[findViewFile()]] on how to specify a view name.
* @param string $view the view name.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidParamException if the view file does not exist.
@@ -206,15 +206,4 @@ class Widget extends Component implements ViewContextInterface
return dirname($class->getFileName()) . DIRECTORY_SEPARATOR . 'views';
}
/**
* Finds the view file based on the given view name.
* File will be searched under [[viewPath]] directory.
* @param string $view the view name.
* @return string the view file path. Note that the file may not exist.
*/
public function findViewFile($view)
{
return $this->getViewPath() . DIRECTORY_SEPARATOR . $view;
}
}

View File

@@ -38,11 +38,6 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont
* @event \yii\base\MailEvent an event raised right after send.
*/
const EVENT_AFTER_SEND = 'afterSend';
/**
* @var string directory containing view files for this email messages.
* This can be specified as an absolute path or path alias.
*/
public $viewPath = '@app/mail';
/**
* @var string|boolean HTML layout view name. This is the layout used to render HTML mail body.
* The property can take the following values:
@@ -104,6 +99,10 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont
* @var \yii\base\View|array view instance or its array configuration.
*/
private $_view = [];
/**
* @var string the directory containing view files for composing mail messages.
*/
private $_viewPath;
/**
* @param array|View $view view instance or its array configuration that will be used to
@@ -159,7 +158,7 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont
* The view to be rendered can be specified in one of the following formats:
*
* - path alias (e.g. "@app/mail/contact");
* - a relative view name (e.g. "contact"): the actual view file will be resolved by [[findViewFile()]]
* - a relative view name (e.g. "contact") located under [[viewPath]].
*
* @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file.
* @return MessageInterface message instance.
@@ -319,14 +318,24 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont
}
/**
* Finds the view file corresponding to the specified relative view name.
* This method will return the view file by prefixing the view name with [[viewPath]].
* @param string $view a relative view name. The name does NOT start with a slash.
* @return string the view file path. Note that the file may not exist.
* @return string the directory that contains the view files for composing mail messages
* Defaults to '@app/mail'.
*/
public function findViewFile($view)
public function getViewPath()
{
return Yii::getAlias($this->viewPath) . DIRECTORY_SEPARATOR . $view;
if ($this->_viewPath === null) {
$this->setViewPath('@app/mail');
}
return $this->_viewPath;
}
/**
* @param string $path the directory that contains the view files for composing mail messages
* This can be specified as an absolute path or a path alias.
*/
public function setViewPath($path)
{
$this->_viewPath = Yii::getAlias($path);
}
/**