daugaard47
daugaard47

Reputation: 1868

Random images in laravel

I have a database table called random_img. Inside are 10 rows for 10 images.

I will be pulling the images from public/images/random

I want to use the database so I can set the loop to Random take(1). I want to use in my hero images. (New image on every page refresh)

Where would I put my database query so I can use it Globally? Or how can I use my RandomImgsController so it is being used globally?

I created a route file, so I can use it as an include where needed.

Route:

Route::post('/layouts/inc/random-img','RandomImgsController@randomimg')->name('random-img');

Include:

@include('layouts.inc.random-img')

Inside Include:

  @foreach ($randomimg as $rand)
  <span class="hero-image">
            <img src="/images/random/{{$rand->file_name}}" class="img--max--hero blur-img">
            </span>
@endforeach

RandomImgsController: (Where should this go so I can use globally)

public function randomimg()
{
    $randomimg = DB::table('randomimg')->orderBy(DB::raw('RAND()'))->get();
    return view('random-img',compact('randomimg'));
}}

This is what I want to achieve on every page of my website:

@php
$randomimg = DB::table('randomimg')->orderBy(DB::raw('RAND()'))->get()->take(1);    
@endphp
  @foreach ($randomimg as $rand)
  <span class="hero-image">
            <img src="/images/random/{{$rand->file_name}}" class="img--max--hero blur-img">
            </span>
@endforeach

What would be a cleaner way to do this?

Update:

I can access the images DB in all views now, but I have an issue.

In my App\Http\ViewComposer\ImageComposer.php file I have this:

public function compose(View $view)
{
    $view->with('foo', Image::inRandomOrder()->get()->take(1));
}

In any view I can use {{$foo}} to get a random row from my images table, but the data comes in a string like this:

[{"id":10,"alt":"Image Alt Tag","title":"Image Title","file_name":"10.jpg"}]

When I try to only grab individual columns like this {{$foo->file_name}}

I get the error:

Property [file_name] does not exist on this collection instance.

How can I grab individual columns like this: {{$foo->alt}} , {{$foo->title}} and {{$foo->file_name}} then cleanly output them in my view? Example, I need {{$foo->file_name}} to render like this: 5.jpg.

Update 2: I figured it out. Have to use @foreach since I'm using the get() method.

@foreach($foo as $f)
{{$f->file_name}}
@endforeach

Would still like to know if there is a way to do it without the get() method. This will work though.

Upvotes: 1

Views: 2789

Answers (1)

Dan Fletcher
Dan Fletcher

Reputation: 1248

First of all you can't @include a route in a blade template. What you would actually do is send an AJAX request from your blade template to the route you created to retrieve the random images. However...

It sounds like a controller is the wrong place for the logic in this situation.

Assuming you have an associated Eloquent model for your table, a simple option could be to define a method on your RandomImage model (could probably just be called Image).

This way, you can just use your Image model to generate and pass a random image to any view you would like. Then there is also no need to query for every image on each page reload. You would only ever be querying for one image per request.

Imagine if the code in your view could look like this:

<span class="hero-image">
    <img 
        src="{{ $image->url() }}" 
        class="img--max--hero blur-img" />
</span>

And maybe this belongs in a home page for example, which is what it sounds like you're trying to do. So maybe you have a route like this:

Route::get('/', function () {
    $image = App\Image::random();
    return view('home', compact('image');
});

You could achieve this using a Query Scope on your Image model:

public function scopeRandom($query)
{
    return $query->inRandomOrder()->first();
}

Edit

If you want this to be used across many, or even all views in your website you can use a View Composer: https://laravel.com/docs/5.6/views#view-composers

Your compose method would look like this:

public function compose(View $view)
{
    $view->with('image', Image::random());
}

And the View Composer would be registered either in your AppServiceProvider or in a new provider such as ComposerServiceProvider. Inside of the boot method you need:

public function boot()
{
    // Using class based composers...
    View::composer(
        '*', 'App\Http\ViewComposers\ImageComposer'
    );
}

Where the * says that you want this composer to be applied to all views.

Upvotes: 3

Related Questions