upload image in laravel 8 - API - laravel

I want to upload image for my posts and have polymorphism relation one to one (because I have other tables and they need image too ) between posts and images
And when I want to send request and store the image in database , I get this error:
BadMethodCallException: Call to undefined method App\Models\Image::move()
I'm creating an API so :
My postman :
My relations :
Image model :
class Image extends Model
{
use HasFactory;
protected $fillable = [
'image'
];
public function imageable(){
return $this->morphTo();
}
}
Post model :
class Post extends Model
{
use HasFactory;
use \Conner\Tagging\Taggable;
protected $fillable = [
'user_id' ,
'category_id' ,
'title' ,
'body' ,
'study_time',
'likes',
'status',
'tags',
];
public function image(){
return $this->morphOne(Image::class , 'imageable');
}
}
And the PostController , store() method :
public function store(Request $request )
{
$data = $request->all();
$validator = Validator::make($data, [
'user_id'=>'required',
'category_id'=>'required',
'title' => 'required|max:150|unique:posts',
'body' => 'required',
'study_time'=>'required',
'tags'=>'nullable|string',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors(), 'error']);
}
//separate tags
$tags = explode(",", $request->tags);
$image = new Image;
$getImage = $request->file('image');
$imageName = time().'.'.$getImage->extension();
$image->move(public_path('images'), $imageName);
$post = Post::create($data);
$post->image()->save($image);
//save tags
$post->tag($tags);
return response()->json([
"success" => true,
"message" => "successfull",
"data" => $post
]);
}
Where is my mistake?

After a month of this challenge, I was finally able to solve it :}
To make the code better and cleaner, I added another column to my image table : path
it's for saving path of image , and another column : image
and i added the path to my fillable in Image model and i edited the code to this :
public function store(Request $request )
{
$data = $request->all();
$validator = Validator::make($data, [
'user_id'=>'required',
'category_id'=>'required',
'title' => 'required|max:150|unique:posts',
'body' => 'required',
'study_time'=>'required',
'tags'=>'nullable|string',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors(), 'error']);
}
//separate tags
$tags = explode(",", $request->tags);
$image = new Image;
$getImage = $request->image
$imageName = time().'.'.$getImage->extension();
$imagePath = public_path(). '/images/posts';
$image->path = $imagePath;
$image->image = $imageName;
$getImage->move($imagePath, $imageName);
$post = Post::create($data);
$post->image()->save($getImage);
$post->tag($tags);
return response()->json([
"success" => true,
"message" => "successfully",
"data" => $post
]);
}

Related

why images aren't stored in public path

