How do I delete and update a photo in Laravel 4? - php

In my application, a user can upload an image for their profile photo. How do I update a users photo and the delete the previously uploaded photo? This is what I have so far in the upload controller:
Photos Model
class Photos extends Eloquent {
protected $table = 'photos';
protected $fillable = array('user_id', 'location');
public function user (){
return $this->belongsTo('User');
}
}
user model
public function photos()
{
return $this->hasOne('photos');
}
Upload Controller
class UploadController extends \BaseController {
public function postUpload (){
$id = Auth::user()->id;
$input = Input::all();
$rules = array(
'photo' => 'required|image|max:500'
);
$validator = Validator::make($input, $rules);
if($validator->fails()){
return Redirect::to('user/profile/'.$id.'/edit')->withErrors($validator);
}
$extension = Input::file('photo')->getClientOriginalExtension();
$directory = public_path('/var/chroot/home/content/59/11581559/html/beta') . '/uploads/'.sha1($id);
$filename = sha1($id.time()).".{$extension}";
$upload_success = Input::file('photo')->move($directory, $filename);
Image::make(Input::file('photo')->getRealPath())->resize(300, 200)->save('foo.jpg');
if($upload_success){
$photo = new Photos(array(
'location' => URL::to('/uploads/'.sha1($id).'/'.$filename)
));
$photo->user_id = $id;
$photo->save();
Session::flash('success_photo', 'You have Successfully uploaded your profile photo!');
return Redirect::to('user/profile/'.$id.'/edit');
}
else{
Session::flash('status_error', 'An Error has occurred while uploading your photo. Please try again!');
}
return Redirect::to('user/profile/'.$id.'/edit');
}
}
View
<div class="col-lg-3">
<div class="panel panel-default">
<div class="panel-heading">
#if(Session::has('status_error'))
<div class="alert alert-error">
<a class="close" data-dismiss="alert" href="#" aria-hidden="true">×</a>
{{ implode('', $errors->all('<li class="error"><b>:status_error</b></li>')) }}
</div>
#endif
<span class="glyphicon glyphicon-exclamation-sign"></span> Upload a Photo
</div>
<div class="panel-body text-center">
#if($user->photos)
<img width="190" height="119" class="img-responsive img-thumbnail" src="{{$user->photos->location }}" alt="">
#endif
<div class="clearfix"></div>
<div class="btn-group mtop-20">
<button type="button" class="btn btn-primary" onclick="$('#upload_modal').modal({backdrop:'static'});">
<span class="glyphicon glyphicon-upload"></span>
</button>
</div>
</div>
<?php echo View::make('modals.photo-upload') ?>
</div><!-- end panel-default -->
</div><!-- col 3-->

Let's talk about what you're doing and work from there.
Uploading a Photo
- In your controller, you're uploading a photo.
- If the upload succeeds, you're storing the location of the photo on your server as well as the ID of the user to whom the photo belongs.
Updating a Photo
- In your controller, you're uploading a photo.
- If the upload succeeds, you're going to:
Get the location of the current file in the database.
$this->photo->where('user_id' , '=' , $the_user_id_in_question)
->get(array('location'));
Delete the file at that location using the delete() function in the FileSystem class (found here: https://github.com/laravel/framework/blob/master/src/Illuminate/Filesystem/Filesystem.php)
Update the user's photo location with the new one:
$this->photo->where('user_id' , '=' , $the_user_id_in_question)
->update('location' => $the_new_upload_location);
I hope that's what you're looking for. Cheers!

Related

Posts are not displaying on the Profile page

I am doing an Instagram clone project and I have encountered a tricky problem because, there is no error really, but the app is not functioning like its supposed to. Basically, I have added a functionality to instagram web application, where the user can add a post. Once the user uploads the image and caption, the create post page is supposed to redirect back to their profile. Which it does, perfectly. But the problem is, the uploaded posts are not displaying on the profile. Here is how my index.blade looks like
<div class="d-flex">
<div style="padding-right: 25px;"><strong>153</strong> posts</div>
<div style="padding-right: 25px;"><strong>2M</strong> followers</div>
<div style="padding-right: 25px;"><strong>300</strong> following</div>
</div>
<div><strong>{{$user->profile->title}}</strong></div>
<div>{{$user->profile->description}}</div>
<div>{{$user->profile->url}}</div>
</div>
<div class="row pt-5">
#foreach($user->posts as $post)
<div class="col-4>
<img src="storage/{{ $post->image }}" class="w-100">
</div>
#endforeach
</div>
</div>
My PostsController
class PostsController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function create()
{
return view('posts.create');
}
public function store(Request $request)
{
$data = $request->validate([
//'another =>'', Tells laravel to ignore all other fields
'caption'=>'required',
'image'=> 'required' ,
]);
if($request->hasfile('image'))
{
$data = $request->file('image');
$extension = $data->getClientOriginalExtension();
$filename = time().'.'.$extension;
$data->storeAs('uploads/public/', $filename);
}
$data = Auth::user()->posts()->create([
'caption'=>$request->caption,
'image'=>$request->image,
]);
$data = Auth::id();
return redirect()->route('Profile.show', [$data]);
//goes ahead and grabs the authenticated user
}
}
My routes
Route::get('/p/create', [App\Http\Controllers\PostsController::class, 'create'])->name('posts.create');
Route::post('/p', [App\Http\Controllers\PostsController::class, 'store']);
Route::get('/Profile/{user}', [App\Http\Controllers\ProfilesController::class, 'index'])->name('Profile.show');

Laravel Livewire image upload verification on edit form problem

I have a product page with an image upload form built with Livewire. when i revisit the page to update information, the page will only submit if I also pass through a new image even if I update other fields. I want it to keep the current uploaded image if the image form isn't touched, allow me to update other fields without a new image upload, and upload and replace the image url when that section is updated.
I have tried all sorts of validator modifiers - nullable, sometimes, and a few if statements and i can't seem to figure it out.
Here is my upload function in my Livewire Component:
public function updateProductVariant($id)
{
$productVariant = ProductVariant::find($id);
$validated = $this->validate([
'img_url'=>'sometimes|image',
'available_end_date'=>'required',
'available_start_date'=>'required',
'notes'=>'required',
]);
$img_url = $productVariant->img_url;
if($validated['img_url'] != "")
{
$name = $productVariant->id . '.' . $validated['img_url']->extension();
$this->img_url->storeAs('public', $name);
$img_url = "/storage/$name";
}
$categories = ['Dough', 'Merch' , 'Packaging' , 'Supplies' , 'Kits' ,
'Featured' , 'Upcoming' , 'Clearance'];
foreach($categories as $category) {
if($this->$category) {
ProductCategory::updateOrCreate(['category_name'=>$category , 'product_variant_id'=>$id],[]);
} else {
ProductCategory::where('category_name' , $category)->where('product_variant_id' , $id)->delete();
}
}
ProductVariant::updateorCreate(
['id' => $id],
[
'img_url' => $img_url,
'available_end_date' => $validated['available_end_date'],
'available_start_date' => $validated['available_start_date'],
'notes' => $validated['notes'],
]);
session()->flash('message', 'Product successfully updated');
$this->resetFields();
$this->emit('gotoTop');
return redirect("corporate/cookies");
}
And my relevant blade section:
<!--/form-group-->
<div class="mb-3">
<input class="form-control form-control-lg" type="file" id="img_url" name="img_url" wire:model="img_url">
<br>
#if($img_url && !is_string($img_url))
<div style="text-align: center;"> <img src="{{$img_url->temporaryUrl()}}" alt="" class="img-fluid rounded-3" style="max-width: 50%;"></div>
#endif
<div style="text-align: center;"> <img src="{{ $img_url }}" alt="" class="img-fluid rounded-3" style="max-width: 50%;"></div>
</div>
<!--/extra-->
<br>
<div class="d-grid mb-">
<button type="submit" class="btn btn-lg btn-block btn-primary" wire:click.prevent="updateProductVariant({{$item_id}})">Update</button>
</div>

Laravel 7 Delete array or single image from db and disk - Deletes post but not associated images from db nor disk

