Silverstripe 3 Many Many – A Comprehensive Example

I see that the website hosting this resource has disappeared, so I’ll try to save this article, as it might come in handy. The images are gone, so I’m only able to save low quality versions.

How to create set up a many_many relation using the SS3 gridfield

In this article we’re going to a create a very simple shop. We’ll create pages for various product categories. And we’ll create products. Some our products will appear in more than one category.

Eg. Each ‘Category’ -> has many-> Products
and each ‘Porduct’ -> has many -> ‘Categories’

This is many_many relationship. In the database, we end with 3 tables – one containing the Categories, one containing the Products, and one table which contains a list of ‘links’ between the products and categories.

Create the Category Page

Create ProductCategoryPage.php

This is the page on your site that will list the the products.

We define the many_many relation to the product, and then set up the gridfield to allow us to manage the products in the CMS.

We use the config option ‘GridFieldConfig_RelationEditor’ to make the datagrid show the right options. We also add “GridFieldDeleteAction(‘unlinkrelation’)” to the config. This allows us to ‘delete’ a product altogether (from all categories), or just remove (unlink) it from the category page we’re editing.

<?php
class ProductCategoryPage extends Page {

public static $many_many = array(
'Products' => 'Product'
);

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

$gridFieldConfig = GridFieldConfig_RelationEditor::create()->addComponents(
new GridFieldDeleteAction('unlinkrelation')
);

$gridfield = new GridField("Products", "Product", $this->Products(), $gridFieldConfig);
$fields->addFieldToTab('Root.Products', $gridfield);
return $fields;

}

}

class ProductCategoryPage_Controller extends Page_Controller {

public static $allowed_actions = array (
);

public function init() {
parent::init();
}

}

 

Create the Product Object

Create Product.php

This is the object that contains data about each product – at this stage we simply have a title and a photograph.

We also define the fact that this item belongs to a many_many – this ties the two parts together nicely.

We’ll also define the summary fields shown in the CMS – or else it will just show the ID, which isn’t much use.

We’re adding a function here to show a thumbnail image – why not – it looks nice!

And finally, we’re calling getCMSFields, and setting up a datagrid so that when we’re on a product page, we get a nice table showing us what categories are related to that product.

<?php

class Product extends DataObject {

public static $db = array(
'Title' => 'Varchar'
);

// One-to-one relationship with profile picture and contact list page
public static $has_one = array(
'Image' => 'Image'
);

public static $belongs_many_many = array(
'ProductCategoryPage' => 'ProductCategoryPage'
);

// Summary fields
public static $summary_fields = array(
'ID' => 'ID',
'Thumbnail' => 'Thumbnail',
'Title' => 'Title'

);

public function getThumbnail() {
return $this->Image()->CMSThumbnail();
}

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

$gridFieldConfig = GridFieldConfig_RelationEditor::create()->addComponents(
new GridFieldDeleteAction('unlinkrelation')
);
$gridFieldConfig->removeComponentsByType('GridFieldAddNewButton');

$gridfield = new GridField("ProductCategoryPage", "ProductCategoryPage", $this->ProductCategoryPage(), $gridFieldConfig);
$fields->addFieldToTab('Root.ProductCategoryPage', $gridfield);
return $fields;

}

}

 

At this stage, upload the files, run a dev/build and create a few ‘ProductCategoryPages’ in your CMS.

Adding New Products

In your CMS, choose one of the new ‘Product Category’ Pages. And move to the ‘Products’ tab.

resizedimage400231-add-product

You should see a screen similar to the image above

Click ‘add product’

resizedimage400231-add-product-2

Give the new product a title, in this case we’ll call it ‘Wheel’ – but don’t bother adding an image. You’ll need to click ‘Create’ first, and then add the image, then ‘Save’ it again.

resizedimage400231-add-product-3

Once you’ve saved your product, click ‘Back’ at the top of the page to return to the main category page

Adding an existing product to another category

Now that we have a product, we can add this product to another category by going to the other page, and again, to the ‘products’ tab

resizedimage400231-add-product-4

Here is another list of products – this time though, instead of clicking ‘Add Product’ to create a new products, we’ll search for an existing product – in this case ‘wheel’.

resizedimage40063-add-product-5

Enter the first few letters of the product in the box next to ‘add product’ and Silverstripe will come with a list of items that match the search. Click on the item you want to add, and then click ‘Link Existing’. The item will now appear in both category pages.

Removing an Item

At the start of this article we added

new GridFieldDeleteAction('unlinkrelation')

It’s now that this little line becomes important. It adds an extra icon into right column

add-product-6

These icons are ‘Edit’, ‘Delete’, and ‘Unlink’

‘Delete’ will remove the product from the database – and remove it from any categories it belong to.

The ‘Unlink’ button allows you to remove it from just this page while leaving it in the database for any other pages that it might belong to.

Note. If you click on an item, and then click on the ‘product category’ tab in the top right – you’ll see a list of pages this item belongs to, where you can also unlink a category from the product, or attach a new category. However note that if you click the ‘delete’ button here you will be deleting a page off your site.

Creating the Templates

Now come the fun bit – making the template to display the information.

The details will of course depend how you want your page to look. This is very basic example

Create ProductCategoryPage.ss with your templates Layout folder

Something like the following will be enough to show your products…

<% loop Products %>

<h3>$Title</h3>
$Image.SetWidth(100)

<% end_loop %>

 

Comments

7 responses to “Silverstripe 3 Many Many – A Comprehensive Example”

  1. […] See our article about Many_Many relations for more details […]

  2. James Barnsley Avatar

    Looks like a handy guide for beginners – very cool. Just a quick tip: in your template you should be using either or as is deprecated.

    1. Clone Avatar
      Clone

      You’re right, this was SS 3.0 targeted code.

  3. Pieter de Jong Avatar
    Pieter de Jong

    Thanks for the code, looks good but for some reason it is not working with SS 3.1.4 Doe you have any ideas why? It would be really handy to be able to make relations like this.

  4. […] This page suggests to just add both action buttons, unlinkrelation and deleterecord, but that would just defer the problem to the user, causing confused users to keep creating “zombie records”. […]

  5. Vlad Avatar
    Vlad

    Thank you Clone for the great example!
    not sure if it’s too late to ask?

    what if I want to add 2 or more the same products?
    for example, i build double cheeseburger which has 2 slices of cheese and two patties.
    Currently, i have to create 2 the same products, but it would be nice if i had just one product name and could add it multiple times to the products page

    could you advise please?

    1. Clone Avatar
      Clone

      Hi Vlad,

      You should check has many relation, where you would define that one DataObject has more then one DataObjects of another type.

      https://docs.silverstripe.org/en/3/tutorials/dataobject_relationship_management/#has-one-and-has-many-relationships-project-and-student

Leave a Reply

Your email address will not be published. Required fields are marked *