Browse Source

Fixes #15417: Added `yii\validators\FileValidator::$minFiles`

tags/2.0.14
Гордиенко Владислав Юрьевич 7 years ago committed by Alexander Makarov
parent
commit
72b69e359a
  1. 2
      framework/CHANGELOG.md
  2. 78
      framework/validators/FileValidator.php
  3. 79
      tests/framework/validators/FileValidatorTest.php

2
framework/CHANGELOG.md

@ -3,7 +3,7 @@ Yii Framework 2 Change Log
2.0.14 under development
------------------------
- Enh #15417: Added `yii\validators\FileValidator::$minFiles` (vladis84)
- Bug #8983: Only truncate the original log file for rotation (matthewyang, developeruz)
- Bug #14157: Add support for loading default value `CURRENT_TIMESTAMP` of MySQL `datetime` field (rossoneri)
- Bug #14276: Fixed I18N format with dotted parameters (developeruz)

78
framework/validators/FileValidator.php

@ -80,6 +80,15 @@ class FileValidator extends Validator
* @see tooMany for the customized message when too many files are uploaded.
*/
public $maxFiles = 1;
/**
* @var int the minimum file count the given attribute can hold.
* Defaults to 0. Higher value means at least that number of files should be uploaded.
*
* @see tooFew for the customized message when too few files are uploaded.
* @since 2.0.14
*/
public $minFiles = 0;
/**
* @var string the error message used when a file is not uploaded correctly.
*/
@ -120,6 +129,18 @@ class FileValidator extends Validator
* - {limit}: the value of [[maxFiles]]
*/
public $tooMany;
/**
* @var string the error message used if the count of multiple uploads less that minFiles.
* You may use the following tokens in the message:
*
* - {attribute}: the attribute name
* - {limit}: the value of [[minFiles]]
*
* @since 2.0.14
*/
public $tooFew;
/**
* @var string the error message used when the uploaded file has an extension name
* that is not listed in [[extensions]]. You may use the following tokens in the message:
@ -156,6 +177,9 @@ class FileValidator extends Validator
if ($this->tooMany === null) {
$this->tooMany = Yii::t('yii', 'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.');
}
if ($this->tooFew === null) {
$this->tooFew = Yii::t('yii', 'You should upload at least {limit, number} {limit, plural, one{file} other{files}}.');
}
if ($this->wrongExtension === null) {
$this->wrongExtension = Yii::t('yii', 'Only files with these extensions are allowed: {extensions}.');
}
@ -185,30 +209,36 @@ class FileValidator extends Validator
*/
public function validateAttribute($model, $attribute)
{
if ($this->maxFiles != 1) {
$files = $model->$attribute;
if (!is_array($files)) {
if ($this->maxFiles != 1 || $this->minFiles > 1) {
$rawFiles = $model->$attribute;
if (!is_array($rawFiles)) {
$this->addError($model, $attribute, $this->uploadRequired);
return;
}
foreach ($files as $i => $file) {
if (!$file instanceof UploadedFile || $file->error == UPLOAD_ERR_NO_FILE) {
unset($files[$i]);
}
}
$files = $this->filterFiles($rawFiles);
$model->$attribute = $files;
if (empty($files)) {
$this->addError($model, $attribute, $this->uploadRequired);
return;
}
if ($this->maxFiles && count($files) > $this->maxFiles) {
$filesCount = count($files);
if ($this->maxFiles && $filesCount > $this->maxFiles) {
$this->addError($model, $attribute, $this->tooMany, ['limit' => $this->maxFiles]);
} else {
foreach ($files as $file) {
$result = $this->validateValue($file);
if (!empty($result)) {
$this->addError($model, $attribute, $result[0], $result[1]);
}
}
if ($this->minFiles && $this->minFiles > $filesCount) {
$this->addError($model, $attribute, $this->tooFew, ['limit' => $this->minFiles]);
}
foreach ($files as $file) {
$result = $this->validateValue($file);
if (!empty($result)) {
$this->addError($model, $attribute, $result[0], $result[1]);
}
}
} else {
@ -220,6 +250,24 @@ class FileValidator extends Validator
}
/**
* Files filter.
* @param array $files
* @return UploadedFile[]
*/
private function filterFiles(array $files)
{
$result = [];
foreach ($files as $fileName => $file) {
if ($file instanceof UploadedFile && $file->error !== UPLOAD_ERR_NO_FILE) {
$result[$fileName] = $file;
}
}
return $result;
}
/**
* @inheritdoc
*/
protected function validateValue($value)

79
tests/framework/validators/FileValidatorTest.php

@ -235,6 +235,85 @@ class FileValidatorTest extends TestCase
$this->assertFalse($m->validate());
}
public function testValidateAttribute_minFilesGreaterThanOneMaxFilesUnlimited_notError()
{
$validator = new FileValidator(['minFiles' => 2, 'maxFiles' => 0]);
$model = FakedValidationModel::createWithAttributes(
[
'attr_images' => $this->createTestFiles(
[
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
]
)
]
);
$validator->validateAttribute($model, 'attr_images');
$this->assertFalse($model->hasErrors('attr_images'));
}
public function testValidateAttribute_minFilesTwoMaxFilesFour_notError()
{
$validator = new FileValidator(['minFiles' => 2, 'maxFiles' => 4]);
$model = FakedValidationModel::createWithAttributes(
[
'attr_images' => $this->createTestFiles(
[
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
]
)
]
);
$validator->validateAttribute($model, 'attr_images');
$this->assertFalse($model->hasErrors('attr_images'));
}
public function testValidateAttribute_minFilesTwoMaxFilesUnlimited_hasError()
{
$validator = new FileValidator(['minFiles' => 2, 'maxFiles' => 0]);
$model = FakedValidationModel::createWithAttributes(
[
'attr_images' => $this->createTestFiles(
[
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
[
'error' => UPLOAD_ERR_NO_FILE,
],
]
)
]
);
$validator->validateAttribute($model, 'attr_images');
$this->assertTrue($model->hasErrors('attr_images'));
}
/**
* @param array $params
* @return UploadedFile[]

Loading…
Cancel
Save