Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

General Questions /

General questions about getting started with SilverStripe that don't fit in any of the categories above.

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo, swaiba

Filter results based on front end selection


Go to End


5 Posts   1257 Views

Avatar
Goatwriter

Community Member, 4 Posts

14 November 2014 at 4:27pm

Hi, I’m new to Silverstripe this week (so, v3…) so apologies if there is a better forum area for this. I’ve been searching and can’t find a solution. Should be simple for those with experience so I hope you can help…

I’ve set up a number of pages, classed CaseStudyPage, that are all children of one CaseStudiesHolder page.

Each CaseStudyPage could have any number of Skills associated with it so I’ve managed to set up a DataObject called Skill, which has a many_many relationship with CaseStudyPage. All good so far. Phew.

Now, in my CaseStudiesHolder page I want to show teasers for all of its children – easy. But then I want the front end user to be able to click on one of a few skill links to filter the list of CaseStudyPages to just the ones that have that skill.

I don’t think I need to be fancy and let them choose more than one skill so the link could be a simple ‘a’ tag with a GET variable passed to the same page. How would the page then filter the list of CaseStudyPages? Any tips on what I should/could be using here would be very welcome, thanks.

Avatar
Goatwriter

Community Member, 4 Posts

17 November 2014 at 5:21pm

Any clues? Is it best to filter $children in the template with if/else? Should I make a public function and query the DB? How would I go about using the GET/POST vars for this?

I have spent so many hours deciphering the docs and other online material to get this far, even getting a module to work. Just need a few pointers from an experienced member to get going with this task in the right direction. Help a Wellingtonian out?

Avatar
martimiz

Forum Moderator, 1391 Posts

18 November 2014 at 2:58am

There are all kinds of more or less sophisticated ways to do this, but this would be sort of simple:

Create the links (CaseStudiesHolder.ss):

<% loop Children %>
	<a href="{$Top.Link}?skill=$URLSegment">$Title</a><br>
<% end loop %>

Return the requested skills (CaseStudiesHolder_Controller):

public function getSkillPages() {
	$vars = $this->request->requestVars();
		
	if (!empty($vars['skill'])) {
		$skill = $vars['skill'];
		return $this->Children()->filter(array('URLSegment' => $skill));
	}
	return $this->Children();
}

Show requested skills (CaseStudiesHolder.ss)

<% loop $SkillPages %>
	<h3>$Title</h3>
<% end_loop %>

Note: this is simplyfied, you'd need to add your validation/sanitizing

Avatar
Goatwriter

Community Member, 4 Posts

19 November 2014 at 1:11pm

Thanks, that helps me understand how the public function can be used to narrow results but the filter itself might need to be quite complex – I am not sure how to write it because of the many_many relationship of skills.

CaseStudiesHolder lists CaseStudyPages, CaseStudyPages have one or more Skills associated with them. I need to filter the CaseStudyPages from the CaseStudiesHolder depending on the one skill supplied via GET or however, eg 'Tank driving'.

Do I need a left join or is there an easy to filter the pages: "show only child pages that have a skill named 'Tank driving' in their skill set.


// The pages that are listed:
class CaseStudyPage extends Page {
    private static $many_many = array(
        'Skills' => 'Skill'
    );
     public function getCMSFields() {
        $fields = parent::getCMSFields();
        $Skills = DataObject::get('Skill');
        $fields->addFieldToTab("Root.Main", new CheckboxsetField('Skills', 'Skills', $Skills));
        return $fields;
    }
}

// Skill is a DataObject:
class Skill extends DataObject {
    public static $db = array(
        'Name' => 'Varchar'
    );
    private static $belongs_many_many = array(
        'CaseStudyPages' => 'CaseStudyPage'
    );
}

// The holder that lists the pages - 
// filtered by one skill (filter by multiple might be ideal but one will do)
class CaseStudiesHolder extends Page {
    private static $allowed_children = array('CaseStudyPage');
}
class CaseStudiesHolder_Controller extends Page_Controller {
    public function getCaseStudyList() { 
       $vars = $this->request->requestVars(); 
       if (!empty($vars['skill'])) { 
          $skill = $vars['skill']; 
          // NEED WORKING FILTER HERE-----------------------//
          return $this->Children()->filter(array('Skills.Name' => $skill));
       } 
       return $this->Children(); 
    }
}

I could list this in a different forum if you think it isn't suited here - Would the Data Model forum be better?

Thanks for your help.

Avatar
Goatwriter

Community Member, 4 Posts

19 November 2014 at 4:13pm

Edited: 19/11/2014 4:24pm

Think I have it:

$skill = $vars['skill']; 
$skillObj = Skill::get()->filter(array('Name' => $skill))->First();
return $skillObj->CaseStudyPages(); 

Thanks to this: http://stackoverflow.com/questions/12146586/silverstripe-3-leftjoin

Not even sure how this works yet, but it does so I'm celebrating.

Seems like the GET var doesn't need to be escaped either: http://doc.silverstripe.org/framework/en/topics/security