graker / oc-photoalbums-plugin

Photo albums plugin for OctoberCMS
MIT License
12 stars 8 forks source link

Is there a way to output all the albums with all their respective images? #8

Closed Nvironmental closed 5 years ago

Nvironmental commented 5 years ago

Hi Graker,

Wanted to know if there is a way to output all the albums with all the photos in it. Currently I can only output list of Albums and one complete album set at a time using its slug (I could add this component multiple times with individuals album slug but this wont scale once you have large number of albums).

Thanks

graker commented 5 years ago

Hi,

No, there's no such component in the plugin. You can probably go through albums in AlbumList component accessing $album->photos directly. Though photos aren't eager-loaded with albums by default. So you should add a hook like onRun() to where you use a component, and then try to eager-load all photos on albums manually to avoid N+1 queries problem.

Or feel free to PR a new component :)

graker commented 5 years ago

Closing it for now, please reopen if any further questions.

Nvironmental commented 5 years ago

Hi Graker,

I am not able to crack this,

No, there's no such component in the plugin. You can probably go through albums in AlbumList component accessing $album->photos directly. Though photos aren't eager-loaded with albums by default. So you should add a hook like onRun() to where you use a component, and then try to eager-load all photos on albums manually to avoid N+1 queries problem.

Can you please guide me more. Please. Thanks

graker commented 5 years ago

@Nvironmental ,

I can take a peek if you elaborate on what exactly you're doing (code samples included) and what exactly doesn't work as expected (error messages/behaviour description included).

Nvironmental commented 5 years ago

Hi Graker attaching snaps of code here

screenshot 2019-02-26 at 9 53 57 pm screenshot 2019-02-26 at 9 54 11 pm screenshot 2019-02-26 at 9 54 18 pm

Not getting any errors but not getting any results either.

$album->photos = $album->photos->getThumb( $this->property('thumbWidth'), $this->property('thumbHeight'), ['mode' => $this->property('thumbMode')] );

Tried this but it gives an error of getThumb doesn't exist.

graker commented 5 years ago

This:

$album->photos->getThumb( $this->property('thumbWidth'))

is wrong: photos is an array (collection, to be exact) so you have to go over it with foreach. Try to remove all your changes and just go over photos right in your template (like it is done in single album component).

If that works, try to insert $albums->load('photos') in onRun() instead of all code you have in the first screen.

If that doesn't work, post code samples and we'll look into it.

P.S. If you don't mind, please try to insert code between triple backticks instead of making screenshots so I could copy it.

Nvironmental commented 5 years ago

Hi Graker, apologies for not being mindful about the backticks for pasting code.

tried the following

==
 function onRun()
{
    $albums->load('photos');

}
==
{% set album = photoAlbum.album  %}
<div class="albums-list row">
    {% for album in albumList.albums %}
    <div class="album-photos row">
    {% for photo in album.photos %}
        <div class="photo col-xs-12 col-sm-6 col-md-4 col-lg-3">
            <a href="{{ photo.url }}"><img
                    data-src="{{ photo.thumb }}"
                    src="{{ photo.thumb }}"
                    alt="{{ photo.title }}"
                    title="{{ photo.title }}"
                    style="max-width: 100%" />
            </a>
            <a href="{{ photo.url }}"><strong>{{ photo.title }}</strong></a>
        </div>
    {% else %}
        <div class="col-xs-12 no-data">Album doesn't have any photos yet</div>
    {% endfor %}
</div>
<div class="album-preview col-xs-12 col-sm-6 col-md-4 col-lg-3">
            <h3><a href="{{ album.url }}">{{ album.title }}</a></h3>
            <a href="{{ album.url }}">
                <img
                    data-src="{{ album.latestPhoto.thumb }}"
                    src="{{ album.latestPhoto.thumb }}"
                    style="max-width: 100%" />
            </a>
            Created on {{ album.created_at|date('M d, Y') }}
            {{ album.photo_count }} images
        </div>
    {% else %}
        <div class="col-xs-12 no-data">You have not created any albums yet</div>
    {% endfor %}
</div>

This does loop over the photos and gives me the titles of my photos(wherever they exist) [attached a reference screenshot] screenshot 2019-02-28 at 11 22 46 am

But fails to load the path/url of the photos

Also tried to use {{album.photos}}

which returns

{"id":67,"user_id":null,"album_id":1,"title":"Raj Mahal Complex","description":"","created_at":"2019-02-11 13:03:39","updated_at":"2019-02-13 05:44:55","sort_order":67,"photo_location":"Tikamgarh, Madhya Pradesh","photo_latitude":"","photo_longitude":""},{"id":66,"user_id":null,"album_id":1,"title":"Mahal Complex","description":"","created_at":"2019-02-11 13:03:39","updated_at":"2019-02-13 05:44:27","sort_order":66,"photo_location":"Tikamgarh, Madhya Pradesh","photo_latitude":"","photo_longitude":""},{"id":65,"user_id":null,"album_id":1,"title":"Raj Mahal & Ruins","description":"","created_at":"2019-02-11 13:03:39","updated_at":"2019-02-13 05:43:54","sort_order":65,"photo_location":"Tikamgarh, Madhya Pradesh","photo_latitude":"","photo_longitude":""},{"id":64,"user_id":null,"album_id":1,"title":"Cenotaphs","description":"","created_at":"2019-02-11 13:03:39","updated_at":"2019-02-13 05:43:06","sort_order":64,"photo_location":"Tikamgarh, Madhya Pradesh","photo_latitude":"","photo_longitude":""},{"id":63,"user_id":null,"album_id":1,"title":"Cenotaphs","description":"","created_at":"2019-02-11 13:03:38","updated_at":"2019-02-13 05:42:28","sort_order":63,"photo_location":"Tikamgarh, Madhya Pradesh","photo_latitude":"","photo_longitude":""},{"id":62,"user_id":null,"album_id":1,"title":"Orchha","description":"","created_at":"2019-02-11 13:03:38","updated_at":"2019-02-12 19:08:07","sort_order":62,"photo_location":"Tikamgarh, Madhya Pradesh","photo_latitude":"","photo_longitude":""}]