In Laravel 7, I am have a task management app. I can upload tasks (posts if it were a blog) and images. I have a multiple image upload working as expected. When it comes time to delete a task, the task deletes just fine but the images are left in the database and in the disk which is public into a folder called task-images. Being new to Laravel, I am struggling on how to go about this. I tried to change the settings in the filesystem.php (which I will post with the commented out code) but that didn't change the location as I had expected. In the end, I want to be able to delete the multiple images when I delete a post and also click delete on an individual image and delete that from both db and disk. I am using resource controller for all my task routes. I have no idea how to go about this and the tutorials that I have found don't really address my specific issue. Any help would be greatly appreciated. Thank you in advance.
Here is my task controller at TaskController.php
<?php
namespace App\Http\Controllers;
use App\Task;
use App\Image;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
class TasksController extends Controller
{
public function index()
{
$tasks = Task::orderBy('created_at', 'desc')->paginate(10);
return view('/tasks')->with('tasks', $tasks);
}
public function create()
{
return view('tasks.create');
}
public function store(Request $request)
{
$this->validate($request, [
'task_name' => 'required',
'task_description' => 'required',
]);
// Create Task
$user = Auth::user();
$task = new Task();
$data = $request->all();
$task->user_id = $user->id;
$task = $user->task()->create($data);
if ($request->hasFile('images')) {
$files = $request->file('images');
foreach ($files as $file) {
$name = time() . '-' . $file->getClientOriginalName();
$name = str_replace(' ', '-', $name);
$file->move('task-images', $name);
$task->image()->create(['name' => $name]);
$images = new Image;
$images->name = $name;
}
}
$task->task_name = $request->input('task_name');
$task->task_description = $request->input('task_description');
$task->task_priority = $request->input('task_priority');
$task->task_assigned_by = $request->input('task_assigned_by');
$task->task_assigned_to = $request->input('task_assigned_to');
$task->task_to_be_completed_date = $request->input('task_to_be_completed_date');
$task->task_notes = $request->input('task_notes');
$task->task_status = $request->task_status;
$task->save();
return redirect('/home')->with('success', 'Task Created');
}
public function edit($id)
{
$task = Task::find($id);
return view('tasks.edit', ['task' => $task]);
}
public function update(Request $request, $id)
{
$this->validate($request, [
'task_name' => 'required',
'task_description' => 'required',
]);
$task = Task::find($id);
$task->task_name = $request->input('task_name');
$task->task_description = $request->input('task_description');
$task->task_priority = $request->input('task_priority');
$task->task_assigned_by = $request->input('task_assigned_by');
$task->task_assigned_to = $request->input('task_assigned_to');
$task->task_to_be_completed_date = $request->input('task_to_be_completed_date');
$task->task_notes = $request->input('task_notes');
$task->task_status = $request->input('task_status');
if ($request->hasFile('images')) {
$files = $request->file('images');
foreach ($files as $file) {
$name = time() . '-' . $file->getClientOriginalName();
$name = str_replace(' ', '-', $name);
$file->move('task-images', $name);
$task->image()->create(['name' => $name]);
}
}
$task->update();
return redirect('/home')->with('success', 'Task Updated');
}
public function show($id)
{
$task = Task::find($id);
return view('tasks.show')->with('task', $task);
}
public function destroy($id)
{
$task = Task::findOrFail($id);
// $image = '/task-images/' . $task->image;
Storage::delete($task->image);
$task->delete();
return redirect('home')->with('success', 'Task Deleted');
}
}
filesystem.php (just the disks section)
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
// 'root' => public_path('task-images'),
],
...
in my individual show template, show.blade.php complete in case there is a code conflict.
#extends('layouts.master')
#section('content')
<div class="container">
Go Back
<div class="card p-3">
<div class="row">
<div class="col-md-4 col-sm-12">
<h3>Task</h3>
<p>{{ $task->task_name }}</p>
<h3>Assigned On:</h3>
<p>{{ $task->created_at->format('m/d/Y') }}</p>
<h3>Assigned To:</h3>
<p>{{ $task->task_assigned_to }}</p>
</div>
<div class="col-md-4 col-sm-12">
<h3>Task Description</h3>
<p>{{ $task->task_description }}</p>
<h3>Priority</h3>
<p>{{ $task->task_priority }}</p>
<h3>Status</h3>
<p>{{ $task->task_status }}</p>
</div>
<div class="col-md-4 col-sm-12">
<h3>Test Environment Date:</h3>
<p>{{ $task->task_to_be_completed_date }}</p>
<h3>Notes</h3>
<p>{{ $task->task_notes }}</p>
<h3>Action</h3>
<div style="display: inline;">
<a href="/tasks/{{$task->id}}/edit" class="btn btn-sm btn-primary mr-2">
<i class="fa fa-edit"></i> Edit
</a>
</div>
<form style="display: inline;" action="/tasks/{{ $task->id }}" method="POST" class="">
#csrf
#method('DELETE')
<button type="submit" class="btn btn-danger btn-sm ml-1 mr-1">
<i class="fa fa-trash"></i> Delete
</button>
</form>
</div>
<div class="col-md-12">
<h5>Images</h5>
<hr />
<div class="row">
#if($task->image->count()>0)
#for($i=0; $i < count($images = $task->image()->get()); $i++)
<div class="col-lg-4 col-md-6 col-sm-12">
<img class="w-50 mb-2" src="/task-images/{{ $images[$i]['name'] }}" alt="">
<form style="display: inline;" action="/tasks/{{ $task->name }}" method="POST" class="">
#csrf
#method('DELETE')
<button type="submit" class="btn btn-danger btn-sm ml-1 mr-1">
<i class="fa fa-trash"></i> Delete
</button>
</form>
</div>
#endfor
#else
<p>No images found</p>
#endif
</div>
<br />
</div>
</div>
</div>
</div>
<!--Modal Start-->
<div id="lightbox" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
<div class="modal-dialog">
<button type="button" class="close hidden" data-dismiss="modal" aria-hidden="true">×</button>
<div class="modal-content">
<div class="modal-body">
<img class="w-100" src="" alt="" />
</div>
</div>
</div>
</div>
<!--Modal End-->
#endsection
#section('scripts')
<script>
$(document).ready(function() {
var $lightbox = $('#lightbox');
$('[data-target="#lightbox"]').on('click', function(event) {
var $img = $(this).find('img'),
src = $img.attr('src'),
alt = $img.attr('alt'),
css = {
'maxWidth': $(window).width() - 100,
'maxHeight': $(window).height() - 100
};
$lightbox.find('.close').addClass('hidden');
$lightbox.find('img').attr('src', src);
$lightbox.find('img').attr('alt', alt);
$lightbox.find('img').css(css);
});
$lightbox.on('shown.bs.modal', function (e) {
var $img = $lightbox.find('img');
$lightbox.find('.modal-dialog').css({'width': $img.width()});
$lightbox.find('.close').removeClass('hidden');
});
});
</script>
#endsection
In my Task model, Task.php, I have:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Image;
class Task extends Model
{
protected $fillable = [
'task_name', 'task_priority', 'task_assigned_to', 'task_assigned_by', 'task_description', 'task_to_be_completed_date', 'task_status',
'task_notes'
];
public function user()
{
return $this->belongsTo(User::class);
}
public function image()
{
// return $this->hasMany('App\Image');
return $this->hasMany(Image::class);
}
}
and finally my Image Model Image.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\Task;
class Image extends Model
{
protected $fillable = [
'task_id',
'name',
];
protected $uploads = '/task-images/';
public function getFileAttribute($image)
{
return $this->uploads . $image;
}
public function task()
{
// return $this->belongsTo('App\Task', 'task_id');
return $this->belongsTo(Task::class);
}
}
If I am missing something, please let me know so I can edit my question. Again, thank you in advance for helping me with this issue. I have been scratching my head all week on this one. Cheers.
Edit
After implementing boot functions in my model as suggested below, I received an error that an invalid argument was used for foreach. I ran a dd($task); and the following image shows the result.
Final Edit
The answer below worked for my situation. I did have to edit some things to finalize the resolution:
in Task.php I changed the foreach to the following.
foreach($task->image ?: [] as $image)
I had declared image and not image in my model and that was causing a problem. Adding the ternary operator also helped the code not throw any errors.
In my TasksController.php I changed both the update and create functions with the same ternary operator as follows:
if ($request->hasFile('images')) {
$files = $request->file('images');
foreach ($files ?: [] as $file) {
$name = time() . '-' . $file->getClientOriginalName();
$name = str_replace(' ', '-', $name);
$file->move('task-images', $name);
$task->image()->create(['name' => $name]);
}
}
I hope this helps anyone else having the same issue. Thanks to #GrumpyCrouton and #lagbox for their help in resolving this as well as #user3563950
Without them, I would still by stratching my head for another couple of weeks.
on your App\Image class, implement to boot function with the following;
use Illuminate\Support\Facades\Storage;
public static function boot() {
parent::boot();
self::deleting(function($image) {
Storage::delete(Storage::path($image->name));
});
}
Also implement the boot method in App\Task class
use Illuminate\Support\Facades\Storage;
public static function boot() {
parent::boot();
self::deleting(function($task) {
foreach($task->images as $image) {
$image->delete();
}
});
}
Now on your TaskController implement the destroy method as follows;
public function destroy($id)
{
$task = Task::findOrFail($id);
$task->delete();
return redirect('home')->with('success', 'Task Deleted');
}
As a bonus, learn Laravel model binding to ease the pain of finding an instance using findOrFail()

