Random object per page request with SilverStripe
Asked Answered
E

2

6

Lets say you show a random statement per page request and use a function to return a random object like:

Statement::get()->sort("RAND()")->limit("1");

But now in the template you want to reference it twice in different places but it should be the same statement and not a randomly different one. How would you make sure to get the same random object per page request?

Eddie answered 3/4, 2013 at 20:33 Comment(2)
whoever downvoted this, please leave a comment why you did so? question seems clear to me, upvotingFranklynfrankness
This was a real question. I really dislike this "let's close it" attitude...Mcgriff
T
4

What about defining a function with a static variable that remembers the object?

public function rndObj() {
   static $obj = null;
   if(!isset($obj)){
      $obj = Statement::get()->sort("RAND()")->limit("1")->first();
   }
   return $obj;
}

and then use rndObj in the template.

Thy answered 3/4, 2013 at 20:57 Comment(13)
thx but this still returns a random object and not the same if you call it twice in the same requestEddie
@Eddie Did you place the definition of rndObj in the page controller? It works for me (tested using SilverStripe 2.4)Thy
I'm on sstr3. It doesn't make a difference if I put the function in controller or the model. The statement has a picture and a testimonial but they still do not match.Eddie
@Eddie Strange. However, can you place the picture and the testimonial inside the same control, like <% control rndObj %> $picture $testimonial <% end_control %> ?Thy
i could, but this is ugly, since i have to use js to put it else whereEddie
shouldn't you place the line static $obj = null outside the function? they way it is currently, you're re-initialising the variable each time rndObj() is called, therefore you get a new value each timeFranklynfrankness
@Franklynfrankness Since the variable is declared static it is only initialized when the function is defined, not on every call. Even if called from different instances of the class in which it is defined, it should give the same result.Thy
@Franklynfrankness I thought the same and tried that but did also not work. Since i did not know any better I just got the random-statement in init got the ID of the object and made this global. Now the getter-function just filters for this ID. I still would like to know a cleaner approach. ` public function init() { parent::init(); global $statmentID; $obj = Statement::get()->sort("RAND()")->limit("1"); $statmentID = $obj[0]->ID; } public function RSt() { global $statmentID; return Statement::get()->filter(array('ID' => "$statmentID")); }`Eddie
@TerjeD. thanks for the explanation, php is still a mystery for meFranklynfrankness
@Eddie The code above must work. If it doesn't, you have a more serious issue elsewhere, e.g. the templates are rendered in different requests or one of them has been cached or... who knows.Mcgriff
@Eddie Disregard my previous comment. You must use Statement::get()->sort("RAND()")->limit("1")->first() instead to trigger the real query execution in SilverStripe 3.Mcgriff
@Mcgriff & schellmax thx you for upvoting and looking at this again. I appreciate it very much and think people like you make stackoverflow a cool place! you are right but i do not get it why, I need to select explicitly the first of just one item to make this work?Eddie
@Eddie The new ORM introduced in SilverStripe 3 uses lazy evaluation. Statement::get()->sort("RAND()")->limit("1") prepares the query but do not execute it: this is done while accessing the result, e.g. by reading its first() element. See silverstripe.org/silverstripe-3-s-new-orm for the rationale.Mcgriff
F
1

One way to do this is to fetch the random statement in the controller init function and assign this to a private variable. We add a getRandomStatement function to fetch the random statement:

class Page_Controller extends ContentController {

    private $randomStatement;

    public function init() {
        parent::init();

        $this->randomStatement = Statement::get()->sort('RAND()')->limit(1)->first();
    }

    public function getRandomStatement() { 
        return $this->randomStatement;
    }
}
Forepart answered 14/7, 2016 at 23:53 Comment(2)
As far as I can see this should work but personally I prefer @Terje D. 's solution -> completed the answer according to the comments.Eddie
dohhh voted your's 1 up but didn't notice I've never marked it as resolved - thx ;)Eddie

© 2022 - 2024 — McMap. All rights reserved.