Browse Source

Fixes #7988: Added `\yii\helpers\Console::errorSummary()` and `\yii\helpers\Json::errorSummary()`

tags/2.0.14
Elvira Sheina 7 years ago committed by Alexander Makarov
parent
commit
f11f818b18
  1. 1
      framework/CHANGELOG.md
  2. 19
      framework/base/Model.php
  3. 42
      framework/helpers/BaseConsole.php
  4. 48
      framework/helpers/BaseHtml.php
  5. 42
      framework/helpers/BaseJson.php
  6. 3
      tests/framework/base/ModelTest.php
  7. 34
      tests/framework/helpers/ConsoleTest.php
  8. 29
      tests/framework/helpers/JsonTest.php

1
framework/CHANGELOG.md

@ -11,6 +11,7 @@ Yii Framework 2 Change Log
- Bug #15194: Fixed `yii\db\QueryBuilder::insert()` to preserve passed params when building a `INSERT INTO ... SELECT` query for MSSQL, PostgreSQL and SQLite (sergeymakinen) - Bug #15194: Fixed `yii\db\QueryBuilder::insert()` to preserve passed params when building a `INSERT INTO ... SELECT` query for MSSQL, PostgreSQL and SQLite (sergeymakinen)
- Bug #15229: Fixed `yii\console\widgets\Table` default value for `getScreenWidth()`, when `Console::getScreenSize()` can't determine screen size (webleaf) - Bug #15229: Fixed `yii\console\widgets\Table` default value for `getScreenWidth()`, when `Console::getScreenSize()` can't determine screen size (webleaf)
- Bug #15234: Fixed `\yii\widgets\LinkPager` removed `tag` from `disabledListItemSubTagOptions` (SDKiller) - Bug #15234: Fixed `\yii\widgets\LinkPager` removed `tag` from `disabledListItemSubTagOptions` (SDKiller)
- Enh #7988: Added `\yii\helpers\Console::errorSummary()` and `\yii\helpers\Json::errorSummary()` (developeruz)
- Bug #15249: Controllers in subdirectories were not visible in commands list (IceJOKER) - Bug #15249: Controllers in subdirectories were not visible in commands list (IceJOKER)
- Bug #15270: Resolved potential race conditions when writing generated php-files (kalessil) - Bug #15270: Resolved potential race conditions when writing generated php-files (kalessil)
- Bug #15301: Fixed `ArrayHelper::filter()` to work properly with `0` in values (hhniao) - Bug #15301: Fixed `ArrayHelper::filter()` to work properly with `0` in values (hhniao)

19
framework/base/Model.php

@ -611,6 +611,25 @@ class Model extends Component implements StaticInstanceInterface, IteratorAggreg
} }
/** /**
* Returns the errors for all attributes as a one-dimensional array.
* @param bool $showAllErrors boolean, if set to true every error message for each attribute will be shown otherwise
* only the first error message for each attribute will be shown.
* @return array errors for all attributes as a one-dimensional array. Empty array is returned if no error.
* @see getErrors()
* @see getFirstErrors()
* @since 2.0.14
*/
public function getErrorSummary($showAllErrors)
{
$lines = [];
$errors = $showAllErrors ? $this->getErrors() : $this->getFirstErrors();
foreach ($errors as $es) {
$lines = array_merge((array)$es, $lines);
}
return $lines;
}
/**
* Adds a new error to the specified attribute. * Adds a new error to the specified attribute.
* @param string $attribute attribute name * @param string $attribute attribute name
* @param string $error new error message * @param string $error new error message

42
framework/helpers/BaseConsole.php

@ -8,6 +8,7 @@
namespace yii\helpers; namespace yii\helpers;
use yii\console\Markdown as ConsoleMarkdown; use yii\console\Markdown as ConsoleMarkdown;
use yii\base\Model;
/** /**
* BaseConsole provides concrete implementation for [[Console]]. * BaseConsole provides concrete implementation for [[Console]].
@ -1051,4 +1052,45 @@ class BaseConsole
self::$_progressEtaLastDone = 0; self::$_progressEtaLastDone = 0;
self::$_progressEtaLastUpdate = null; self::$_progressEtaLastUpdate = null;
} }
/**
* Generates a summary of the validation errors.
* @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:
*
* - showAllErrors: boolean, if set to true every error message for each attribute will be shown otherwise
* only the first error message for each attribute will be shown. Defaults to `false`.
*
* @return string the generated error summary
* @since 2.0.14
*/
public static function errorSummary($models, $options = [])
{
$showAllErrors = ArrayHelper::remove($options, 'showAllErrors', false);
$lines = self::collectErrors($models, $showAllErrors);
return implode(PHP_EOL, $lines);
}
/**
* Return array of the validation errors
* @param Model|Model[] $models the model(s) whose validation errors are to be displayed.
* @param $showAllErrors boolean, if set to true every error message for each attribute will be shown otherwise
* only the first error message for each attribute will be shown.
* @return array of the validation errors
* @since 2.0.14
*/
private static function collectErrors($models, $showAllErrors)
{
$lines = [];
if (!is_array($models)) {
$models = [$models];
}
foreach ($models as $model) {
$lines = array_unique(array_merge($lines, $model->getErrorSummary($showAllErrors)));
}
return $lines;
}
} }