Laravel how to upload an image to a database and show it in view

So i was making a form that consists of three field, the title, thumbnail, and textarea(with texteditor) and it seems that it upload the image just fine since i notice that there is images that i had uploaded in my /public/image folder after i submit the form, but when i check the database the thumbnail field showed not the name of the file in the /public/image folder like 20190713125534.jpg but
C:\xampp\tmp\phpC18A.tmp
im confused i thought it doesn't upload the image at all, but as i explained earlier it does, so my question is how do i change the value of thumbnail field with the filename and how do i show the image in my view ?
this is my Blogcontroller.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Blog;
use Validator,Redirect,Response,File;
class BlogController extends Controller
{
public function index()
{
$blogs = Blog::get();
return view('post.post_textarea',[
'blogs' => $blogs
]);
}
public function store(Request $request)
{
Blog::create([
'name' => $request->name,
'message' => $request->message,
'thumbnail' => $request->thumbnail,
]);
if ($files = $request->file('thumbnail')) {
$destinationPath = 'public/image/'; // upload path
$profileImage = date('YmdHis') . "." . $files->getClientOriginalExtension();
$files->move($destinationPath, $profileImage);
$insert['thumbnail'] = "$profileImage";
}
return redirect()->back();
}
public function getFullPost($blog_id) {
$blogs = Blog::where('id', '=', $blog_id)->get();
return view('post.read')->with(compact('blogs'));
}
}
this is my view for the form
<form enctype="multipart/form-data" method="POST">
{{csrf_field()}}
<div class="form-group">
<h4 style="color: black;" >Judul</h4>
<br>
<input type="text" class="form-control" name="name">
</div>
<div class="form-group">
<h4 style="color: black;" >Thumbnail</h4>
<br>
<input type="file" name="thumbnail">
</div>
<div class="form-group">
<h4 style="color: black;" >Isi</h4>
<br>
<textarea class="form-control" name="message" id="" rows="10"></textarea>
</div>
<div class="form-group">
<button class="pull-right site-btn" type="submit" >Upload<img src="../public/asset/img/icons/double-arrow.png" alt="#"/></button>
</div>
</form>
and this is my view to display the data from database
#foreach ($blogs as $blog)
<div class="blog-item">
<div class="blog-thumb">
<img src="asset/img/blog/1.jpg" alt=""> ->this is where i was supposed to fetch the image
</div>
<div class="blog-text text-box text-white">
<div class="top-meta">{{ Carbon\Carbon::parse($blog->created_at)->format('d-m-Y') }} / di Rakitan</div>
<h3>{{ $blog->name }}</h3>
<p>{!! \Illuminate\Support\Str::words($blog->message, 30, '...') !!}</p>
Lanjutkan Baca <img src="asset/img/icons/double-arrow.png" alt="#"/>
</div>
</div>
#endforeach
try to add this in controller
$blog = new Blog;
$blog->name = $request->name;
$blog->message = $request->message;
if($request->hasFile('thumbnail')) {
$file = Input::file('thumbnail');
//getting timestamp
$timestamp = str_replace([' ', ':'], '-', Carbon::now()->toDateTimeString());
$name = $timestamp. '-' .$file->getClientOriginalName();
$file->move(public_path().'/images/', $name);
$blog->thumbnail = url('/images/' . $name);
}
$blog->save();
return back();
than in your view
#foreach ($blogs as $blog)
<div class="blog-item">
<div class="blog-thumb">
<img src="{{ $blog->thumbnail }}" alt=""> ->this is where i was supposed to fetch the image
</div>
<div class="blog-text text-box text-white">
<div class="top-meta">{{ Carbon\Carbon::parse($blog->created_at)->format('d-m-Y') }} / di Rakitan</div>
<h3>{{ $blog->name }}</h3>
<p>{!! \Illuminate\Support\Str::words($blog->message, 30, '...') !!}</p>
Lanjutkan Baca <img src="asset/img/icons/double-arrow.png" alt="#"/>
</div>
</div>
#endforeach
The problem with your code, I think in your store function, you did not save it correctly. Please see my code below to save link of your thumbnail into db.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Blog;
class BlogController extends Controller{
//some your function goes here
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$blog = new Blog;
$blog->name = $request->input('name');
$blog->message = $request->input('message');
$file = $request->file('your_thumbnail');
//make sure yo have image folder inside your public
$destination_path = 'image/';
$profileImage = date("Ymd").".".$file->getClientOriginalName();
$file->move($destination_path, $profileImage);
//save the link of thumbnail into myslq database
$blog->thumbnail = $destination_path . $profileImage;
$blog->save();
return redirect()->back();
}
}