I am a Laravel beginner and I want to build an API with Laravel 8.
I have posts and images and I want to store and update them.
My store method works and the images are saved in the database and public path in images folders, but in update method I can't save it in folder.
These are my codes:
PostController
public function store(Request $request )
{
$data = $request->all();
//validationg posts and images fields
$validator = Validator::make($data, [
'user_id' => 'required',
'category_id' => 'required',
'title' => 'required|max:150|unique:posts',
'body' => 'required',
'study_time' => 'required',
'tags' => 'nullable|string',
'image' => 'required',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors(), 'خطا در اعتبار سنجی']);
}
//separate tags
$tags = explode(",", $request->tags);
if ($request->hasfile('image')) {
//getting post images from request
$files = $request->file('image');
//saving name and path of images
foreach ($files as $file) {
$imageName = time().rand(1,10000).'.'.$file->extension();
$postTitle = $request->title; //post title for folder name and the images inside it
$imagePath = public_path(). '/images/posts/'.$postTitle;
$file->move($imagePath, $imageName);
$image = new Image;
$image->image = $imageName;
$image->path = $imagePath;
$images[] = $image; // make an array of uploaded images
}
}
$post = Post::create($data);
$post->images()->saveMany($images);//save imageas in image table
$post->tag($tags);//save tags in tags table
return response()->json([
'success' => true,
'message' => 'با موفقیت ثبت گردید ',
'data' => $post
]);
}
public function update(Request $request, $id)
{
$post_failed = Post::find($id);
if (is_null($post_failed)) {
return response()->json('پست مورد نظر یافت نشد ', 404);
}
$data = $request->all();
//validation posts and images fields
$validator = Validator::make($data, [
'user_id' => 'required',
'category_id' => 'required',
'title' => 'required|max:150|unique:posts',
'body' => 'required',
'study_time' => 'required',
'tags' => 'nullable|string',
'image' => 'required',
]);
if ($validator->fails()) {
return response()->json(['error' => $validator->errors(), 'خطا در اعتبار سنجی ']);
}
$tags = explode(",", $request->tags);
if ($request->hasfile('image')) {
$postTitle = $request->title; //post title for folder name and the images inside it
//delete last Images from database for updating images
Image::where('imageable_type', 'App\Models\Post')->where('imageable_id' , $id)->delete();
//delete last images images folder
File::delete(public_path('/images/posts/'.$postTitle));
$files = $request->file('image');
foreach ($files as $file) {
$imageName = time().rand(1,10000).'.'.$file->extension();
$imagePath = public_path(). '/images/posts/'.$postTitle;
$image = new Image();
$image->image = $imageName;
$image->path = $imagePath;
$images[] = $image;
}
}
$post = Post::find($id);
$post->user_id = $data['user_id'];
$post->category_id = $data['category_id'];
$post->title = $data['title'];
$post->body = $data['body'];
$post->study_time = $data['study_time'];
$post->tags = $data['tags'];
$post->save();
$post->images()->saveMany($images);
$post->tag($tags);
return response()->json([
'success' => true,
'message' => 'با موفقیت ویرایش گردید ',
'data' => $post
]);
}
The relation between posts and images is polymorphic one to many and I tested it with postman.
Postman
Database
And the path:
Please, help.
In store() method you saved images on disk by using
$imagePath = public_path(). '/images/posts/'.$postTitle;
$file->move($imagePath, $imageName);
In update() you deleted them
File::delete(public_path('/images/posts/'.$postTitle));
and determined path for new files
$imagePath = public_path(). '/images/posts/'.$postTitle;
but nothing happens after this. In whole update() method there is no code that could do something in storage, so of course nothing appears in folder ;)
So again use $file->move() or Storage facade to save files.
TIP
Also this is bad practice to repeat long code logic like that. It would be better to extract this and share between store/update.

getting error when i update image in my admin panel

I want to update my product table but when I update my product table, it throws this error :
ErrorException in CreatesController.php line 201: Undefined variable:
name
201 line is this: 'image'=> $name,
My product table contains following fields :
productname,image,price,category_id
This is CreatesController :
public function productupdate(Request $request, $id){
$this->validate($request, [
'productname'=>'required',
'image'=>'image|mimes:jpg,png,jpeg|max:10000',
'price'=>'required',
'category_id'=>'required'
]);
if($request->hasfile('image'))
{
$file=$request->file('image');
$new_name = rand(). '.' .
$path=public_path().'/images';
$name=$file->getClientOriginalName();
$file->move($path, $name);
$data=$name;
}
$data=array(
'productname'=> $request->input('productname'),
'image'=> $name,
'price'=> $request->input('price'),
'category_id'=> $request->input('category_id')
);
Product::where('id', $id)
->update($data);
return redirect('/item')->with('info','Product updated successfuly!');
}
If you are only updating the product details without uploading an image, then if($request->hasfile('image')) becomes false, as $name variable is not getting assigned. Try this..
public function productupdate(Request $request, $id) {
$this->validate($request, [
'productname' => 'required',
'image' => 'image|mimes:jpg,png,jpeg|max:10000',
'price' => 'required',
'category_id' => 'required'
]);
$data = array(
'productname' => $request->input('productname'),
'image' => null,
'price' => $request->input('price'),
'category_id' => $request->input('category_id')
);
if ($request->hasfile('image')) {
$file = $request->file('image');
$path = public_path() . '/images';
$name = $file->getClientOriginalName();
$file->move($path, $name);
$data['image'] = $name;
}
Product::where('id', $id)
->update($data);
return redirect('/item')->with('info', 'Product updated successfully!');
}

How can i avoid image required in edit form if image exist in laravel?

