D
D
Dmitry Sidorenko2015-09-14 15:18:47
Yii
Dmitry Sidorenko, 2015-09-14 15:18:47

How to load images in Yii2 and then store their names in the database?

Hello!
There is an attribute in the database - image1
I want to put the name of the image in it, and store the image itself in a separate folder on the server.
I do it like this: $model->setAttribute('image1', 'File name with extension');
The problem is that due to the fact that in the model I specify the rule (rules) that the data type is image, it does not allow me to save the value of this attribute that I have named in the database.
So how is it right to store images on the file system and link to them in the database? :)
Template

<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?>
<?= $form->field($model, 'image1')->fileInput([/*'multiple' => true, */'accept' => 'image/*']) ?>

Model
public function rules() {
  return [
    [['image1'], 'image', 'extensions' => 'png, jpg, jpeg, gif', 'maxFiles' => 4, 'skipOnEmpty' => false]
  ];
  ...
}
public function upload($dir, $imageObj) {
  $name = $imageObj->baseName;
  $ext = $imageObj->extension;
  $imageObj->saveAs($dir . $name . '.' . $ext);
  return true;
}

Controller
public function actionUpdate($id) {
  $model = $this->findModel($id);
  $model->image1 = UploadedFile::getInstance($model, 'image1');
  if (Yii::$app->request->post()) {
    if ($model->image1) {
      $dir = $_SERVER['DOCUMENT_ROOT'] . '/upload/manufacturers/';
      // Меняем содержимое аттрибута, записываем туда название файла, чтобы это лежало в БД
      $model->setAttribute('image1', 'myFileName.' . $model->image1->getExtension());
    }
  }
  if ($model->load(Yii::$app->request->post()) && $model->save()) {
    return $this->redirect(['view', 'id' => $model->id_manufacturer]);
  }
}

PS the image appears in the required directory,
but if, before the template is displayed, after trying to change the value of the attribute, print the model using the print_r () function, then you can notice the following error:
if ($model->load(Yii::$app->request->post()) && $model->save()) {
    print_r($model);die;
    return $this->redirect(['view', 'id' => $model->id_manufacturer]);
}
[_validators:yii\base\Model:private] => ArrayObject Object
    (
        [storage:ArrayObject:private] => Array
            (
                [0] => yii\validators\ImageValidator Object
                    (
                        [notImage] => The file "{file}" is not an image.

Answer the question

In order to leave comments, you need to log in

[[+comments_count]] answer(s)
I
Ivan Karabadzhak, 2015-09-14
@sidorenkoda

My advice to you. Create an additional model for the form. In it, validate directly the data entered by the user, including the file itself.
And after loading the file and validating the entire form - create an object of your model, write the file name there and save it.
It's normal practice to have one model to communicate with the database and another to validate the form.
In this example, the form model has a SaveModel method. Which saves the entity model from the database. In my case, I don't need to edit the image file (Attachment), so I just create a new one and delete the old one. IMHO not the best code, but which one I managed to find quickly.

<?php
/**
 * Created by PhpStorm.
 * User: Jakeroid
 * Date: 17-Jul-15
 * Time: 13:28
 */

namespace app\modules\cp\models;

use app\models\Attachment;
use Yii;
use yii\base\Model;
use app\models\Team;

class TeamForm extends Model
{
    public $name;
    public $logo;

    /**
     * @var Team
     */
    private $dbModel;

    /**
     * @return array the validation rules.
     */
    public function rules()
    {
        return [
            [['name'], 'required'],
            [['name'], 'string', 'max' => 255],
            [['logo'], 'file', 'extensions' => 'gif, jpg, jpeg, png', 'skipOnEmpty' => false],
        ];
    }

    /**
     * @return array customized attribute labels
     */
    public function attributeLabels()
    {
        return [
            'name' => Yii::t('app', 'Team name'),
            'logo' => Yii::t('app', 'Team logo (flag)'),
        ];
    }

    /**
     * @param $is_update boolean
     * @return boolean from save method of dbModel
     */
    public function saveModel($is_update = false)
    {
        $attachment = new Attachment();
        $attachment->type = 'team_logo';
        $attachment->attachments_group_id = 0;
        $attachment->saveWithFile($this->logo);
        if ($is_update) {
            $this->dbModel->logo->delete();
        }
        $this->dbModel->logo_id = $attachment->id;
        $this->dbModel->name = $this->name;
        return $this->dbModel->save();
    }

    public function loadModel($model)
    {
        $this->dbModel = $model;
        $this->name = $model->name;
    }

    /**
     * @return Team from current dbModel
     */
    public function getModel()
    {
        return $this->dbModel;
    }
}

The controller is like this:
public function actionUpdate($id)
    {
        $model = new TeamForm();
        $model->loadModel($this->findModel($id));

        if ($model->load(Yii::$app->request->post())) {
            $model->logo = UploadedFile::getInstance($model, 'logo');
            if ($model->validate() && $model->logo) {
                $model->saveModel(true);
                return $this->redirect(['view', 'id' => $model->getModel()->id]);
            }
        }

        return $this->render('update', [
            'model' => $model,
        ]);
    }

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question