This is a quick guide on how to render a DataObject as a page. We’ll cover the following areas:
Our example will be based on the following ProductsPage which ‘has_many’ Products.
class ProductsPage extends Page {
private static $table_name = 'ProductsPage';
private static $has_many = [
'Products' => Product::class
];
public function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldsToTab('Root.Products', [
GridField::create(
'Products',
'Products',
$this->Products(),
GridFieldConfig_RelationEditor::create()
)
]);
return $fields;
}
}
And here’s the ProductsPageController which is empty for now, but we’ll soon write our method to render each Product DataObject onto its own template here.
class ProductsPageController extends PageController {
}
Here’s what the Product DataObject looks like, a simple DataObject with only 2 database fields ‘Name’ and ‘Price’, and a ‘has_one’ relation that ties it back to the ProductsPage.
class Product extends DataObject {
private static $table_name = "Product";
private static $has_one = [
'ProductPage' => ProductsPage::class
];
private static $db = [
'Name' => 'Text',
'Price' => 'Varchar'
];
public function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldsToTab('Root.Main', [
TextField::create('Name'),
TextField::create('Price')
]);
return $fields;
}
}
Let’s add a method called ‘Link’ inside the Product DataObject class which will generate a unique link for each product.
public function Link() {
return $this->ProductPage()->Link('product/'.$this->ID);
}
Now with what we have above and after rebuilding our database and flushing the cache with ‘dev/build?flush=all’, we can loop all Product DataObjects onto the ProductsPage.ss template like so
<% loop $Products %>
<div class="product">
<a href="$Link">
<span>$Name</span>
<span>$Price</span>
</a>
</div>
<% end_loop %>
Notice the $Link used in the loop which is referencing the ‘Link’ method created earlier in the Product DataObject class.
Now we can write our method to render each Product onto its own template in the ProductsPageController. We’ll call this method ‘product’ to match exactly what the $Link inside the loop is outputting (‘/product/productID’). We’ll also whitelist the method ‘product’ by adding it to the ‘$allowed_actions’ array shown below
class ProductsPageController extends PageController
{
private static $allowed_actions = [
'product'
];
public function product(HTTPRequest $request) {
$product = Product::get_by_id($request->param('ID'));
if (!$product) {
return $this->httpError(404, 'Product not found');
}
return [
'Product' => $product
];
}
}
Now flush the cache by appending ‘?flush=all’ to the end of our URL.
The last step is to create a template that should render each Product. For this to work our template name has to follow this convention ‘PageType_action.ss’, so let’s name ours ‘ProductsPage_product.ss’ and put the following inside it.
<% with $Product %>
<span>ID: $ID</span>
<span>Name: $Name</span>
<span>Price: $Price</span>
<% end_with %>
Now introduce the new template by flushing the cache with “?flush=1” at the end of your URL and you should now be able to click on each Product and see it in its own template.
This guide is inspired by Silverstripe’s tutorial on Controller Actions and DataObjects as pages which covers the topic in deeper detail.
Post your comment
Comments
No one has commented on this page yet.
RSS feed for comments on this page | RSS feed for all comments