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

Accessing DataObjects from has_one child relation


Go to End


4 Posts   966 Views

Avatar
Neomang

Community Member, 9 Posts

10 June 2016 at 5:06am

I currently have designed a structure where a custom Page has a child DataObject (Topic) which houses several other DataObjects (EducationPost). I am trying to do a couple things.

1. I have built a listbox field that I want to have manage the many_many relation between Topic and EducationPost, but I am not sure how to get the field to work with that table in the database when I put it into the CMSFields for EducationPost.

2. I need to access my EducationPost objects from the Page that houses the Topic. I attempted to do this (from the template) by using $Topic.EducationPost but I am not certain that will work (cannot test until the table is properly managed in the above step).

Any help that can be provided is appreciated.

Avatar
Devlin

Community Member, 344 Posts

10 June 2016 at 8:32pm

Edited: 10/06/2016 8:37pm

Prerequisites:

class EducationPost extends DataObject {
	private static $db = ['Title' => 'Varchar'];
	private static $belongs_many_many = ['Topics' => 'Topic'];
}
class Topic extends DataObject {
	private static $db = ['Title' => 'Varchar'];
	private static $many_many = ['EducationPosts' => 'EducationPost'];
	private static $has_many = ['Pages' => 'Page'];
}
class Page extends SiteTree {
	private static $db = ['Title' => 'Varchar'];
	private static $has_one = ['Topic' => 'Topic'];
}

1. ... but I am not sure how to get the field to work with that table in the database when I put it into the CMSFields for EducationPost.

class EducationPost extends DataObject {
	// ...

	public function getCMSFields() {
		$fields = parent::getCMSFields();

		$source = Topic::get()->map('ID', 'Title')->toArray();
		$value = array_keys($this->Topics()->getIDList());
		$fields->addFieldToTab('Root.Main', 
			ListboxField::create('Topics', 'Topic', $source, $value, $size = null, $multiple = true)
		);

		return $fields;
	}
}

Though, the ListboxField maybe become quite lengthy if there are too many Topics. Maybe you should use a GridField for this instead.

2. ... using $Topic.EducationPost but I am not certain that will work

// Page.ss
$Title // Title of Page
$Topic.Title // Title of Topic
<% loop $Topic.EducationPosts %>
	$Title // Title of EducationPost
<% end_loop %>

// ... or in php
$this->Title; // Title of Page
$this->Topic()->Title; // Title of Topic
foreach ($this->Topic()->EducationPosts() as $EducationPost) {
	$EducationPost->Title; // Title of EducationPost
}

// also vice versa
<% loop $Topic.EducationPosts %>
	$Title // Title of EducationPost
	<% loop $Topics %>
		$Title // Title of Topic
		<% loop $Pages %>
			$Title // Title of Page
		<% end_loop %>
	<% end_loop %>
<% end_loop %>

https://docs.silverstripe.org/en/3.2/developer_guides/model/relations/

Avatar
Neomang

Community Member, 9 Posts

11 June 2016 at 7:25am

Edited: 11/06/2016 9:09am

Thanks for your help. I got the listbox working but i'm still having some issues with getting the pages to show the posts associated with the topic. Here's what I currently have.

Prerequisites:

class EducationPost extends DataObject {
	private static $db = ['Title' => 'Varchar'];
	private static $belongs_many_many = ['Topics' => 'Topic'];
}
class Topic extends DataObject {
	private static $db = ['Title' => 'Varchar'];
	private static $has_one = ['TopicAggregatorPage' => 'TopicAggregatorPage'];
	private static $many_many = ['EducationPosts' => 'EducationPost'];
}
class TopicAggregatorPage extends EducationPage {
	private static $db = ['Title' => 'Varchar'];
	private static $has_one = ['Topic' => 'Topic'];
}

TopicAggregatorPage:

<div class="row row-eq-height">
	<% if $Topic.EducationPosts %>
		<% loop $Topic.EducationPosts.Sort("Created", DESC) %>
			<% if $MultipleOf(3) %>
				<div class="row row-eq-height">
			<% end_if %>
				<div class="col-xs-12 col-sm-6 well sub-detail-block">
				<img src="$MainImage.Filename">
				<h3>$Title</h3>
				<div class="text">$Teaser</div>
				<p>$Topic</p>
				</div>
			<% if $MultipleOf(2) %>
				<% if not $Last %>
					</div>
				<% end_if %>
			<% end_if %>
		<% end_loop %>
	<% else %>
		<h4>No results to display.</h3>
	<% end_if %>

Currently this only ever shows me "No results to display." despite the fact that I have several posts associated with the page I'm looking at.

Additionally, I have a pagetype EdAggregatorPage that is a parent to several TopicAggregatorPages in the site tree, and I am trying to display posts for those topics on the EdAggregatorPage. I wrote a custom function to get these and build an arraylist (so I can sort, limit, etc as we decide what exactly we want the page to have). That code is as follows:

public function getChildPosts() {
		
	$array = Array();
		
	foreach($Child as $topic){
		
		foreach($topic->EducationPosts as $edPost){
				array_push($array, $edPost);
		}
	}
		
	$list = new ArrayList($array);

	return $list;
}

This worked previously, but has stopped working since I made the updates to fix the listbox. Am I missing something in the names or am I doing something else wrong? I feel like I am close but just can't quite sort it out.

Avatar
Devlin

Community Member, 344 Posts

13 June 2016 at 12:14am

Edited: 13/06/2016 12:17am

Currently this only ever shows me "No results to display." despite the fact that I have several posts associated with the page I'm looking at.

Works for me. Are you sure your page has a topic? Try a "$TopicID" in your template, it should output some value.

edit: http://www.sspaste.com/paste/show/575d52d6a9c15

As in your getChildPosts() function: your variable "$Child" is undefined and "$topic->EducationPosts" should be a function like "$topic->EducationPosts()"