Laravel 8.* + Backpack + Article with image (file upload)
In order to proceed you should have:
- Laravel installed + Backpack admin (teaching purposes)
- Tags CRUD created
- Article CRUD created
- virtual host ready for you
- xampp setup or other web server
- composer installed
Article
- title — 255 symbols
- content — text — RichTextEditor
- tags (many available) — select with multiple options
New tutorial to add file upload to the artilce
- image (one image) — image upload
#STEP 1: Create migration to add image to an article
php artisan make:migration add_image_to_articles_table --table=articles
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('articles', function (Blueprint $table) {
$table->string('image',255)->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('articles', function (Blueprint $table) {
$table->dropColumn('image');
});
}
We are adding a new column image — which will be used to store the url of the image. Next step is to run the migration.
php artisan migrate
Expected result.
#STEP 2: Alter Article model
We need to add extra items to use:
use Illuminate\Support\Str;
use Intervention\Image\ImageManagerStatic as Image;
use Illuminate\Support\Facades\Storage;
And then add two functions in FUNCTIONS section.
public static function boot()
{
parent::boot();
static::deleting(function($obj) {
Storage::delete(Str::replaceFirst('storage/','public/', $obj->image));
});
}
public function setImageAttribute($value)
{
$attribute_name = "image";
// destination path relative to the disk above
$destination_path = "public/articles";
// if the image was erased
if ($value==null) {
// delete the image from disk
Storage::delete($this->{$attribute_name});
// set null in the database column
$this->attributes[$attribute_name] = null;
}
// if a base64 was sent, store it in the db
if (Str::startsWith($value, 'data:image'))
{
// 0. Make the image
$image = Image::make($value)->encode('jpg', 90);
// 1. Generate a filename.
$filename = md5($value.time()).'.jpg';
// 2. Store the image on disk.
Storage::put($destination_path.'/'.$filename, $image->stream());
// 3. Delete the previous image, if there was one.
Storage::delete(Str::replaceFirst('storage/','public/', $this->{$attribute_name}));
// 4. Save the public path to the database
// but first, remove "public/" from the path, since we're pointing to it
// from the root folder; that way, what gets saved in the db
// is the public URL (everything that comes after the domain name)
$public_destination_path = Str::replaceFirst('public/', 'storage/', $destination_path);
$this->attributes[$attribute_name] = $public_destination_path.'/'.$filename;
}
}
First function will make sure that once we delete an entry — the file will be deleted as well.
Second function is a mutator responsible for the upload the image to the correct folder.
We have logic replacing /public folder with /storage folder due to the fact that images are exposed to end users using /storage folder.
#STEP 3: Install intervention/image
Run
composer require intervention/image
#STEP 4: Adjust Article controller
[
'label' => "Article Image",
'name' => "image",
'type' => 'image',
'crop' => true, // set to true to allow cropping, false to disable
'aspect_ratio' => 1, // omit or set to 0 to allow any aspect ratio
]
We need to adjust getFieldsData function and add the image column.
Our next change is related to setupListOperation method. We need to update it to the following
protected function setupListOperation()
{
$this->crud->set('show.setFromDb', false);
$this->crud->addColumns($this->getFieldsData(TRUE));
}
This will make sure that when we are adding images they will be shown on list as well.
#STEP 5: Make disk public and allow files to be shown
php artisan storage:link
#STEP 6: Time to test
Adding of an item
Edit of an item
List items table
Note: Files are uploaded to storage/app/public/articles
But they are available to the end users by accessing — DOMAIN/storage/articles/{IMAGE_NAME}