@lilwings

Правильно ли я сделал на yii2 (Code review)?

Controller:

public function actionAdd()
{
    $model = new Info();

    if ( $model->load(Yii::$app->request->post()) ) {
        $model->img_preview = UploadedFile::getInstance($model, 'img_preview');
        $model->img_full = UploadedFile::getInstance($model, 'img_full');

        if ( $model->upload() && $model->save(false)) {
            Yii::$app->session->setFlash('message', 'Данные сохранены!');

            return $this->refresh();
        }

        Yii::$app->session->setFlash('message', 'Не правильные данные!');
    }

    return $this->render('add', compact('model'));
}


Model info:

class Info extends ActiveRecord
{
    public static function tableName()
    {
        return '{{info}}';
    }

    public function rules() {
        return [
            [['title', 'preview', 'description_seo'], 'string', 'length' => [0, 255]],
            [['title', 'preview', 'description_seo'], 'filter', 'filter' => 'strip_tags'],
            [['title', 'preview', 'description_seo'], 'trim'],
            [['title', 'preview', 'description_seo'], 'required'],
            [['img_preview', 'img_full'], 'safe'],
            ['description', 'safe'],
        ];
    }

    public function upload() {
        if ($this->validate()) {

            $model = new InfoUpload($this);
            $model->upload();

            return true;
        }

        return false;
    }
}


Model InfoUpload:

class InfoUpload extends Model
{
    public $modelInfo;
    public $img_preview;
    public $img_full;

    public function __construct(&$model)
    {
        $this->modelInfo = $model;
        $this->img_preview = $model->img_preview;
        $this->img_full = $model->img_full;
    }

    public function upload() {
        // Создание директории
        $folderName = $this->generateUniqFileName("web/info");
        FileHelper::createDirectory( Yii::getAlias("@frontend/web/img/info/$folderName") );

        // Создание файла
        $imgPreviewName = $folderName . '/' . $this->generateUniqFileName("web/info/$folderName") . '.' . $this->img_preview->extension;
        $this->img_preview->saveAs( Yii::getAlias("@frontend/web/img/info/$imgPreviewName") );

        // Создание Файла
        $imgFullName = $folderName . '/' . $this->generateUniqFileName("web/info/$folderName") . '.' . $this->img_full->extension;
        $this->img_full->saveAs( Yii::getAlias("@frontend/web/img/info/$imgFullName") );

        // Заполнение главной модели
        $this->fillingInfo(['img_preview' => $imgPreviewName, 'img_full' => $imgFullName,]);
    }

    public function fillingInfo($paths) {
        $this->modelInfo->img_preview = $paths['img_preview'];
        $this->modelInfo->img_full = $paths['img_full'];
    }

    public function generateUniqFileName($path) {
        $name = bin2hex(random_bytes(8));

        if ( file_exists( Yii::getAlias("@frontend/$path/$name") ) ) return $this->generateUniqFileName($path);
        else return $name;
    }
}


Я создал две модели( Спасибо за это Дмитрий ):
1) Модель Info - Отвечает за валидацию данных и запись их в базу данных
2) Модель InfoUpload - Отвечает за сохранение файлов и перезаписи значений в главной модели Info.

В InfoUpload передается вся модель Info по ссылке, и при записи файлов модель с данными Info обновляется, и вместо файлов там путь к ним.
  • Вопрос задан
  • 223 просмотра
Решения вопроса 1
myks92
@myks92 Куратор тега Yii
Нашёл решение — пометь вопрос ответом!
1. Зачем вы в модели поместили создание директории, создание файла? Это ответственность какого-нибудь сервиса, но не модели (сущности).
2. Загрузку файлов можно вынести из контроллера в этот же сервис.
3. Не очень понимаю зачем тут две модели.

Из этого всего показываю вам сервис загрузки и удаления изображений, правда на Symfony, но его не сложно сделать на Yii. Подключаете в конструкторе контроллера и работаете с ним.

/**
 * Class FileUploader
 * @author Maxim Vorozhtsov <myks1992@mail.ru>
 */
class FileUploader
{
    /**
     * @var string
     */
    private $basUrl;

    /**
     * FileUploader constructor.
     * @param string $basUrl
     */
    public function __construct(string $basUrl)
    {
        $this->basUrl = $basUrl;
    }

    /**
     * @param UploadedFile $file
     * @return File
     * @throws Exception
     */
    public function upload(UploadedFile $file): File
    {
        $path = $this->generateUrl();
        $name = time() . '.' . $file->getExtension();
        $fileName = $path . '/' . $name;
        FileHelper::createDirectory($path);
        $file->saveAs($fileName);
        return new File($path, $name, $file->size);
    }

    /**
     * @return string
     */
    public function generateUrl(): string
    {
        return $this->basUrl;
    }

    /**
     * @param string $name
     */
    public function remove(?string $name): void
    {
        if (is_file($fileName = $this->generateUrl() . '/' . $name)) {
            unlink($fileName);
        }
    }
}


Store и BaseUrl присваивается в DI контейнере.

'container' => [
        'singletons' => [
            FileUploader::class => static function () {
                return new Myks92\Vmc\Event\Service\Uploader\FileUploader(Yii::getAlias('@staticRoot/origin/images/events'));
            },
        ],
    ],


Контроллер:
public function actionUploadPoster($id)
    {
        $event = $this->findModel($id);
        $form = new Poster\Upload\Form();
        $handler = Yii::createObject(Poster\Upload\Handler::class);

        if (!$this->checker->allowEdit($event->getId())) {
            throw new ForbiddenHttpException('Вам не разрешено производить данное действие!');
        }

        if ($form->load(Yii::$app->request->post()) && $form->validate()) {
            $uploader = Yii::createObject(FileUploader::class);
            $uploader->remove($event->getPoster());
            $uploaded = $uploader->upload($form->poster);

            $file = new Poster\Upload\File(
                $uploaded->getPath(),
                $uploaded->getName(),
                $uploaded->getSize()
            );

            $handler->handle(new Poster\Upload\Command($event->getId()->getValue(), $file));

            return $this->redirect(['view', 'id' => $event->getId()->getValue()]);
        }

        return $this->render('upload-poster', [
            'model' => $event,
            'posterForm' => $form,
        ]);
    }
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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