So in the following code I have to query the database each time for every image. It's quite slow. Is there a way to do this in a single query while keeping the actual image urls hidden like I currently have in the blade file?
Blade:
<img src="/image/1">
<img src="/image/2">
<img src="/image/3">
Route:
Route::get('/image/{id}', [ImageController::class, 'image']);
Controller:
public function image($id)
{
$img = DB::where('id', '=', $id)
->select('path', 'filename', 'extension')
->first();
$image_path = $img->path.'/'.$img->filename.$img->extension;
return response()->file( $image_path );
}
I'm basically getting the links from the database and the images should be accessible without having to login. I just want to hide the filename without having to change the actual filename to hash ids. The reason for this is because the filenames help me identify what I'm looking at. I just want to hide the filenames in the browser while not having to sacrifice performance.
CodePudding user response:
This looks like a perfect candidate for a View Composer:
app\Composers\ImageComposer.php
(New file in new Folder app\Composers
)
<?php
namespace App\Providers\Composers;
use App\Models\Image;
use Illuminate\View\View;
class ImageComposer {
public function compose(View $view) {
// Note: Important to use an `Image` model here for extended functionality
$images = Image::whereIn('id', [1, 2, 3])->get();
return $view->with(['images' => $images]);
}
}
app\Providers\AppServiceProvider.php
) (Existing File)
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Providers\Composers\ImageComposer;
class AppServiceProvider extends ServiceProvider {
public function boot() {
view()->composer('images', ImageComposer::class);
}
}
app\Models\Image.php
(New or Existing Model)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Image extends Model {
public function getDisplayPathAttribute() {
return $this->path. '/' . $this->filename . $this->extension;
}
public function getBase64EncodedStringAttribute() {
return 'data:image/' . $this->extension . ';base64,' . base64_encode(file_get_contents($this->display_path));
}
}
images.blade.php
(Existing file where your /images/1
, etc. code is)
@foreach($images as $image)
<img src="{{ $image->display_path }}"/>
<!-- OR -->
<img src="{{ $image->base64_encoded_string }}"/>
@endforeach
The basic logic here is that images.blade.php
is a view
, the Composer creates an $images
variable, which you can then iterate over and fill in the src
property with display_path
, which is an Accessor on your Image
model for returning the full path. Any time you render the images.blade.php
view, either via @include('images')
, or view('images')
, etc., it will have $images
available.