P
P
Pavel Gogolinsky2015-05-22 15:07:55
Yii
Pavel Gogolinsky, 2015-05-22 15:07:55

How to arrange file upload in a form?

There is a form that should be able to attach 5 photos. How to correctly organize the form and model, which would be extensible (10 photos will eventually be allowed) and with validation?
You can make the attributes file1, file2, ..., file5 in the model and render the fields separately in the form. I understand how to do validation, but it's not very extensible
. You can make an array $files => [file1, file2, ..., file5]. but then I have no idea how to validate.
Who implemented such forms, tell me

Answer the question

In order to leave comments, you need to log in

1 answer(s)
V
Vladimir Korovin, 2015-05-23
@vakorovin

Hello! You did not fully disclose your question, but I will try to answer based on our projects on yii2.
If a mechanism is used in which files can be attached at the stage of creating a certain model (say Portfolio), and they are loaded by the server via an ajax request (for example https://github.com/hayageek/jquery-upload-file), then a situation arises that there is nothing to bind to (the object of the Portfolio class has not yet been saved), and the files are already on the server. In this case, we use the hash field, the value of which is unique, and files are linked using it. Those. when creating a new Portfolio object, we immediately generate a unique hash, pass it to the creation form, and load files with Ajax. If desired, you can hang up a cron task to remove files from the file system that are linked to a non-existent Portfolio.hash.
Next, the model itself. We take the official documentation:
https://github.com/yiisoft/yii2/blob/master/docs/g...
We expand it as we please, for example like this:

class File extends \yii\db\ActiveRecord
{
    public $file;

    public function rules()
    {
        return [
            [['file'], 'file'],
            [['filename', 'parent_id'], 'required'],
            [['parent_id'], 'integer'],
            [['filename', 'path'], 'string', 'max' => 255],
            [['description'], 'string']
        ];
    }

Further, how to behave in the controller is described just at the link above, but in our case the essence is this - for each new model (more on this later), we get the file itself:
$model = new File();
        $model->file = UploadedFile::getInstance($model, 'file');

and assign all other parameters, be it parent_id or something else (including generating a new name to store in the file system). Further, if the model passes validation, we save it in the database and save the file in the file system:
if ($model->file && $model->validate()) {                
            $model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
        }

One clarification. If you upload files one at a time, and only show several fields in the form, then this is solved using js tools, hanging a button to create the next fileInput named File[][file] and textInput File[][description] will not be a problem. But if you want to throw them in a bunch at once, then there are 2 exits - either as in the example indicated by the link - allow multiloading in one model, and from it (after validation) create the models you need, or (which seems more logical to me) play with the method formName() which will return the desired attribute name from the form.
Those. in the base case, form fields are named File[file], File[description], File[id]. In our case, we get the following names:
File[0][file], File[0][description], File[0][id];
File[1][file], File[1][description], File[1][id];
File[2][file], File[2][description], File[2][id];

Now in the controller in a loop we pass
foreach (Yii::$app->request->post('File') as $sn => $file){
        $model = new File;
        $model->fakeFormName = "File[{$sn}]";
        $model->file = UploadedFile::getInstance($model, 'file');
    }

In the example above, we created the $fakeFormName property in advance, in which we put the base name of the form fields required for each case and return its value in the formName() method, in which case UploadedFile::getInstance($model, 'file') will work as it should.
Phew, I don’t know how intelligibly I explained, I may have lost something in the stream of consciousness, but I think I explained the main essence and reference points. If something is not clear, unsubscribe, I will describe in more detail (there are many projects on Yii2, all involve working with files to one degree or another, there are different implementations, including right now we are writing a file manager for our admin panel on yii2).

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question