Edward Palen
Edward Palen

Reputation: 565

FatalErrorException in routes.php line 113: Call to a member function delete() on null in Laravel 5.2

I am trying to delete a file through routes.php but it is generating the following error:

FatalErrorException in routes.php line 113: Call to a member function delete() on null

This is the view where the function is placed in the delete button.

<div class="col-md-12 col-xs-12">
        <div class="row">
            @foreach($properties->files as $index=>$file)

                  <div class="col-sm-6 col-md-2">
                    <div class="thumbnail">
                      <img src="{{ URL::asset('uploads/products/' . $file->name) }}" alt="{{ $file->property_id }}" width="300" height="200">
                      <div class="caption">
                        <div class="caption" align="center">
                            <form action="{{ url('file/'.$file->id) }}" method="POST" enctype="multipart/form-data">
                                {{ csrf_field() }}
                                {{ method_field('DELETE') }}
                                <button onclick="return confirm('Está seguro eliminar esta imagen?')" class="button btn btn-danger btn-xs" data-toggle="tooltip" data-placement="top" title="Eliminar imagen"><i class="material-icons delete-white">delete</i></button>
                            </form>
                        </div>
                      </div>
                    </div>
                  </div>           

            @endforeach
        </div>
    </div>

And this is the path I'm using to delete the file in the directory and database.

// Delete files
    Route::delete('/file/{id}', function ($id) {
        //File::findOrFail($id)->delete();
        $file = File::find(Input::get('id')->delete());

        $filename= Input::get('upload');
        $path = 'uploads/products/' . $file->filename;

        //return redirect('/');
        return redirect()->back()->with('success', 'Imagen eliminada satisfactoriamente!!!');

    });

Upvotes: 0

Views: 227

Answers (3)

Edward Palen
Edward Palen

Reputation: 565

Thanks for the recommendations, but I decided to change the method to handle these events.

1 - I create a new controller (FilesController) and through the controller I passed the parameters for elimination in the BD and the public path, for this controller we use the destroy method.

2 - I create a Route resource from the same controller.

This is the File model:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

use Illuminate\Database\Eloquent\SoftDeletes;

class File extends Model
{
    protected $table = 'files';

    protected $fillable = ['name', 'property_id'];

    // Relation with Property
    public function property()
    {
        return $this->belongsTo('App\Property');
    }
}

This is the FilesController method:

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Input;
use Illuminate\Http\Request;

use App\Http\Requests;
use App\File;
use Redirect;
use Storage;

class FilesController extends Controller
{
    public function destroy(Request $request, $id)
    {

        $file = File::find($id);

        $fileName = $file->name;

        //dd($fileName);

        $file_path = public_path() . "/uploads/products/" . $fileName;

        //dd($file_path);

        if(File::exists($file_path))
        { 
            unlink($file_path);
        }

        $file->delete();

        return redirect()->back()->with('success', 'Imagen eliminada satisfactoriamente!!!');

    }
}

The route:

Route::resource('properties','PropertyController');

And this is the part in the view that delete the files:

<div class="col-md-12 col-xs-12">
        <div class="row">
            @foreach($properties->files as $index=>$file)

                  <div class="col-sm-4 col-md-2">
                    <div class="thumbnail">
                      <img src="{{ URL::asset('uploads/products/' . $file->name) }}" alt="{{ $file->property_id }}" width="300" height="200">
                      <div class="caption">
                        <div class="caption" align="center">
                            {!! Form::open(['method' => 'DELETE','route' => ['files.destroy', $file->id],'style'=>'display:inline']) !!}

                                {!! Form::hidden('_method', 'DELETE') !!}

                                {!! csrf_field() !!}

                                @permission('role-delete')
                                <button onclick="return confirm('Se eliminara la propiedad de la lista')" class="button btn btn-danger btn-xs" data-toggle="tooltip" data-placement="top" title="Eliminar imagen" data-id="{{$file->id}}"><i class="material-icons delete-white">delete</i></button>
                                @endpermission

                            {!! Form::close() !!}
                        </div>
                      </div>
                    </div>
                  </div>           

            @endforeach
        </div>
    </div>

With this simple form we can remove an image of the DB and the public path.

I hope to collaborate with other passionate people.

Upvotes: 1

Carlos Adames
Carlos Adames

Reputation: 178

The error is generated because you are trying to retrieve a value from an input field which does not exist. You should read the documentation and see the difference between Input and Request Requests & Input

Since there is no input field in your form and you are just passing and id in your form request, change this

 $file = File::find(Input::get('id'))->delete();

to this

 $file = File::find(Request::segment(2))->delete();

It should work fine now.

Updated: Make sure you have your model class in your web route. Also make sure you're using Request use Illuminate\Http\Request; In your web route use Request. Do the following: Change this

// Delete files
Route::delete('/file/{id}', function ($id) {
    //File::findOrFail($id)->delete();
    $file = File::find(Input::get('id')->delete());

    $filename= Input::get('upload');
    $path = 'uploads/products/' . $file->filename;

    //return redirect('/');
    return redirect()->back()->with('success', 'Imagen eliminada satisfactoriamente!!!');

});

to this

// Delete files
Route::delete('/file/{id}', use function (Request $request) {

    File::findOrFail($request->segment(2))->delete();

    $filename= Input::get('upload');
    $path = 'uploads/products/' . $file->filename;

    //return redirect('/');
    return redirect()->back()->with('success', 'Imagen eliminada satisfactoriamente!!!');

});

Upvotes: 1

patricus
patricus

Reputation: 62368

When processing request input, there are two types of parameters: route parameters and query parameters. Route parameters are part of the url and are made available as parameters to the route handler (closure or controller method), whereas query parameters come from the query string and are made available through the request data (Input facade that you are using).

As written, your code has two issues. First, your file id is a route parameter, but you're trying to access it as if it were a query parameter. Second, you're actually attempting to call delete() on the id itself, which is actually null since it doesn't exist as a query parameter.

The line that you have commented out should work fine:

File::findOrFail($id)->delete();

It looks like you're also attempting to delete a file from the file system when you delete your File record. I would suggest you add a deleted() event to your File method, so that whenever a File model is deleted, it deletes the associated file from the file system.

class File extends Model
{
    public static function boot()
    {
        // make sure to call the parent boot
        parent::boot();

        // this function will be called whenever a File is deleted
        static::deleted(function ($model) {
            // delete the file when the model is deleted. very basic,
            // you'll want to add in more sanity checks, etc.

            // get the file path
            $path = 'uploads/products/' . $model->filename;

            // delete the file
            unlink($path);
        });
    }
}

You could also use the deleting() event, which will fire before the File record is deleted from the database. If you did this, you could return false from the event if the file fails to delete, and that will prevent the record from being deleted from the database.

Upvotes: 1

Related Questions