48
framework/helpers/BaseHtml.php

@ -1216,35 +1216,45 @@ class BaseHtml
$encode = ArrayHelper::remove($options, 'encode', true); $encode = ArrayHelper::remove($options, 'encode', true);
$showAllErrors = ArrayHelper::remove($options, 'showAllErrors', false); $showAllErrors = ArrayHelper::remove($options, 'showAllErrors', false);
unset($options['header']); unset($options['header']);
$lines = self::collectErrors($models, $encode, $showAllErrors);
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);
}
/**
* Return array of the validation errors
* @param Model|Model[] $models the model(s) whose validation errors are to be displayed.
* @param $encode boolean, if set to false then the error messages won't be encoded.
* @param $showAllErrors boolean, if set to true every error message for each attribute will be shown otherwise
* only the first error message for each attribute will be shown.
* @return array of the validation errors
* @since 2.0.14
*/
private static function collectErrors($models, $encode, $showAllErrors)
{
$lines = []; $lines = [];
if (!is_array($models)) { if (!is_array($models)) {
$models = [$models]; $models = [$models];
} }
foreach ($models as $model) { foreach ($models as $model) {
/* @var $model Model */ $lines = array_unique(array_merge($lines, $model->getErrorSummary($showAllErrors)));
foreach ($model->getErrors() as $errors) {
foreach ($errors as $error) {
$line = $encode ? Html::encode($error) : $error;
if (!in_array($line, $lines, true)) {
$lines[] = $line;
}
if (!$showAllErrors) {
break;
}
}
}
} }
if (empty($lines)) { if ($encode) {
// still render the placeholder for client-side validation use for ($i = 0; $i < count($lines); $i++) {
$content = '<ul></ul>'; $lines[$i] = Html::encode($lines[$i]);
$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); return $lines;
} }
/** /**

42
framework/helpers/BaseJson.php

@ -10,6 +10,7 @@ namespace yii\helpers;
use yii\base\Arrayable; use yii\base\Arrayable;
use yii\base\InvalidParamException; use yii\base\InvalidParamException;
use yii\web\JsExpression; use yii\web\JsExpression;
use yii\base\Model;
/** /**
* BaseJson provides concrete implementation for [[Json]]. * BaseJson provides concrete implementation for [[Json]].
@ -179,4 +180,45 @@ class BaseJson
return $data; return $data;
} }
/**
* Generates a summary of the validation errors.
* @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:
*
* - showAllErrors: boolean, if set to true every error message for each attribute will be shown otherwise
* only the first error message for each attribute will be shown. Defaults to `false`.
*
* @return string the generated error summary
* @since 2.0.14
*/
public static function errorSummary($models, $options = [])
{
$showAllErrors = ArrayHelper::remove($options, 'showAllErrors', false);
$lines = self::collectErrors($models, $showAllErrors);
return json_encode($lines);
}
/**
* Return array of the validation errors
* @param Model|Model[] $models the model(s) whose validation errors are to be displayed.
* @param $showAllErrors boolean, if set to true every error message for each attribute will be shown otherwise
* only the first error message for each attribute will be shown.
* @return array of the validation errors
* @since 2.0.14
*/
private static function collectErrors($models, $showAllErrors)
{
$lines = [];
if (!is_array($models)) {
$models = [$models];
}
foreach ($models as $model) {
$lines = array_unique(array_merge($lines, $model->getErrorSummary($showAllErrors)));
}
return $lines;
}
} }

