Commit 92bd71cd by Qiang Xue

Fixes #2912: Relative view files will be looked for under the directory…

Fixes #2912: Relative view files will be looked for under the directory containing the view currently being rendered
parent 48383f9a
......@@ -372,6 +372,20 @@ echo $this->render('_profile', [
]);
```
When you call `render()` to render a partial in a current view, you may use different formats to refer to the partial.
The most commonly used format is the so-called relative view name which is as shown in the above example.
The partial view file is relative to the directory containing the current view. If the partial is located under
a subdirectory, you should include the subdirectory name in the view name, e.g., `public/_profile`.
You may use path alias to specify a view, too. For example, `@app/views/common/_profile`.
And you may also use the so-called absolute view names, e.g., `/user/_profile`, `//user/_profile`.
An absolute view name starts with a single slashes or double slashes. If it starts with a single slash,
the view file will be looked for under the view path of the currently active module. Otherwise, it will
will be looked for under the application view path.
### Accessing context
Views are generally used either by controller or by widget. In both cases the object that called view rendering is
......
......@@ -268,13 +268,11 @@ class ApiRenderer extends BaseApiRenderer implements 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.
* @inheritdoc
*/
public function findViewFile($view)
public function getViewPath()
{
return Yii::getAlias('@yii/apidoc/templates/html/views/' . $view);
return Yii::getAlias('@yii/apidoc/templates/html/views');
}
/**
......
......@@ -7,7 +7,7 @@ $extensions = $panel->getExtensions();
<h1>Configuration</h1>
<?php
echo $this->render('panels/config/table', [
echo $this->render('table', [
'caption' => 'Application Configuration',
'values' => [
'Yii Version' => $panel->data['application']['yii'],
......@@ -18,13 +18,13 @@ echo $this->render('panels/config/table', [
]);
if (!empty($extensions)) {
echo $this->render('panels/config/table', [
echo $this->render('table', [
'caption' => 'Installed Extensions',
'values' => $extensions,
]);
}
echo $this->render('panels/config/table', [
echo $this->render('table', [
'caption' => 'PHP Configuration',
'values' => [
'PHP Version' => $panel->data['php']['version'],
......
......@@ -11,27 +11,27 @@ echo Tabs::widget([
'items' => [
[
'label' => 'Parameters',
'content' => $this->render('panels/request/table', ['caption' => 'Routing', 'values' => ['Route' => $panel->data['route'], 'Action' => $panel->data['action'], 'Parameters' => $panel->data['actionParams']]])
. $this->render('panels/request/table', ['caption' => '$_GET', 'values' => $panel->data['GET']])
. $this->render('panels/request/table', ['caption' => '$_POST', 'values' => $panel->data['POST']])
. $this->render('panels/request/table', ['caption' => '$_FILES', 'values' => $panel->data['FILES']])
. $this->render('panels/request/table', ['caption' => '$_COOKIE', 'values' => $panel->data['COOKIE']])
. $this->render('panels/request/table', ['caption' => 'Request Body', 'values' => $panel->data['requestBody']]),
'content' => $this->render('table', ['caption' => 'Routing', 'values' => ['Route' => $panel->data['route'], 'Action' => $panel->data['action'], 'Parameters' => $panel->data['actionParams']]])
. $this->render('table', ['caption' => '$_GET', 'values' => $panel->data['GET']])
. $this->render('table', ['caption' => '$_POST', 'values' => $panel->data['POST']])
. $this->render('table', ['caption' => '$_FILES', 'values' => $panel->data['FILES']])
. $this->render('table', ['caption' => '$_COOKIE', 'values' => $panel->data['COOKIE']])
. $this->render('table', ['caption' => 'Request Body', 'values' => $panel->data['requestBody']]),
'active' => true,
],
[
'label' => 'Headers',
'content' => $this->render('panels/request/table', ['caption' => 'Request Headers', 'values' => $panel->data['requestHeaders']])
. $this->render('panels/request/table', ['caption' => 'Response Headers', 'values' => $panel->data['responseHeaders']])
'content' => $this->render('table', ['caption' => 'Request Headers', 'values' => $panel->data['requestHeaders']])
. $this->render('table', ['caption' => 'Response Headers', 'values' => $panel->data['responseHeaders']])
],
[
'label' => 'Session',
'content' => $this->render('panels/request/table', ['caption' => '$_SESSION', 'values' => $panel->data['SESSION']])
. $this->render('panels/request/table', ['caption' => 'Flashes', 'values' => $panel->data['flashes']])
'content' => $this->render('table', ['caption' => '$_SESSION', 'values' => $panel->data['SESSION']])
. $this->render('table', ['caption' => 'Flashes', 'values' => $panel->data['flashes']])
],
[
'label' => '$_SERVER',
'content' => $this->render('panels/request/table', ['caption' => '$_SERVER', 'values' => $panel->data['SERVER']]),
'content' => $this->render('table', ['caption' => '$_SERVER', 'values' => $panel->data['SERVER']]),
],
],
]);
......@@ -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)
......
......@@ -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.
......@@ -368,17 +368,6 @@ class Controller extends Component implements ViewContextInterface
}
/**
* 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.
* @return string|boolean the layout file path, or false if layout is not needed.
......
......@@ -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);
}
......
......@@ -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();
}
......@@ -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;
}
}
......@@ -39,11 +39,6 @@ abstract class BaseMailer extends Component implements MailerInterface, ViewCont
*/
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 getViewPath()
{
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 findViewFile($view)
public function setViewPath($path)
{
return Yii::getAlias($this->viewPath) . DIRECTORY_SEPARATOR . $view;
$this->_viewPath = Yii::getAlias($path);
}
/**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment