kimono
@kimono
Web developer

Карусель afterSave в YII2 или как прикрепить изображение к сущности?

В общем ситуация такая: в базу нужно загружать PDF-файлы (PS: загружать в базу не сами файлы, а записи с информацией о их местоположении на сайте), чтобы люди их потом скачивали/смотрели в браузере.
Атрибуты модели:
return [
                'id'             => 'ID',
                'issue_date'     => 'Дата выпуска',
                'issue_num'      => 'Номер газеты',
                'year_num'       => 'Номер в году',
                'path'           => 'Ссылка на файл',
                'size'           => 'Размер файла',
                'created_by'     => 'Создано',
                'updated_by'     => 'Обновлено',
                'created_at'     => 'Дата создания',
                'updated_at'     => 'Дата обновления',
                'view_count'     => 'Количество просмотров',
                'download_count' => 'Количество скачиваний',
                'is_active'      => 'Активность',
            ];

Сразу скажу, что все работает безупречно за исключением одного проблемного места. Файлы загружаются в форму через dropzone, и складываются во временную папку /tmp. Заполняется форма с остальными данными и при сохранении записи файл нужно переместить в подпапку по ID записи: /userdata/pdfs/XXXX (ну, вы знаете как это бывает).
Для редактирования - все понятно, все работает как часы. Но как быть при добавлении новой записи? Ведь ID еще неизвестен, а потому мы не может создать такую папку!
"Хорошо" - подумал я, и решил перемещать временный файл в методе afterSave. Но тогда после перемещения мне нужно изменить адрес файла в базе, тогда afterSave дергается опять, и опять, и опять?!
С загрузкой изображений в отдельную таблицу базы данных - не проблема. А как быть, если файл нужно держать вместе с записью?
  • Вопрос задан
  • 860 просмотров
Решения вопроса 1
qonand
@qonand
Software Engineer
"Хорошо" - подумал я, и решил перемещать временный файл в методе afterSave. Но тогда после перемещения мне нужно изменить адрес файла в базе, тогда afterSave дергается опять, и опять, и опять?!

о каком адресе идет речь? у Вас есть место для хранения файла /userdata/pdfs/XXXX Вам достаточно хранить название файла - не нужно хранить весь путь к нему. Т.е. вы можете спокойно сохранить запись с названием, а потом на afterSave его переместить

Допустим есть путь к файлу /userdata/pdfs/module/id/filename.pdf.
Каждый файл соответственно относится к какому-то модулю, насколько я понимаю принадлежность модуля определяется до сохранения данных модели. Что мешает сделать следующее?
1. Вынести путь к файлам /userdata/pdfs/ в какой-то алиас или на крайний случай в константу
2. В модель добавить атрибут $module - в который на стадии загрузки записывать информацию о модуле.
3. В модель добавить атрибут $filename - в котором на стадии загрузки записывать название файла
4. На afterSave сделать перемещения файла
5. Полный путь к файлу получать как совокупность всех этих данных

Т.е. сделать приблизительно так:
/**
 * @property $id ID
 * @property $issue_date Дата выпуска
 * @property $issue_num Номер газеты
 * @property $year_num Номер в году
 * @property $size Размер файла
 * @property $created_by Создано
 * @property $updated_by Обновлено
 * @property $created_at Дата создания
 * @property $updated_at Дата обновления
 * @property $view_count Количество просмотров
 * @property $download_count Количество скачиваний
 * @property $is_active Активность
 *
 * @property $module Модуль к которому относится файл
 * @property $filename Название файла (вместе с расширением)
 */
class PdfFile extends \yii\db\ActiveRecord 
{
    /**
     * @var string Путь к папке загрузок, но вообще лучше его вынести в алиас
     */
    const PATH = '/userdata/pdfs/'
    
    /**
     * Функция получения полного пути к файлу
     *
     * @return string
     */
    public function getFilepath() {
        return $this::PATH . $this->module . '/' . $this->id . '/' . $this->filename;
    }

    /**
     * @inheritdoc
     */
    public function afterSave( $insert, $changedAttributes ){
        // тут перемещаем файл с временной папки в папку $model->getFilepath
    }
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
arutyunov
@arutyunov
Mooza.ru — Делаем сайты
В afterSave передаются $insert и $changedAttributes — вам нужно дернуть только при $insert, насколько я понимаю.

Делаете проверку if($insert) и обновляете запись, указывая путь до файла, сохраняетесь. После этого сохранения $insert будет уже false, потому что у модели уже будет айдишник.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Похожие вопросы