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.

Template Questions

Displaying DataObject as a Page


Reply

3 Posts   1335 Views

Avatar
TotalNet

1 September 2010 at 4:55pm (Last edited: 2 September 2010 8:30am), Community Member, 181 Posts

I've just written this long post and found the solution as a result of literally spelling it out, so rather than hit cancel I might as well share what I have :)

This topic has been mentioned a few times but I've yet to see a clear solution (in my situation anyway) so, I'll share what I've done and hope that someone can help me with the last piece of the puzzle.

There are already some great tips on displaying DOs in a page like [url=http://www.ssbits.com/using-silverstripe-url-parameters-to-display-dataobjects-on-a-page]SSBits[/url] and tutorials that show how to display a list of DOs on a page. What all of these have in common is that you must create a page in the CMS which is not something I want to do and I have a couple of left-over issues.

The issues first:

  • Can't (without a lot of work) access DOs via a top-level SEO friendly URL
  • Can't set the MetaTags for the page displaying the DO

Now the first issue has been talked about quite a bit and from what I can see it's because ModelAsController is tied to SiteTree and although I'm open to discussing ways around it, I might actually use mod_rewrite to bypass the issue. For now.

The second one is where I'm really scratching my head, the code below shows how I am returning the DO using the customise function and while I can set Title etc I can't figure out how to set the MetaDescription and others returned by the MetaTags function.

Anyway here's a scenario and the code so far (reduced for simplicity of demonstration) :

Let's say I have a Library which contains Books, I don't want lots of Library pages, I'll add Category pages at a later date. We will view the books by going to /library/show/name-of-book

We have our DataObject "Book"

class Book extends DataObject{

      static $db = array (
         "URLSegment" => "Varchar(255)",
         'Name' => 'Varchar(255)',
         'Content' => 'HTMLText',
         'MetaDescription' => 'Text',
      );

      static $indexes = array(
         "URLSegment" => true,
      );

      static $has_one = array(
         "Library" => "Library",
      );

      static $searchable_fields = array(
         'Name',
      );

      static $summary_fields = array (
         'Name' => 'Name',
      );
}

Book DataObjects will be managed in a ModelAdmin subclass. There are many ways to set the URLSegment but for now assume it's sanitised and unique ;)

And to display a Book

class Library extends Page {
   // Hide Library page type from the CMS
   static $hide_ancestor = "Library";
}

class Library_Controller extends Page_Controller {

   static $allowed_actions = array("show");

   function show(){

      $ID = Convert::raw2sql(Director::urlParam("ID"));
      if (is_numeric($ID)){
         $item = DataObject::get_by_id("Book", $ID);
      }
      else {
         $item = DataObject::get_one("Book", "URLSegment = '{$ID}'");
      }
      if ($item){
         $book = $this->customise($item);
         return $book;
      }
      else return ErrorPage::response_for(404);
   }
}

We need to extend the Page class to pick up the templates automatically. see update in post below

This should work on its own but for good measure I added a Director rule in config.php:

Director::addRules(100, array(
   'library//$Action/$ID' => "Library_Controller"
   ));

This is the point I realised that by putting a MetaTags function in the Book class I can get it to work - just had to put "return SiteTree::MetaTags($includeTitle);" inside :)

Feedback welcome, hope this helps someone else.

Rich

Avatar
Mad_Clog

1 September 2010 at 7:18pm Community Member, 78 Posts

You don't need to extend Page when you're not going to create a CMS page from your class.
All you need is the controller and the Director rule.
You can use the renderWith method to tell the controller which template(s) to use.

Avatar
TotalNet

2 September 2010 at 8:25am (Last edited: 2 September 2010 8:37am), Community Member, 181 Posts

That's what I was expecting to be able to do but wasn't able to get it to work as expected and so, created the Page subclass which handled it automatically.

The behaviour I want, is to use the Page.ss main template (no point in duplicating it) and the Layout/Library_show.ss layout template.

It took some experimenting but the following now works so I can get rid of the Page subclass!

$book = $this->customise($item)->renderWith(array("Library_show","Page"));

Think I understand the template engine much better since doing this.

[Edit] May now consider moving the controller to the DataObject