Silverstripe 3: create page control function to get images from grandchild pages and sort all randomly

2.3k views Asked by At

I'm trying to get a specific image ($FeaturedImage) from every grandchild page (GalleryPage.ss) of my Portfolio Page (PortfolioPage.ss) and display them in a random order.

I can get the images using the template easily enough. PortfolioPage.ss

<% loop Children %>
 <% loop Children %>
   <% loop FeaturedImage %>
      <img src="$Url"></>
   <% end_loop %>
 <% end_loop %>
<% end_loop %>

But this will display them in the order of the pages in the menu.

After some research it seems best to create a function in the page controller, but I'm not sure how to write this.. (anyone with a link to documentation / tutorials on these would also be great).

Examples of similar code found so far: get Dataobjects from Children - SilverStripe 3.1 http://www.silverstripe.org/template-questions/show/23296

Silverstripe docs: http://doc.silverstripe.org/framework/en/topics/datamodel

I'm just not sure how to apply this to my code..thanks

2

There are 2 answers

10
colymba On BEST ANSWER

Basically you need to create a function in your Portfolio Page Controller (or in whatever page you need this logic to be).

Here are 2 examples. First one just gets all the existing FeaturedImage from the database and returns then in random order:

function AllFeaturedImages()
{
    return FeaturedImage::get()->sort('RAND()');
}

And this one get all the FeaturedImage from the page's children's children and return them in random order:

function DescendantFeaturedImages()
{
    $featuredImages = array();

    foreach ($this->Children() as $child)
    {
        foreach ($child->Children() as $grandChild)
        {
            $images = $grandChild->FeaturedImage();
            if ( $images )
            {
                $featuredImages = array_merge( $featuredImages, $images->toArray() );
            }
        }
    }

    shuffle($featuredImages);

    return ArrayList::create($featuredImages);
}

If the FeaturedImage relation is just a has_one, this changes a little bit:

function DescendantFeaturedImages()
{
    $featuredImages = array();

    foreach ($this->Children() as $child)
    {
        foreach ($child->Children() as $grandChild)
        {
            $image = $grandChild->FeaturedImage();
            if ( $image )
            {
                array_push( $featuredImages, $image );
            }
        }
    }

    shuffle($featuredImages);

    return ArrayList::create($featuredImages);
}

Then in your Portfolio Page template you can just loop through the FeaturedImage by calling the function name. So here, either $AllFeaturedImages or $DescendantFeaturedImages. In your case you'll get something like:

<% loop $DescendantFeaturedImages %>
    <img src="$URL"/>
<% end_loop %>

I could find one example in the SilverStirpe tutorials using a Controller function: http://doc.silverstripe.org/framework/en/tutorials/2-extending-a-basic-site

Let me know how this goes.

0
Marius Engen Haugen On

I tried Colymba's code, and it worked like a champ. I would recommend following his code over the method I'm gonna explain below.

As you say in a comment, you can access grandparent images from template. You can use JavaScript, or as in this example jQuery, to randomly sort your images.

(function($){

    $.fn.shuffle = function() {

        var allElems = this.get(),
            getRandom = function(max) {
                return Math.floor(Math.random() * max);
            },
            shuffled = $.map(allElems, function(){
                var random = getRandom(allElems.length),
                    randEl = $(allElems[random]).clone(true)[0];
                allElems.splice(random, 1);
                return randEl;
           });

        this.each(function(i){
            $(this).replaceWith($(shuffled[i]));
        });

        return $(shuffled);

    };

})(jQuery);

And then call the function on the elements you want to sort randomly:

$('#imgholder img').shuffle();

A more thorough explanation can be found on css-tricks.com