So it does loop over photos in the album and fetches the fields set for it except the path or url of the photo

screenshot 2019-02-28 at 11 29 52 am

Let me know how to proceed

graker commented 5 years ago

Yeah, I forgot that image file relation is not loaded automatically when photo model is loaded.

Try to replace

function onRun()
{
    $albums->load('photos');
}

with

function onRun()
{
    $albums->load('photos', 'photos.image');
}

It also could be 'photos.images', try both :)

Nvironmental commented 5 years ago

Hi Graker,

tried

function onRun()
{
    $albums->load('photos', 'photos.image');
}

and

function onRun()
{
    $albums->load('photos', 'photos.images');
}

But no luck, got the same output as before with no file path or url:

{"id":67,"user_id":null,"album_id":1,"title":"Raj Mahal Complex","description":"","created_at":"2019-02-11 13:03:39","updated_at":"2019-02-13 05:44:55","sort_order":67,"photo_location":"Tikamgarh, Madhya Pradesh","photo_latitude":"","photo_longitude":""},{"id":66,"user_id":null,"album_id":1,"title":"Mahal Complex","description":"","created_at":"2019-02-11 13:03:39","updated_at":"2019-02-13 05:44:27","sort_order":66,"photo_location":"Tikamgarh, Madhya Pradesh","photo_latitude":"","photo_longitude":""},{"id":65,"user_id":null,"album_id":1,"title":"Raj Mahal & Ruins","description":"","created_at":"2019-02-11 13:03:39","updated_at":"2019-02-13 05:43:54","sort_order":65,"photo_location":"Tikamgarh, Madhya Pradesh","photo_latitude":"","photo_longitude":""},{"id":64,"user_id":null,"album_id":1,"title":"Cenotaphs","description":"","created_at":"2019-02-11 13:03:39","updated_at":"2019-02-13 05:43:06","sort_order":64,"photo_location":"Tikamgarh, Madhya Pradesh","photo_latitude":"","photo_longitude":""},{"id":63,"user_id":null,"album_id":1,"title":"Cenotaphs","description":"","created_at":"2019-02-11 13:03:38","updated_at":"2019-02-13 05:42:28","sort_order":63,"photo_location":"Tikamgarh, Madhya Pradesh","photo_latitude":"","photo_longitude":""},{"id":62,"user_id":null,"album_id":1,"title":"Orchha","description":"","created_at":"2019-02-11 13:03:38","updated_at":"2019-02-12 19:08:07","sort_order":62,"photo_location":"Tikamgarh, Madhya Pradesh","photo_latitude":"","photo_longitude":""}]

Was wondering since, we are getting id for each photo in the album, could there be a way to fetch it via that method.

Sincere thanks for your time and help on this :)

graker commented 5 years ago

It's worth also trying just $albums->load('photos.image'); but I was sure one of those two should have worked.

Yes, off course you can fetch images by id, but it would be very ineffective to run a query to fetch each image. Images should be eager-loaded, I just don't see yet why they are not. Maybe because they are related using October attachment and not original hasOne/belongsToOne.

I think it's also worth to try this:

function onRun()
{
    $albums->load(['photos' => function ($query) {
      $query->with('image');
    }]);
}
graker commented 5 years ago

Also note that even if it works and attached image will be loaded, you shouldn't access thumbs as {{ photo.thumb }} because that thumb is created in the component's prepareAlbums() method and it is't happening for photos you've just loaded. So I believe you should access your image' thumb like this:

<img src="{{ photo.image.thumb(100, 100, auto) }}"/>
Nvironmental commented 5 years ago

Hi Graker,

Thanks for your incredible help and support. I was finally able to crack this using

 {% for album in albumList.albums %}
    {% for photo in album.photos %}
      <img src="{{ photo.image.path() }}"/>
    {% endfor %}
 {% endfor %}

On side note: Even if we do not put onRun() code for eager loading, we still get all the photos for that album

Thanks once again :)

graker commented 5 years ago

Hi @Nvironmental ,

It does because Laravel lazy-loads each relation when you're accessing it. But it leads to running as much DB queries as there are photos. So if you'd install a debugbar and inspect DB queries made for the request, I believe you'd see N queries of photos table and N queries of images table where N is overall amount of photos. And if I wrote that last sample of eager-loading code correctly, running with it in place would show exactly 1 query of photos and 1 query of images.

So I'd recommend to keep eager-loading code for better performance (that is if it works).

Nvironmental commented 5 years ago

Absolutely! Thanks for your inputs 👍 Cheers 🥂