I am adding and editing a user with same function (Store), when ever i add a user it asks me image is required but whenever i edit a user which have image it also ask me image is required and i want if a image is already present it wont ask me , please see my above code i had recently changed my code according to Gurpal singh
In my controller
public function rules()
{
$child_details = Children::findOrFail($inputs['id']);
$rules = [
'child_name' => 'required',
'gender' => 'required',
'dob' => 'required',
'current_class' => 'required',
'b_group' => 'required',
'm_tongue' => 'required',
'image' => 'image',
];
if ($child_details->notHavingImageInDb()){
$rules['image'] = 'required|image';
}
return $rules;
}
public function Postchild(Request $request)
{
$data = \Input::except(array('_token')) ;
$validator = \Validator::make($data,$rules);
$inputs = $request->all();
if ($validator->fails())
{
return redirect()->back()->withInput()->withErrors($validator->messages());
}
if(!empty($inputs['id'])){
$child_details = Children::findOrFail($inputs['id']);
}else{
$child_details = new Children;
}
$child_details->parent_id = Auth::User()->id;
$child_details->child_name = $inputs['child_name'];
$child_image = $request->file('image');
if($child_image){
$tmpFilePath = 'uploads/childrens/';
$extension = $child_image->getClientOriginalExtension();
$hardPath = str_slug($inputs['child_name'], '-').'-'.md5(time());
$img = Image::make($child_image);
//$img->resize(180)->save($tmpFilePath.$hardPath.'-b.jpg');
$img->fit(250, 250)->save($tmpFilePath.$hardPath.'.'.$extension);
$child_details->image = $hardPath.'.'.$extension;
}
$child_details->save();
if(!empty($inputs['id'])){
return \Redirect()->route('child_list')->with('success', 'Child has been updated');
}else{
return \Redirect()->route('child_list')->with('success', 'Child has been added');
}
}
You can use Conditionally Adding Rules Not having image in database
Add this in model
public function notHavingImageInDb()
{
return (empty($this->image))?true:false;
}
This is the validation rule request
public function rules()
{
$user = User::find(Auth::id());
$rules = [
'name' =>'required|max:100',
'image' =>'image',
];
if ($user->notHavingImageInDb()){
$rules['image'] = 'required|image';
}
return $rules;
}
Don't forgot to import auth and user model
ie
use App\User;
use Auth;
for more detail click here
You can normally do like below :
$rule = array(
'name' => 'required',
);
if (!empty($inputs['id'])) {
$user = User::findOrFail($inputs['id']);
} else {
$rule["image"] = "required";
$user = new User;
}
It is better to separate them or simply create another function. But you can put an if statement that if the image is in the request or not.
Like this:
if(! isset($data['image'])){ //if the image is not in the request
//Your code
}
else{ //if the image is in the request
//Your code
}
If you want a code for storing, renaming, moving an image feel free to request.
You can use validation's after hook.
public function Postchild(Request $request)
{
//Define your rules
$rules = [
'child_name' => 'required',
'gender' => 'required',
'dob' => 'required',
'current_class' => 'required',
'b_group' => 'required',
'm_tongue' => 'required',
];
//Validate your data
$data = $request->except('_token');
$validator = \Validator::make($data,$rules);
$validator->after(function ($validator) {
//Check the mode of request (Create or Update)
if(!empty($data['id'])){
$child_details = Children::findOrFail($data['id']);
if($child_details->image == null){
$validator->errors()->add('image', 'Image field is required');
}
}
});
if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput();
}
}
Just this few lines can solve your problems... You have to check there image have or not.
Rules in a private or protected function
private function validateRequest($request)
{
//This is for Update without required image, this will check that In DB image have or not
$child_image = Children::find($request->id);
$rules = [];
if ($child_image) :
if ($child_image->image == null):
$rules['image'] = 'required|image|max:1999';
endif;
//This is for regular validation
else :
$rules = [
'image' => 'required|image|max:1999',
];
endif;
return $rules;
}

Lumen: update records via json body

I have a Laravel Lumen API. I'm seeing an issue with the update functionality.
In my controller, the code for updating an item is:
public function update(Request $request, $id)
{
$this->validate($request, [
'name' => 'required',
'description' => 'required',
'completed' => 'required',
]);
$todo = Todo::find($id);
$todo->name = $request->name;
$todo->description = $request->description;
$todo->completed = $request->completed;
$todo->save();
return response()->json(['status' => 'success']);
}
I can update the todo item using:
http://lumen-todo.app/api/51?name=test&description=test&completed=1
however was hoping I could send the parameters in a json body, like this
PUT http://lumen-todo.app/api
{
"id": 1
"name": "Test",
"description": "Test",
"completed": 1,
}
For adding items, it works via a json body, so don't understand why it does not work for updates. For info, the 'add item' controller code is here:
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required',
'description' => 'required',
'completed' => 'required'
]);
$todo = new Todo();
$todo->name = $request->name;
$todo->description = $request->description;
$todo->completed = $request->completed;
$todo->save();
return response()->json(['status' => 'success']);
}
If you want to get the json data from request payload, validate and store it, use
public function store(Request $request)
{
$data = $request->json()->all();
$this->validate($data, [
'name' => 'required',
'description' => 'required',
'completed' => 'required'
]);
$resource = $this->model->find($id);
$resource->fill($request);
$resource->save();
return response()->json(['status' => 'success']);
}
Instead of doing this:
$todo = new Todo();
$todo->name = $request->name;
$todo->description = $request->description;
$todo->completed = $request->completed;
$todo->save();
Do, this:
use App\Todo;
protected $model;
public function __construct(Todo $model) {
$this->model = $model;
}
$resource = $this->model->find($id);
$resource->fill($request);
$resource->save();
Also, you can do json_decode() function to change your json params to array and use that to validate and save data.

laravel 5.2 - store multiple value with sum

I have a 2 table user and reports
Report model
public function user() {
return $this->belongsTo('App\User', 'author_id');
}
User model
public function reports() {
return $this->hasMany('App\Report', 'author_id');
}
In User model there is a column called "sum_sales"
In Report model there is a column called "total"
Ho can I pass the sum(total) from my Report model to 'sum_total' inside my User model?
My report controller
public function store(Request $request)
{
$this->validate($request, ['title' => 'required',
'date' => 'required|date_format:d/m/Y|regex:/[0-9]{2}\/[0-9]{2}\/[0-9]{4}/',
'image_1' => 'required|mimes:png,jpeg',
'products' => 'required',
'total' => 'required',
'time' => 'required|min:2',
'location' => 'required',
'sub_location' => 'required',
]);
$user = Auth::user()->id;
$report = new Report($request->all());
$report->author_id = $user;
$image = $request->file('image_1');
$destinationPath = 'uploads/reports';
$ext = $image->getClientOriginalExtension();
$fileName = rand(11111,99999).'.'.$ext;
$report->image_1 = $image->move($destinationPath, $fileName);
$field_total = $request->input('total');
$sum_total = $report->sum('total');
$totalSum = $field_total + $sum_total;
$report->author_id->sum_sales = $totalSum;
$report->save();
Session::flash('flash_message', 'Report added!');
return redirect('dash/reports');
}
With this the browser say:
Indirect modification of overloaded property App\Report::$author_id has no effect
How can I figure out?
solved by Giedrius Kiršys
public function store(Request $request)
{
$this->validate($request, ['title' => 'required',
'date' => 'required|date_format:d/m/Y|regex:/[0-9]{2}\/[0-9]{2}\/[0-9]{4}/',
'image_1' => 'required|mimes:png,jpeg',
'products' => 'required',
'total' => 'required',
'time' => 'required|min:2',
'location' => 'required',
'sub_location' => 'required',
]);
$user = Auth::user()->id;
$report = new Report($request->all());
$report->author_id = $user;
$image = $request->file('image_1');
$destinationPath = 'uploads/reports';
$ext = $image->getClientOriginalExtension();
$fileName = rand(11111,99999).'.'.$ext;
$report->image_1 = $image->move($destinationPath, $fileName);
$report->save();
$sumUserTotal = User::find($user)->reports->sum('total');
Auth::user()->update(['sum_sales' => $sumUserTotal]);
Session::flash('flash_message', 'Report added!');
return redirect('dash/reports');
}

Resources