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 SSBits 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