Level 4
run
php artisan storage:link
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?
Please or to participate in this conversation.