How to store an image as a link inside my Database in laravel-8 that will be used in frontend Vue.js?

Viewed 1386

I developed one controller, model, and migration table. I want to store an image as a URL in my database which should be displayed on my frontend page, for that I write in the migration table as a file column as a binary it's not storing as a URL format inside my database, please help me how to store that image path as a url-link inside my database which should be reused in my frontend pages

Books migration table

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateBooksTable extends Migration {
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up() {
        Schema::create('books', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('author');
            $table->integer('price');
            $table->binary('file')->nullable();
            $table->integer('quantity');
            // $table->string('file')->nullable();
            $table->string('description');
            $table->unsignedBigInteger('user_id');
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down() {
        Schema::dropIfExists('books');
    }
}

FileController.php

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Books;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Auth;
use SebastianBergmann\CodeCoverage\StaticAnalysis\Cache;
use App\Http\Resources\Books as BookResource;

class FileController extends Controller {    
    public function upload(Request $request) {
        $book = new Books();
        $book->price=$request->input('price');
        $book->name=$request->input('name');
        $book->quantity=$request->input('quantity');
        $book->author=$request->input('author');
        $book->description=$request->input('description');
        $book->file=$request->file('file')->store('apiDocs','public');
        $book->user_id = auth()->id();
        $book->save();
        return new BookResource($book);
    }
}

Books.php

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Books extends Model {
    use HasFactory;
    protected $fillable = [
        'file',
        'price',
        'name',
        'quantity',
        'description',
        'author'
    ];
    protected $hidden = [
        'password',
        'remember_token',
        'updated_at'
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    /**
     * Return a key-value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims() {
        return [];
    }

    /**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier() {
        return $this->getKey();
    }
   
    //inverse one to many
   public function user() {
       return $this->belongsTo(User::class);
   }
}

How inside my database storing

mysql> select * from books \G;

*************************** 1. row ***************************
         id: 1
       name: Vue
     author: flysystem
      price: 999
       file: 0x617069446F63732F4953356145597479614A657361616D395838495933426D545171696E47733274346C6C54774857732E706E67
   quantity: 2
description: laravel
    user_id: 3
 created_at: 2021-07-06 11:40:16
 updated_at: 2021-07-06 11:40:16

1 row in set (0.12 sec)
2 Answers

Follow this ways step by step:

0- Change your column type of migration from binary to text or string.

1- Create function that store your files in storage: (You can create this function in trait for reusability)

protected function uploadImages($file, $path)
{
    $date = Carbon::now();
    $filePath = $path . "/$date->year";
    $filename = $date->timestamp . '_' . $file->getClientOriginalName();
    return $file->storeAs(
        $filePath, $filename, 'public'
    );
}

this function return path to your file like: images/books/2021/YOUR_FILE_NAME

2- use this function for uploading files:

public function store(Request $request)
{
    $imagesUrl = $this->uploadImages($request->file('image'), '/images/books');
}

3- Create symlink to your storage:

php artisan storage:link

4- Finally, in vue you can access images like:

<img :src="getImage(book.image)" class="img-fluid index-post-image rounded" :alt="post.slug">

methods : {
  getImage(image) {
    return process.env.VUE_APP_SERVER_URL + '/storage/' + image;
  }
}

change the file type to string and in your controller use the method below to save your file in backend public folder and the link in the database.

Books migration table

$table->string('file')->nullable();

FileController.php

$image = $request->file;
$rand = hexdec(uniqid()); //random unique name for the file
$extension = strtolower($image->getClientOriginalExtension());
$img_name = $rand.'.'.$extension;
$up_location = 'image/'; //location in public folder to save file
$image->move($up_location, $img_name);
$book->file= = $up_location.$img_name;

it will save the image as: image/*filename*, you can add your backend url in front of it to read it in frontend.

for example if your backend url is api.domain.com:

<img :src="'api.domain.com'+book.file">
Related