Как организовать загрузку файлов в форме?

Есть форма у которой должна быть возможность прикрепить 5 фотографий. Как грамотно организовать форму и модель, что бы было расширяемо (со временем разрешат 10 фотографий) и с валидацией?
Можно в моделе сделать аттрибуты file1, file2, ..., file5 а в форме рендерить поля по отдельности. Я понимаю как сделать валидацию, но это не очень расширяемо
Можно сделать массив $files => [file1, file2, ..., file5]. но тогда не представляю как валидировать.
Кто реализовывал подобные формы, подскажите
  • Вопрос задан
  • 221 просмотр
Пригласить эксперта
Ответы на вопрос 1
vakorovin
@vakorovin
Разработчик
Здравствуйте! Не раскрыли вы полностью ваш вопрос, но постараюсь ответить, исходя из наших проектов на yii2.
Если используется механизм, при котором файлы можно прикреплять на этапе создания некой модели (скажем Portfolio), и загружаются они сервер посредством ajax-запроса (к примеру https://github.com/hayageek/jquery-upload-file), то возникает ситуация, что привязываться то еще не к чему (объект класса Portfolio еще не сохранен), а файлы уже на сервере. На этот случай используем поле hash, значение которого уникально, и именно по нему привязываются файлы. Т.е. при создании нового объекта Portfolio сразу генерируем уникальный hash, передаем его в форму создания, и с ним грузим аяксом файлы. При желании можно повесить cron-задачу для удаления из файловой системы файлов, которые привязаны к несуществующему Portfolio.hash.

Далее, сама модель. Берем официальную документацию:

https://github.com/yiisoft/yii2/blob/master/docs/g...

Расширяем как нам угодно, например так:

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']
        ];
    }


Далее, в контроллере как себя вести, описано как раз по ссылке выше, но в нашем случае суть такова - для каждой новой модели (об этом чуть позже) получаем сам файл:

$model = new File();
        $model->file = UploadedFile::getInstance($model, 'file');


и назначаем все остальные параметры, будь то parent_id или что-то еще (включая генерацию нового имени для хранения в файловой системе). Далее, если модель проходит валидацию - сохраняем ее в БД и сохраняем файл в файловой системе:

if ($model->file && $model->validate()) {                
            $model->file->saveAs('uploads/' . $model->file->baseName . '.' . $model->file->extension);
        }


Одно уточнение. Если загружать файлы по одному, и только в форме показывать несколько полей, то это решается средствами js, повесить кнопку для создания очередных fileInput с именем File[][file] и textInput File[][description] - проблем не составит. А вот если требуется закинуть их сразу пачкой, то выходов 2 - либо как в указанном по ссылке примере - в одной модели разрешить мультизагрузку, и уже из нее (после валидации) создавать нужные вам модели, либо (что мне кажется логичнее) играться с методом formName(), который будет возвращать нужное имя аттрибута из формы.

Т.е. в базовом случае поля формы имею имена File[file], File[description], File[id]. В нашем же случае получаются такие имена:

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];


Теперь в контроллере в цикле проходим

foreach (Yii::$app->request->post('File') as $sn => $file){
        $model = new File;
        $model->fakeFormName = "File[{$sn}]";
        $model->file = UploadedFile::getInstance($model, 'file');
    }


В примере выше мы заранее создали свойство $fakeFormName, в которое поместим требуемое для каждого случая базовое имя полей формы и вернем его значение в методе formName(), в таком случае UploadedFile::getInstance($model, 'file') сработает как надо.

Уф, не знаю, насколько доходчиво разъяснил, что-то может потерял в потоке сознания, но думаю основную суть и опорные точки разъяснил. Если что-то непонятно, отпишитесь, я распишу подробнее (проектов на Yii2 много, все включают работу с файлами в той или иной степени, есть разные реализации, в том числе прямо сейчас пишем файловый менеджер для нашей админки на yii2).
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы