Commit 5d5501e1 by Alexander Makarov

Fixed not really correct file uploading in the guide

parent 29ef5693
Uploading Files Uploading Files
=============== ===============
> Note: This section is under development. Uploading files in Yii is done via the a form model, its validation rules and some controller code. Let's review what's
required to handle uploads properly.
Uploading files in Yii is done via the a form model, its validation rules and some controller code. Let's review what's needed
to handle uploads properly.
Form model Uploading single file
---------- ---------------------
First of all, you need to create a model that will handle file uploads. Create `models/UploadForm.php` with the following First of all, you need to create a model that will handle file uploads. Create `models/UploadForm.php` with the following
content: content:
...@@ -24,7 +23,7 @@ use yii\web\UploadedFile; ...@@ -24,7 +23,7 @@ use yii\web\UploadedFile;
class UploadForm extends Model class UploadForm extends Model
{ {
/** /**
* @var UploadedFile|Null file attribute * @var UploadedFile file attribute
*/ */
public $file; public $file;
...@@ -40,11 +39,10 @@ class UploadForm extends Model ...@@ -40,11 +39,10 @@ class UploadForm extends Model
} }
``` ```
In the code above, we created a model `UploadForm` with an attribute `$file` that will become `<input type="file">` in In the code above, we've created a model `UploadForm` with an attribute `$file` that will become `<input type="file">` in
the HTML form. The attribute has the validation rule named `file` that uses [[yii\validators\FileValidator|FileValidator]]. the HTML form. The attribute has the validation rule named `file` that uses [[yii\validators\FileValidator|FileValidator]].
Form view ### Form view
---------
Next, create a view that will render the form: Next, create a view that will render the form:
...@@ -65,8 +63,7 @@ use yii\widgets\ActiveForm; ...@@ -65,8 +63,7 @@ use yii\widgets\ActiveForm;
The `'enctype' => 'multipart/form-data'` is necessary because it allows file uploads. `fileInput()` represents a form The `'enctype' => 'multipart/form-data'` is necessary because it allows file uploads. `fileInput()` represents a form
input field. input field.
Controller ### Controller
----------
Now create the controller that connects the form and model together: Now create the controller that connects the form and model together:
...@@ -114,10 +111,13 @@ If you're using the "basic" application template, then folder `uploads` should b ...@@ -114,10 +111,13 @@ If you're using the "basic" application template, then folder `uploads` should b
That's it. Load the page and try uploading. Uploads should end up in `basic/web/uploads`. That's it. Load the page and try uploading. Uploads should end up in `basic/web/uploads`.
Additional information Validation
---------------------- ----------
It's often required to adjust validation rules to accept certain files only or require uploading. Below we'll review
some common rule configurations.
### Required rule ### Required
If you need to make the file upload mandatory, use `skipOnEmpty` like the following: If you need to make the file upload mandatory, use `skipOnEmpty` like the following:
...@@ -156,12 +156,13 @@ public function rules() ...@@ -156,12 +156,13 @@ public function rules()
[List of common media types](http://en.wikipedia.org/wiki/Internet_media_type#List_of_common_media_types) [List of common media types](http://en.wikipedia.org/wiki/Internet_media_type#List_of_common_media_types)
### Validating uploaded image ### Image properties
If you upload an image, [[yii\validators\ImageValidator|ImageValidator]] may come in handy. It verifies if an attribute If you upload an image, [[yii\validators\ImageValidator|ImageValidator]] may come in handy. It verifies if an attribute
received a valid image that can be then either saved or processed using the [Imagine Extension](https://github.com/yiisoft/yii2/tree/master/extensions/imagine). received a valid image that can be then either saved or processed using the [Imagine Extension](https://github.com/yiisoft/yii2/tree/master/extensions/imagine).
### Uploading multiple files Uploading multiple files
------------------------
If you need to download multiple files at once, some adjustments are required. If you need to download multiple files at once, some adjustments are required.
...@@ -194,15 +195,9 @@ View: ...@@ -194,15 +195,9 @@ View:
use yii\widgets\ActiveForm; use yii\widgets\ActiveForm;
$form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]);
if ($model->hasErrors()) { //it is necessary to see all the errors for all the files.
echo '<pre>';
print_r($model->getErrors());
echo '</pre>';
}
?> ?>
<?= $form->field($model, 'file[]')->fileInput(['multiple' => '']) ?> <?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
<button>Submit</button> <button>Submit</button>
...@@ -212,7 +207,7 @@ if ($model->hasErrors()) { //it is necessary to see all the errors for all the f ...@@ -212,7 +207,7 @@ if ($model->hasErrors()) { //it is necessary to see all the errors for all the f
The difference is the following line: The difference is the following line:
```php ```php
<?= $form->field($model, 'file[]')->fileInput(['multiple' => '']) ?> <?= $form->field($model, 'file[]')->fileInput(['multiple' => true]) ?>
``` ```
Controller: Controller:
...@@ -232,31 +227,13 @@ class SiteController extends Controller ...@@ -232,31 +227,13 @@ class SiteController extends Controller
$model = new UploadForm(); $model = new UploadForm();
if (Yii::$app->request->isPost) { if (Yii::$app->request->isPost) {
$model->file = UploadedFile::getInstances($model, 'file');
$files = UploadedFile::getInstances($model, 'file');
if ($model->file && $model->validate()) {
foreach ($files as $file) { foreach ($model->file as $file) {
$file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
$_model = new UploadForm();
$_model->file = $file;
if ($_model->validate()) {
$_model->file->saveAs('uploads/' . $_model->file->baseName . '.' . $_model->file->extension);
} else {
foreach ($_model->getErrors('file') as $error) {
$model->addError('file', $error);
}
} }
} }
if ($model->hasErrors('file')){
$model->addError(
'file',
count($model->getErrors('file')) . ' of ' . count($files) . ' files not uploaded'
);
}
} }
return $this->render('upload', ['model' => $model]); return $this->render('upload', ['model' => $model]);
...@@ -264,5 +241,6 @@ class SiteController extends Controller ...@@ -264,5 +241,6 @@ class SiteController extends Controller
} }
``` ```
The difference is using `UploadedFile::getInstances($model, 'file');` instead of `UploadedFile::getInstance($model, 'file');`. There are two differences from single file upload. First is that `UploadedFile::getInstances($model, 'file');` used
The former returns instances for **all** uploaded files while the latter gives you only a single instance. instead of `UploadedFile::getInstance($model, 'file');`. The former returns instances for **all** uploaded files while
the latter gives you only a single instance. The second difference is that we're doing `foreach` and saving each file.
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