Merging collections in controller

Hello,

I am currently fetching all image of a set of pages in a controller like this:

<?php $masonry = page('page-a','page-b','page-c')->children()->listed()->images()->shuffle(); ?>

This works as expected, but was wondering if there is way to modify the controller to fetch only the first image of the children of page-a and page-b, but all of the images of the children of page-c, and then shuffle the result?

$pageAImages = page('page-a')->children()->listed()->images()->filter(function($image) {
  if($image->is($image->parent()->images()->first())) {
    return $image;
  }
});

$pageBImages = page('page-b')->children()->listed()->images()->filter(function($image) {
  if($image->is($image->parent()->images()->first())) {
    return $image;
  }
});
$pageCImages = page('page-c')->children()->listed()->images();

$allImages = new Files([$pageAImages,$pageBImages, $pageCImages]);

Oh my word, this is perfect – works like a charm! Thanks so much, @texnixe!

Now that I think about it, we should actually be able to shorten this some more:

$pageABImages = page('page-a', 'page-b')->children()->listed()->images()->filter(function($image) {
  if($image->is($image->parent()->images()->first())) {
    return $image;
  }
});

$pageCImages = page('page-c')->children()->listed()->images();

$allImages = new Files([$pageABImages, $pageCImages]);

Sorry to un-burry this older thread @texnixe but I have one more question regarding sorting. If I add a shuffle() after the last line

$allImages = new Files([$pageABImages, $pageCImages]);
$allImages = $allImages->shuffle();

it works as expected; however, if I change the last line to

$allImages = $allImages->sortBy('date', 'desc');

it does not seem to do anything; am I missing something obvious?

Do your images have a date field?

As a matter of fact, no - I can see the problem now :slight_smile: Is there a way to sort via the parent? I just tried

$allImages = $allImages->parent()->sortBy('date', 'desc');

but that does not really work, as I am fetching things in the template e.g. like this:

$item->parent()->coverimage()

$allimages doesn’t have a single parent. You could use the map function to map the parent’s date to each image file.

$sortedImages = $allImages->map(function($file) {
  $file->date = $file->parent()->date();
  return $file;
})->sortBy('date', 'desc');

It might be more performant to store the parent’s date in the file’s metadata for this use case.

Brilliant, tried & tested – that works!

But do I understand you correctly, you are suggesting in terms of performace it would be better to add a “date” field to the image?

I’d say it depends on the number of images. For the mapping, Kirby has to find the parent of each file, then read the content file, so I think that could slow things down in the long run. I have no idea how much faster it is if the date is stored directly in the meta data file. If you use the cache, it’s probably completely negligible.

But you might as well use a hook that stores the date of the parent in the files meta data whenever a new file is uploaded.

1 Like