Using forTemplate on DataObjects in templates

1,191 views
Skip to first unread message

webbower

unread,
Mar 17, 2010, 10:38:00 PM3/17/10
to SilverStripe Development
I just got finished trying to figure out how to trigger a DataObject's
forTemplate() method to render the DataObject in a template as just a
template variable with some help in the SS IRC channel. The SS docs
didn't help much and so I figured I'd share with all what I figured
out about rendering DataObjects in templates by just using a single
template variable and the DataObject->forTemplate() method.

For those who don't know, DataObject->forTemplate() allows you to
define a template file to serve as the rendering template for said
DataObject. A template like this is usually comparable to a template
file you'd find in the templates/Includes folder, a small snippet of
HTML with variables relating to a DataObject's $db properties. It
allows you to just output the DataObject with the defined template as
a template variable.

So, on to the solution. I learned about the ability to do this in the
SilverStripe tutorials when I first started playing with SS. It's
explained in Step 5 of the tutorials. Typically, you have a Page
(let's say MyPage) with has_one to a DataObject (let's say
HasOneObject).

======================================
class MyPage extends Page {

static $has_one = array('SingleObject' => 'HasOneObject');

// ...

}
======================================

Then, if I define

======================================
class HasOneObject extends DataObject {

function forTemplate() { return $this->renderWith('HasOneObject'); }

}
======================================

this is saying to render the HasOneObject in templates with the
HasOneObject.ss file, probably located in the templates/Includes
folder. So in my MyPage.ss template, if I use the template variable
$SingleObject, it will render the whole HasOneObject as defined in the
HasOneObject.ss file.

So that's old news. The problem that sent me looking for answers was
how to leverage the DataObject->forTemplate() method in a control loop
that looped over a has_many relation. If I had

======================================
class MyPage extends Page {

//...

static $has_many = array('ManyObjects' => 'HasManyObject');

// ...

}
======================================

and

======================================
class HasManyObject extends DataObject {

function forTemplate() { return $this->renderWith('HasManyObject'); }

}
======================================

and in my MyPage.ss file I had

======================================
<% control ManyObjects %>
$ManyObjects
<% end_control %>
======================================

It didn't output anything. I eventually realized that ManyObjects
referred to a DataObjectSet and I had to somehow refer directly to the
DataObject as a template variable in order to leverage the
forTemplate() method. At first, I made a custom method on the
HasManyObject that just returned $this.

======================================
class HasManyObject extends DataObject {
//...

function Object() { return $this; }

}
======================================

I changed my template code to look like this

======================================
<% control ManyObjects %>
$Object
<% end_control %>
======================================

and it worked. But I wasn't satisfied. There had to be a native method
on DataObject that could be used as a template variable that just
returned the DataObject, e.g. just did "return $this;". I found the
DataObject->data() method with returned $this, but it was not a method
you use in the templates since it wasn't Capital Camel Case as is the
standard. I couldn't find another one. Then it hit me to traverse up
the class tree and see if maybe one of the parent classes had my
answer. I didn't have to look far, the answer was in ViewableData, the
direct parent class of DataObject. ViewableData has a Me() method that
returns $this. So, I tried using it.

======================================
<% control ManyObjects %>
$Me
<% end_control %>
======================================

Success!

Now traditionally, you see something more along the lines of the
following being used to accomplish the same goal

======================================
<% control ManyObjects %>
<% include HasManyObject %>
<% end_control %>
======================================

and it works great. My situation was that I had one DataObject tied to
2 different page types: one was by has_many and the other was a
has_one. So I wrote the forTemplate() method for my DataObject and
wanted to use the variable outputting method rather than including the
template on both page types.

Sorry for the long-windedness, but, as many of my friends will
confirm, I like telling stories. I hope this helps people.

Cam Spiers

unread,
Mar 18, 2010, 1:53:47 AM3/18/10
to silverst...@googlegroups.com
Hey Mate,

Thanks for this! You should post this in the forum if you haven't already, it is useful. I also found out this approach some time ago but I didn't know about the $Me thing and was stuck with just using the include.

Thanks

Cam


--
You received this message because you are subscribed to the Google Groups "SilverStripe Development" group.
To post to this group, send email to silverst...@googlegroups.com.
To unsubscribe from this group, send email to silverstripe-d...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/silverstripe-dev?hl=en.


Sam Minnee

unread,
Mar 18, 2010, 3:24:00 AM3/18/10
to SilverStripe Development
The $Me/forTemplate() method works well if you only have a single way
of representing an object inside your template. If you had different
ways that you could render your objects, for example a small summary
view and a large detail view, you could do that like so:

class MyPage {
function SmallView() {
return $this->renderWith('HasManyObject_small');
}
function LargeView() {
return $this->renderWith('HasManyObject_large');
}
}

<h2>Small views</h2>

<% control ManyObjects %>
$SmallView
<% end_control %>

...

<h2>Large views</h2>

<% control ManyObjects %>
$LargeView
<% end_control %>

schellmax

unread,
Jan 31, 2013, 5:50:02 AM1/31/13
to silverst...@googlegroups.com
thanks for sharing!
Reply all
Reply to author
Forward
0 new messages