how to display images with laravel

I'm trying to upload images to my website but it does not show up
this is the HTML
<div class="col-md-10">
<div class="post-image">
<canvas style="display: none" id="canvas-preview" style="overflow:hidden;"></canvas>
<img id="img-preview" src="{{ url('backend/'). ($posts->preview_image?'/'. $posts->preview_image:'/post_preview/post-image.png')}}"> </div>
<div class="m-b-10">
<a id="upload-submit" class="btn btn-warning btn-block btn-sm" onclick="file.click();"><i class="fa fa-upload"></i> Upload Picture </a>
{{ Form::file('preview_image', ['class'=> 'btn btn-warning btn-block btn-sm','id'=>'file','style'=>'visibility:hidden']) }}
</div>
</div>
the controller:
public function create()
{ $this->authorize('create', Post::class);
return \View::make('posts.edit')
->with('posts', new \App\Models\Post);
}
and the model:
class Post extends Model
{
const DEFAULT_PREVIEW_IMAGE = "post_preview/post-image.png";
/**
* get preview image
* #return mixed|string
*/
public function getPreviewImage()
{
return $this->show_preview_image?$this->preview_image:static::DEFAULT_PREVIEW_IMAGE;
//return $this->preview_image;
}
}
I tried to add multiple extensions like jpg, jpeg or gif in the model but the problem persists
For laravel images should be stored in storage folder or you can create a folder inside storage folder. You also need to create symbolic link
php artisan storage:link
Here is how to upload the file to the storage folder
if ($request->hasFile('file_name')) {
$file = $request->file('file_name');
$fileName = str_replace(' ', '-', $file->getClientOriginalName());
$uploadPath = storage_path('app/public/folder_name');
$path = $request->file('file_name')->move($uploadPath, $fileName);
$uploadPathFile = $fileName;
}
Then you save the path to your DB.
For showing the image in the blade
<img src="/storage/folder_name/{{$data->image}}" alt="No image available" class="img-thumbnail">
Here $data->image is only the path
is your image stored in a public directory - try accessing the URL in your browser to see if the response is the expected image.
If not please provide more details how are you trying to retrieve the image (via binary response or stored as a public asset)?

Categories