3
tests/framework/base/ModelTest.php

@ -310,6 +310,9 @@ class ModelTest extends TestCase
'lastName' => ['Another one!'], 'lastName' => ['Another one!'],
], $speaker->getErrors()); ], $speaker->getErrors());
$this->assertEquals(['Another one!', 'Something is wrong!', 'Totally wrong!'], $speaker->getErrorSummary(true));
$this->assertEquals(['Another one!', 'Something is wrong!'], $speaker->getErrorSummary(false));
$speaker->clearErrors('firstName'); $speaker->clearErrors('firstName');
$this->assertEquals([ $this->assertEquals([
'lastName' => ['Another one!'], 'lastName' => ['Another one!'],

34
tests/framework/helpers/ConsoleTest.php

@ -10,6 +10,7 @@ namespace yiiunit\framework\helpers;
use Yii; use Yii;
use yii\helpers\Console; use yii\helpers\Console;
use yiiunit\TestCase; use yiiunit\TestCase;
use yii\base\DynamicModel;
/** /**
* @group helpers * @group helpers
@ -204,6 +205,39 @@ class ConsoleTest extends TestCase
$this->assertEquals($html, Console::ansiToHtml($ansi)); $this->assertEquals($html, Console::ansiToHtml($ansi));
} }
public function testErrorSummary()
{
$model = new TestConsoleModel();
$model->name = 'not_an_integer';
$model->addError('name', 'Error message. Here are some chars: < >');
$model->addError('name', 'Error message. Here are even more chars: ""');
$model->validate(null, false);
$options = ['showAllErrors' => true];
$expectedHtml = "Error message. Here are some chars: < >\nError message. Here are even more chars: \"\"";
$this->assertEquals($expectedHtml, Console::errorSummary($model, $options));
}
}
/**
* @property string name
* @property array types
* @property string description
*/
class TestConsoleModel extends DynamicModel
{
public function rules()
{
return [
['name', 'required'],
['name', 'string', 'max' => 100]
];
}
public function init()
{
$this->defineAttribute('name');
}
/** /**
* @covers \yii\helpers\BaseConsole::input() * @covers \yii\helpers\BaseConsole::input()
*/ */

29
tests/framework/helpers/JsonTest.php

@ -7,7 +7,7 @@
namespace yiiunit\framework\helpers; namespace yiiunit\framework\helpers;
use yii\base\Model; use yii\base\DynamicModel;
use yii\helpers\BaseJson; use yii\helpers\BaseJson;
use yii\helpers\Json; use yii\helpers\Json;
use yii\web\JsExpression; use yii\web\JsExpression;
@ -208,9 +208,21 @@ class JsonTest extends TestCase
} }
} }
} }
public function testErrorSummary()
{
$model = new JsonModel();
$model->name = 'not_an_integer';
$model->addError('name', 'Error message. Here are some chars: < >');
$model->addError('name', 'Error message. Here are even more chars: ""');
$model->validate(null, false);
$options = ['showAllErrors' => true];
$expectedHtml = '["Error message. Here are some chars: < >","Error message. Here are even more chars: \"\""]';
$this->assertEquals($expectedHtml, Json::errorSummary($model, $options));
}
} }
class JsonModel extends Model implements \JsonSerializable class JsonModel extends DynamicModel implements \JsonSerializable
{ {
public $data = ['json' => 'serializable']; public $data = ['json' => 'serializable'];
@ -218,4 +230,17 @@ class JsonModel extends Model implements \JsonSerializable
{ {
return $this->data; return $this->data;
} }
public function rules()
{
return [
['name', 'required'],
['name', 'string', 'max' => 100]
];
}
public function init()
{
$this->defineAttribute('name');
}
} }

Loading…
Cancel
Save