Skip to content

Commit

Permalink
Fix file uploader, test typed attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
bizley committed May 26, 2024
1 parent 9975597 commit 8deadac
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 31 deletions.
45 changes: 14 additions & 31 deletions framework/validators/FileValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -208,40 +208,23 @@ public function init()
*/
public function validateAttribute($model, $attribute)
{
if ($this->maxFiles != 1 || $this->minFiles > 1) {
$rawFiles = $model->$attribute;
if (!is_array($rawFiles)) {
$this->addError($model, $attribute, $this->uploadRequired);
$files = $this->filterFiles((array) $model->$attribute);
$filesCount = count($files);
if ($filesCount === 0) {
$this->addError($model, $attribute, $this->uploadRequired);

return;
}

$files = $this->filterFiles($rawFiles);
$model->$attribute = $files;

if (empty($files)) {
$this->addError($model, $attribute, $this->uploadRequired);

return;
}

$filesCount = count($files);
if ($this->maxFiles && $filesCount > $this->maxFiles) {
$this->addError($model, $attribute, $this->tooMany, ['limit' => $this->maxFiles]);
}
return;
}

if ($this->minFiles && $this->minFiles > $filesCount) {
$this->addError($model, $attribute, $this->tooFew, ['limit' => $this->minFiles]);
}
if ($this->maxFiles && $filesCount > $this->maxFiles) {
$this->addError($model, $attribute, $this->tooMany, ['limit' => $this->maxFiles]);
}
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 {
$result = $this->validateValue($model->$attribute);
foreach ($files as $file) {
$result = $this->validateValue($file);
if (!empty($result)) {
$this->addError($model, $attribute, $result[0], $result[1]);
}
Expand Down
17 changes: 17 additions & 0 deletions tests/data/validators/models/FakedValidationTypedModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php
/**
* @link https://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license https://www.yiiframework.com/license/
*/

namespace data\validators\models;

use yii\base\Model;

class FakedValidationTypedModel extends Model
{
public ?UploadedFile $single = null;

public array $multiple = [];
}
150 changes: 150 additions & 0 deletions tests/framework/validators/FileValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

namespace yiiunit\framework\validators;

use data\validators\models\FakedValidationTypedModel;
use Yii;
use yii\helpers\FileHelper;
use yii\validators\FileValidator;
Expand Down Expand Up @@ -314,6 +315,30 @@ public function testValidateAttribute_minFilesTwoMaxFilesUnlimited_hasError()
$this->assertTrue($model->hasErrors('attr_images'));
}

/**
* https://github.com/yiisoft/yii2/issues/19855
*/
public function testValidateArrayAttributeWithMinMaxOneAndOneFile()
{
$validator = new FileValidator(['maxFiles' => 1, 'minFiles' => 0]);
$model = FakedValidationModel::createWithAttributes(
[
'attr_images' => $this->createTestFiles(
[
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
],
]
)
]
);

$validator->validateAttribute($model, 'attr_images');
$this->assertFalse($model->hasErrors('attr_images'));
}

/**
* @param array $params
* @return UploadedFile[]
Expand Down Expand Up @@ -672,4 +697,129 @@ public function mimeTypeCaseInsensitive() {
['image/jxra', 'image/jxrA', true],
];
}

public function testValidateTypedAttributeNoErrors()
{
if (version_compare(PHP_VERSION, '7.4', '<')) {
$this->markTestSkipped('Requires typed properties');
}

$validator = new FileValidator(['minFiles' => 0, 'maxFiles' => 2]);
$file = $this->createTestFiles(
[
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
]
]
)[0];
$model = new FakedValidationTypedModel();
$model->single = $file;
$model->multiple = [$file];
$validator->validateAttribute($model, 'single');
$this->assertFalse($model->hasErrors('single'));
$validator->validateAttribute($model, 'multiple');
$this->assertFalse($model->hasErrors('multiple'));
}

public function testValidateTypedAttributeExactMinNoErrors()
{
if (version_compare(PHP_VERSION, '7.4', '<')) {
$this->markTestSkipped('Requires typed properties');
}

$validator = new FileValidator(['minFiles' => 1]);
$file = $this->createTestFiles(
[
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
]
]
)[0];
$model = new FakedValidationTypedModel();
$model->single = $file;
$model->multiple = [$file];
$validator->validateAttribute($model, 'single');
$this->assertFalse($model->hasErrors('single'));
$validator->validateAttribute($model, 'multiple');
$this->assertFalse($model->hasErrors('multiple'));
}

public function testValidateTypedAttributeExactMaxNoErrors()
{
if (version_compare(PHP_VERSION, '7.4', '<')) {
$this->markTestSkipped('Requires typed properties');
}

$validator = new FileValidator(['maxFiles' => 1]);
$file = $this->createTestFiles(
[
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
]
]
)[0];
$model = new FakedValidationTypedModel();
$model->single = $file;
$model->multiple = [$file];
$validator->validateAttribute($model, 'single');
$this->assertFalse($model->hasErrors('single'));
$validator->validateAttribute($model, 'multiple');
$this->assertFalse($model->hasErrors('multiple'));
}

public function testValidateTypedAttributeMinError()
{
if (version_compare(PHP_VERSION, '7.4', '<')) {
$this->markTestSkipped('Requires typed properties');
}

$validator = new FileValidator(['minFiles' => 2]);
$file = $this->createTestFiles(
[
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
]
]
)[0];
$model = new FakedValidationTypedModel();
$model->single = $file;
$model->multiple = [$file];
$validator->validateAttribute($model, 'single');
$this->assertTrue($model->hasErrors('single'));
$validator->validateAttribute($model, 'multiple');
$this->assertTrue($model->hasErrors('multiple'));
}

public function testValidateTypedAttributeMaxError()
{
if (version_compare(PHP_VERSION, '7.4', '<')) {
$this->markTestSkipped('Requires typed properties');
}

$validator = new FileValidator(['maxFiles' => 0]);
$file = $this->createTestFiles(
[
[
'name' => 'image.png',
'size' => 1024,
'type' => 'image/png',
]
]
)[0];
$model = new FakedValidationTypedModel();
$model->single = $file;
$model->multiple = [$file];
$validator->validateAttribute($model, 'single');
$this->assertTrue($model->hasErrors('single'));
$validator->validateAttribute($model, 'multiple');
$this->assertTrue($model->hasErrors('multiple'));
}
}

0 comments on commit 8deadac

Please sign in to comment.