eggplantSword's avatar

How to upload an image and save to the database?

I'm making a recipe book page and want to save an image for the recipe and also an image for each step if the user wants. This is what I have in the store function of the recipe controller

public function store(Request $request)
    {
        DB::beginTransaction();
        $recipe = new Recipe();
        $recipe->name = $request->name;
        $recipe->description = $request->description;

        $file = $request->file('image');

        if ($file) {
            $file = $request->file('image');
            $filename = Uuid::uuid() . '.' . $file->getClientOriginalExtension();
            $file->move('img/recipes/', $filename);
            $recipe->image = 'img/recipes/' . $filename;
        }

        $recipe->save();


        if ($request->has('steps')) {
            $steps = [];
            $recipe_id = $recipe->id;

            foreach ($request->get('steps') as $number => $item) {
                $num = $number + 1;
                $duration = $item['duration'];
                $instructions = $item['instructions'];
                $file = $request->file('img');

                if ($file) {
                    $file = $request->file('img');
                    $filename = Uuid::uuid() . '.' . $file->getClientOriginalExtension();
                    $file->move('img/steps', $filename);
                    $img = $recipe->img = 'img/steps/' . $filename;
                }

                if (isset($num, $duration, $instructions)) {
                    $steps[] = [
                        "number" => $num,
                        "instructions" => $instructions,
                        "duration" => $duration,
                        "recipe_id" => $recipe_id,
                        "img" => $img,
                    ];
                }
                Log::info($steps);
            }
            if (count($steps)) {
                Step::insert($steps);
            }
        }

        if ($request->has('ingredient')) {
            $ingredients = [];
            $recipe_id = $recipe->id;

            foreach ($request->get('ingredient') as $item) {
                $ingredient = $item['ingredient'];
                $amount = $item['amount'];
                $measurement = $item['measurement'];

                if (isset($ingredient, $amount, $measurement)) {
                    $ingredients[] = [
                        'recipe_id' => $recipe_id,
                        'ingredient_id' => $ingredient,
                        'amount' => $amount,
                        'measurement_id' => $measurement
                    ];
                }
            }
            if (count($ingredients)) {
                RecipeIngredient::insert($ingredients);
            }
        }
        DB::commit();
        return back();
    }

I want to save the images in this structure

public
    -> img
        - > recipe
        - > steps

This is my vue file with the form and methods I'm using, I'm using Element-ui as well

<el-form-item label="Recipe Picture">
     <el-upload
         class="avatar-uploader"
         action="/api/vendors/fake-upload"
         accept="image/*"
         :show-file-list="false"
         :on-success="handleAvatarSuccess"
          :before-upload="beforeAvatarUpload">
          <img v-if="form.image" :src="form.image" class="avatar">
          <i v-else class="el-icon-plus avatar-uploader-icon"></i>

          <div class="buttonImage">
              <el-button v-if="form.image" class="img-button mt-1" type="warning">
                  Change Picture
              </el-button>
          </div>
    </el-upload>
</el-form-item>

In the data()

loadingImage: false,
imageFile: null,
form: {
    name: '',
    description: '',
    image: ''
},
ingredient: [{
    ingredient: '',
    amount: '',
    measurement: ''
}],
steps: [{
    number: '',
    instructions: '',
    duration: '',
    img: '',
}],

Methods

onErrorImage() {
    this.loadingImage = false;
},
handleAvatarSuccess(res, file) {
    this.form.image = URL.createObjectURL(file.raw);
    this.loadingImage = false;
},
beforeAvatarUpload(file) {
    this.imageFile = file;

    const isJPG = file.type === 'image/jpeg';
    const isLt2M = file.size / 1024 / 1024 < 2;

    if (!isJPG) {
        this.$message.error('This picture must be a JPG!');
     }
     if (!isLt2M) {
         this.$message.error('This image is bigger than 2MB!');
     }

     this.loadingImage = true;
     return isLt2M && isJPG;
},

The submit method in the vue

submit() {
                this.$refs.form.validate((valid) => {
                    if (valid) {
                        this.loading = true;
                        if (!this.form.id) {
                            this.$inertia.post(this.baseUrl, {
                                name: this.form.name,
                                description: this.form.description,
                                category: this.category,
                                steps: this.steps,
                                ingredient: this.ingredient,
                                measurements: this.measurements,
                                image: this.imageFile
                            }).then(
                                () => {
                                    this.recipe = this.$page.recipe;
                                    this.$message({
                                        type: 'success',
                                        message: 'Created correctly.'
                                    });
                                    this.loading = false
                                },
                                (res) => {
                                    this.$message.error(parseError(res)[0]);
                                    this.loading = false;
                                })
                        } else {
                            this.$inertia.post(this.customUpdateUrl + '/' + this.form.id, {
                                name: this.form.name,
                                description: this.form.description,
                                category: this.category,
                                steps: this.steps,
                                ingredient: this.ingredient,
                                measurements: this.measurements,
                                image: this.imageFile,
                            }).then(
                                () => {
                                    this.recipe = this.$page.recipe;
                                    this.$message({
                                        type: 'success',
                                        message: 'Saved correctly.'
                                    });
                                    this.loading = false
                                },
                                (res) => {
                                    this.$message.error(parseError(res)[0]);
                                    this.loading = false;
                                })
                        }
                    } else {
                        return false;
                    }
                    this.reset();
                });
            },

This sends the image as null always, even if I do have an image selected.

What am I doing wrong ? If this is not the most effective way that what should I be doing instead?

0 likes
1 reply

Please or to participate in this conversation.