1
votes

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
If I understand you correctly, you only want the images from grandchildren, not children or grandgrandchildren? Or doesn't it matter? If not you can recursively loop through Children in your template. Give me a shout if this is sufficient enough for you.Marius Engen Haugen
I want an image from grandchildren pages. They have a chosen image per page which I want to display on their grandparent page in a random order. I can loop in the template just fine to get the grandchild images just not sort them randomly..pinkp

2 Answers

3
votes

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.

2
votes

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