Commit 119f0f01 by Carsten Brandt

Merge branch 'master' of github.com:yiisoft/yii2

* 'master' of github.com:yiisoft/yii2: Refactored filter error display for GridView. Fixes #3008: Added `Html::errorSummary()`
parents fe14f0c5 c15aceb0
...@@ -21,6 +21,7 @@ Yii Framework 2 Change Log ...@@ -21,6 +21,7 @@ Yii Framework 2 Change Log
- Bug #3204: `yii\di\Container` did not handle the `$config` parameter well in case when it does not have a default value (qiangxue) - Bug #3204: `yii\di\Container` did not handle the `$config` parameter well in case when it does not have a default value (qiangxue)
- Bug #3216: Fixed the bug that `yii.activeForm.destroy()` did not remove `submit` event handlers (qiangxue) - Bug #3216: Fixed the bug that `yii.activeForm.destroy()` did not remove `submit` event handlers (qiangxue)
- Enh #2837: Error page now shows arguments in stack trace method calls (samdark) - Enh #2837: Error page now shows arguments in stack trace method calls (samdark)
- Enh #3008: Added `Html::errorSummary()` (qiangxue)
- Enh #3088: The debug and gii modules will manage their own URL rules now (hiltonjanfield, qiangxue) - Enh #3088: The debug and gii modules will manage their own URL rules now (hiltonjanfield, qiangxue)
- Enh #3103: debugger panel is now not displayed when printing a page (githubjeka) - Enh #3103: debugger panel is now not displayed when printing a page (githubjeka)
- Enh #3108: Added `yii\debug\Module::enableDebugLogs` to disable logging debug logs by default (qiangxue) - Enh #3108: Added `yii\debug\Module::enableDebugLogs` to disable logging debug logs by default (qiangxue)
......
...@@ -46,7 +46,7 @@ abstract class ErrorHandler extends Component ...@@ -46,7 +46,7 @@ abstract class ErrorHandler extends Component
/** /**
* Register this errorhandler * Register this error handler
*/ */
public function register() public function register()
{ {
......
...@@ -141,16 +141,22 @@ class DataColumn extends Column ...@@ -141,16 +141,22 @@ class DataColumn extends Column
{ {
if (is_string($this->filter)) { if (is_string($this->filter)) {
return $this->filter; return $this->filter;
} elseif ($this->filter !== false && $this->grid->filterModel instanceof Model && }
$this->attribute !== null && $this->grid->filterModel->isAttributeActive($this->attribute)) {
if ($this->grid->filterModel->hasErrors($this->attribute)) { $model = $this->grid->filterModel;
Html::addCssClass($this->filterOptions, 'has-error');
if ($this->filter !== false && $model instanceof Model && $this->attribute !== null && $model->isAttributeActive($this->attribute)) {
if ($model->hasErrors($this->attribute)) {
Html::addCssClass($this->filterOptions, 'has-error');
$error = Html::error($model, $this->attribute, $this->grid->filterErrorOptions);
} else {
$error = '';
} }
if (is_array($this->filter)) { if (is_array($this->filter)) {
$options = array_merge(['prompt' => ''], $this->filterInputOptions); $options = array_merge(['prompt' => ''], $this->filterInputOptions);
return Html::activeDropDownList($this->grid->filterModel, $this->attribute, $this->filter, $options); return Html::activeDropDownList($model, $this->attribute, $this->filter, $options) . ' ' . $error;
} else { } else {
return Html::activeTextInput($this->grid->filterModel, $this->attribute, $this->filterInputOptions); return Html::activeTextInput($model, $this->attribute, $this->filterInputOptions) . ' ' . $error;
} }
} else { } else {
return parent::renderFilterCellContent(); return parent::renderFilterCellContent();
......
...@@ -15,7 +15,6 @@ use yii\helpers\Url; ...@@ -15,7 +15,6 @@ use yii\helpers\Url;
use yii\helpers\Html; use yii\helpers\Html;
use yii\helpers\Json; use yii\helpers\Json;
use yii\widgets\BaseListView; use yii\widgets\BaseListView;
use yii\helpers\ArrayHelper;
use yii\base\Model; use yii\base\Model;
/** /**
...@@ -142,6 +141,9 @@ class GridView extends BaseListView ...@@ -142,6 +141,9 @@ class GridView extends BaseListView
* Both "format" and "label" are optional. They will take default values if absent. * Both "format" and "label" are optional. They will take default values if absent.
*/ */
public $columns = []; public $columns = [];
/**
* @var string the HTML display when the content of a cell is empty
*/
public $emptyCell = ' '; public $emptyCell = ' ';
/** /**
* @var \yii\base\Model the model that keeps the user-entered filter data. When this property is set, * @var \yii\base\Model the model that keeps the user-entered filter data. When this property is set,
...@@ -161,6 +163,9 @@ class GridView extends BaseListView ...@@ -161,6 +163,9 @@ class GridView extends BaseListView
* as GET parameters to this URL. * as GET parameters to this URL.
*/ */
public $filterUrl; public $filterUrl;
/**
* @var string additional jQuery selector for selecting filter input fields
*/
public $filterSelector; public $filterSelector;
/** /**
* @var string whether the filters should be displayed in the grid view. Valid values include: * @var string whether the filters should be displayed in the grid view. Valid values include:
...@@ -175,18 +180,29 @@ class GridView extends BaseListView ...@@ -175,18 +180,29 @@ class GridView extends BaseListView
* @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered. * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
*/ */
public $filterRowOptions = ['class' => 'filters']; public $filterRowOptions = ['class' => 'filters'];
/**
* @var array the options for rendering the filter error summary.
* Please refer to [[Html::errorSummary()]] for more details about how to specify the options.
* @see renderErrors()
*/
public $filterErrorSummaryOptions = ['class' => 'error-summary'];
/**
* @var array the options for rendering every filter error message.
* This is mainly used by [[Html::error()]] when rendering an error message next to every filter input field.
*/
public $filterErrorOptions = ['class' => 'help-block'];
/** /**
* @var string the layout that determines how different sections of the list view should be organized. * @var string the layout that determines how different sections of the list view should be organized.
* The following tokens will be replaced with the corresponding section contents: * The following tokens will be replaced with the corresponding section contents:
* *
* - `{summary}`: the summary section. See [[renderSummary()]]. * - `{summary}`: the summary section. See [[renderSummary()]].
* - `{errors}`: the filter model errors. See [[renderErrors()]]. * - `{errors}`: the filter model error summary. See [[renderErrors()]].
* - `{items}`: the list items. See [[renderItems()]]. * - `{items}`: the list items. See [[renderItems()]].
* - `{sorter}`: the sorter. See [[renderSorter()]]. * - `{sorter}`: the sorter. See [[renderSorter()]].
* - `{pager}`: the pager. See [[renderPager()]]. * - `{pager}`: the pager. See [[renderPager()]].
*/ */
public $layout = "{summary}\n{errors}\n{items}\n{pager}"; public $layout = "{summary}\n{items}\n{pager}";
/** /**
* Initializes the grid view. * Initializes the grid view.
...@@ -233,12 +249,15 @@ class GridView extends BaseListView ...@@ -233,12 +249,15 @@ class GridView extends BaseListView
public function renderErrors() public function renderErrors()
{ {
if ($this->filterModel instanceof Model && $this->filterModel->hasErrors()) { if ($this->filterModel instanceof Model && $this->filterModel->hasErrors()) {
return Html::tag('div', Html::ul($this->filterModel->getFirstErrors(), ['class' => 'help-block']), ['class' => 'has-error']); return Html::errorSummary($this->filterModel, $this->filterErrorSummaryOptions);
} else { } else {
return ''; return '';
} }
} }
/**
* @inheritdoc
*/
public function renderSection($name) public function renderSection($name)
{ {
switch ($name) { switch ($name) {
......
...@@ -1032,6 +1032,46 @@ class BaseHtml ...@@ -1032,6 +1032,46 @@ class BaseHtml
} }
/** /**
* Generates a summary of the validation errors.
* If there is no validation error, an empty error summary markup will still be generated, but it will be hidden.
* @param Model|Model[] $models the model(s) whose validation errors are to be displayed
* @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
*
* - header: string, the header HTML for the error summary. If not set, a default prompt string will be used.
* - footer: string, the footer HTML for the error summary.
*
* The rest of the options will be rendered as the attributes of the container tag. The values will
* be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
* @return string the generated error summary
*/
public static function errorSummary($models, $options = [])
{
$lines = [];
if (!is_array($models)) {
$models = [$models];
}
foreach ($models as $model) {
/** @var Model $model */
foreach ($model->getFirstErrors() as $error) {
$lines[] = Html::encode($error);
}
}
$header = isset($options['header']) ? $options['header'] : '<p>' . Yii::t('yii', 'Please fix the following errors:') . '</p>';
$footer = isset($options['footer']) ? $options['footer'] : '';
unset($options['header'], $options['footer']);
if (empty($lines)) {
// still render the placeholder for client-side validation use
$content = "<ul></ul>";
$options['style'] = isset($options['style']) ? rtrim($options['style'], ';') . '; display:none' : 'display:none';
} else {
$content = "<ul><li>" . implode("</li>\n<li>", $lines) . "</li></ul>";
}
return Html::tag('div', $header . $content . $footer, $options);
}
/**
* Generates a tag that contains the first validation error of the specified model attribute. * Generates a tag that contains the first validation error of the specified model attribute.
* Note that even if there is no validation error, this method will still return an empty error tag. * Note that even if there is no validation error, this method will still return an empty error tag.
* @param Model $model the model object * @param Model $model the model object
......
...@@ -217,41 +217,12 @@ class ActiveForm extends Widget ...@@ -217,41 +217,12 @@ class ActiveForm extends Widget
* The rest of the options will be rendered as the attributes of the container tag. The values will * The rest of the options will be rendered as the attributes of the container tag. The values will
* be HTML-encoded using [[\yii\helpers\Html::encode()]]. If a value is null, the corresponding attribute will not be rendered. * be HTML-encoded using [[\yii\helpers\Html::encode()]]. If a value is null, the corresponding attribute will not be rendered.
* @return string the generated error summary * @return string the generated error summary
* @see errorSummaryCssClass
*/ */
public function errorSummary($models, $options = []) public function errorSummary($models, $options = [])
{ {
if (!is_array($models)) { Html::addCssClass($options, $this->errorSummaryCssClass);
$models = [$models]; return Html::errorSummary($models, $options);
}
$lines = [];
foreach ($models as $model) {
/** @var Model $model */
foreach ($model->getFirstErrors() as $error) {
$lines[] = Html::encode($error);
}
}
$header = isset($options['header']) ? $options['header'] : '<p>' . Yii::t('yii', 'Please fix the following errors:') . '</p>';
$footer = isset($options['footer']) ? $options['footer'] : '';
unset($options['header'], $options['footer']);
if (!isset($options['class'])) {
$options['class'] = $this->errorSummaryCssClass;
} else {
$options['class'] .= ' ' . $this->errorSummaryCssClass;
}
if (!empty($lines)) {
$content = "<ul><li>" . implode("</li>\n<li>", $lines) . "</li></ul>";
return Html::tag('div', $header . $content . $footer, $options);
} else {
$content = "<ul></ul>";
$options['style'] = isset($options['style']) ? rtrim($options['style'], ';') . '; display:none' : 'display:none';
return Html::tag('div', $header . $content . $footer, $options);
}
} }
/** /**
......
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