Laravel 11.x + Backpack + Article with image (file upload)

Lyubomir Filipov
3 min readDec 16, 2024

--

In order to proceed you should have:
- Laravel installed + Backpack admin (teaching purposes)
- Tags CRUD created
- Article CRUD created

Note: There is an older version of this tutorial before Backpack 11.x

#STEP 1: Create migration to add an image to an article

php artisan make:migration add_image_to_articles_table --table=articles

edit the file so it looks like this

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('articles', function (Blueprint $table) {
$table->string('image',255)->nullable();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('articles', function (Blueprint $table) {
$table->dropColumn('image');
});
}
};

We are adding a new column to the articles table. In the down method, we are removing the column. The new column will hold information about the image name.

#STEP 2: Run migration

php artisan migrate

The expected end result of running the query is adding a new column to the tables.

#STEP 3: Alter the Articles model

use Illuminate\Support\Str;
use Illuminate\Support\Facades\Storage;

We are going to use Str support and facade for the Storage. We need to be able to delete the uploaded image once:

  • new image is added
  • the entity is deleted
public static function boot()
{
parent::boot();
static::deleting(function($obj) {
if ($obj->image) {
// Remove 'storage/' from the start of the path to get the relative path
$path = str_replace('storage/', '', $obj->image);
$response = Storage::disk('public')->delete($path);
}
});
}


private function deleteImage($attribute_name) {
// Remove 'storage/' from the start of the path to get the relative path
$path = str_replace('storage/', '', $this->{$attribute_name});
$response = Storage::disk('public')->delete($path);
}


public function setImageAttribute($value)
{
$attribute_name = "image";
// destination path relative to the disk above
$destination_path = "articles";

// if the image was erased
if ($value==null) {
$this->deleteImage($attribute_name);
// set null in the database column
$this->attributes[$attribute_name] = null;
} else {
$this->deleteImage($attribute_name);
$disk = "public";
// filename is generated - md5($file->getClientOriginalName().random_int(1, 9999).time()).'.'.$file->getClientOriginalExtension()
$this->uploadFileToDisk($value, $attribute_name, $disk, $destination_path, $fileName = null);
$this->attributes[$attribute_name] = 'storage/' . $this->attributes[$attribute_name];
}
}

The first function will make sure that once we delete an entry — the file will be deleted as well.

The second function is a mutator that is responsible for uploading the image to the correct folder.

Note: We need to delete the old entry (image) in two cases. Once when the image is removed or when the image is replaced by another image.

#STEP 4: Adjust Articles controller

Add the following code

[
'label' => "Article Image",
'name' => "image",
'type' => ($show ? 'view' : 'upload'),
'view' => 'partials/image',
'upload' => true,
]

to the getFieldsData function

and also adjust setupListOperation function

/**
* Define what happens when the List operation is loaded.
*
* @see https://backpackforlaravel.com/docs/crud-operation-list-entries
* @return void
*/
protected function setupListOperation()
{
$this->crud->set('show.setFromDb', false);
$this->crud->addColumns($this->getFieldsData(TRUE));

/**
* Columns can be defined using the fluent syntax or array syntax:
* - CRUD::column('price')->type('number');
* - CRUD::addColumn(['name' => 'price', 'type' => 'number']);
*/
}

#STEP 5: Create new view for the image

Create a new view file in /resources/views/partials/image.blade.php

Content of the view file:

@if(isset($entry->image))
<img src="/{{ $entry->image }}" width="120" alt="Article image" />
@endif

#STEP 6: Make the disk public and allow files to be shown

php artisan storage:link

Test everything

--

--

Lyubomir Filipov
Lyubomir Filipov

Written by Lyubomir Filipov

Group Architect at FFW, believer, developer, enthusiast

No responses yet