ErikRobles's avatar

Unclear on how to delete single image from post from multiple images

Using Laravel 7, I can upload, add and delete all images from a task (post if it were a blog) but I am unclear on how to delete a single image from a task view (single post view). I am using resource controller for tasks but I assume I will need a different function. I created one in the same TasksController and about the resource controller, I created a delete route for it. My application complains that I am trying to get a property 'task_name' of non object when I click the single image delete button. I am not sure how to go about this or if I need to create an Image Controller (of which I am not using at the moment). I will show what I am attempting and maybe, you can tell me if I am off base or share some recommendations. So, to start off with, here is my web.php:

<?php

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');

Route::get('/users', 'UsersController@index');
Route::delete('delete-image', 'TasksController@delete')->name('delete-image');

Route::resource('tasks', 'TasksController');
Route::resource('users', 'UsersController');

My TasksController showing both my destroy method as well as my newly created delete method:

public function destroy($id)
    {
        $task = Task::with('images')->findOrFail($id);

        foreach ($task->images as $image) {
            Storage::disk('public')->delete('upload/' . $image->name);
        }

        $task->images()->delete();
        $task->delete();
        return redirect('home')->with('success', 'Task Deleted');
    }

    public function delete($id)
    {
        //
        $task = Task::with('images')->findOrFail($id);
        $task->images()->delete();

        $images = Image::find($id);
        Storage::disk('public')->delete('upload/' . $images->name);
        $images->name()->delete();
        return redirect('home')->with('success', 'Task Deleted');
    }

In my show.blade.php which would act as a single post view:

<div class="col-md-12">
                <h5>Images</h5>
                <hr />
                  <div class="row">
                      @if($task->images->count()>0)

                          @for($i=0; $i < count($images = $task->images()->get()); $i++)
                          <div class="col-lg-4 col-md-6 col-sm-12">
                            <a href="delete-image" class="badge badge-danger p-2 mb-3">Delete</a><br>
                            <a href="#" class="thumbnail" data-toggle="modal" data-target="#lightbox"><img class="w-50 mb-2" src="/storage/upload/{{ $images[$i]['name'] }}" alt=""></a>

                        </div>

                          @endfor
                          @else
                              <p>No images found</p>
                      @endif
                  </div>
                <br />
              </div>

In my Image.php Model my relationships are as follows:

public function task()
    {
        return $this->belongsTo('App\Task', 'task_id');
        // return $this->belongsTo(Task::class);
    }

    public static function boot()
    {
        parent::boot();
        self::deleting(function ($images) {

            // File::delete(Storage::path($images['name']));
            File::delete(str_replace('\', '/', storage_path('app/public/upload/' . $images->name)));
        });
    }

and in my Task.php Model:

public function images()
    {
        // return $this->hasMany('App\Image');
        return $this->hasMany(Image::class);
    }

    public static function boot()
    {
        parent::boot();
        self::deleting(function ($task) {
            foreach ($task->image ?: [] as $image) {
                $image->delete();
            }
        });
    }

If I missed anything, please let me know so I can modify my question. I really appreciate the help on this as I am a week behind. Thank you in advance.

0 likes
7 replies
jlrdw's avatar

Should be similar, go by name. In the loop if name matches that's the one.

ErikRobles's avatar

Hello and thanks for the response @jlrdw Should I create a separate function for this? I'm unclear as my app doesn't like my new function in the same controller.

newbie360's avatar

where the $id come from

Route::delete('delete-image', 'TasksController@delete')->name('delete-image');

public function delete($id)

and the blade file for loop i'm look very confuse xD,

JeromeFitzpatrick's avatar
Level 8

@erikrobles

  1. Add Route::delete('images/{image}', 'TasksController@deleteImage')->name('delete.image'); to your web.php file
  2. In your blade file, replace <a href="delete-image" class="badge badge-danger p-2 mb-3">Delete</a> with
<form action="{{route('delete.image', ['image' => $images[$i]['id']])}}" method="POST">
@method('delete')
<button type='submit' value='delete' />
</form>

Then in the TaskController for the method to delete the image, add:

public function deleteImage(Image $image)
{
  $image->delete();
  return redirect('home')->with('success', 'Image Deleted');
}

This is just to get it working. Afterwards you can style the delete button or use a link which sends the POST (delete) request using javascript.

1 like
ErikRobles's avatar

Hello @jeromefitzpatrick . I implemented the code you sent and it works great. The only problem left (related) is that after implementing it, yes it deletes form the db and storage, but now I cannot display the images as Laravel complains with the message Property [name'] does not exist on this collection referring to the line in show.blade.php <img src="/storage/upload/{{$images->name}}"> Any clues? Thanks mate. EDIT changed {{$images->name}} to {{ $images[$i]['name'] }} and now all is good. Thank you

Please or to participate in this conversation.