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.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

Archive /

Our old forums are still available as a read-only archive.

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo

ComplexTableList to show only related items


Go to End


5 Posts   2935 Views

Avatar
Hammy

Community Member, 49 Posts

4 December 2008 at 10:21pm

I have created a relationship between 2 classes
1. ProductPage (Page)
2. StoreList (DataObject)

I want to be able to list only related StoreList items for each ProductPage item in Silverstripe admin. What is the best way about doing this without listing all StoreList items in a ProductPage (eventually there will be too many StoreList items for this to be easily managed)

Also, I would like to be able to create a StoreList item within a ProductPage and have it automatically assigned to that ProductPage.

How do I do this? I imagine this could be a common scenario. Can this be done using ComplexTableField?

Avatar
Sean

Forum Moderator, 922 Posts

5 December 2008 at 12:18am

Edited: 05/12/2008 12:33am

You'll want to set up the relation between ProductPage and StoreList. e.g.

ProductPage.php:


class ProductPage extends Page {

	static $many_many = array(
		'Stores' => 'Store'
	);

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

		$fields->addFieldToTab(
			'Root.Content.Stores',
			$this->storesTableField()
		);

		return $fields;
	}

	function storesTableField() {
		$tableField = new ManyManyComplexTableField(
			$this,
			'Stores',
			'Store',
			Store::field_list(),
			'getCMSFields'
		);

		return $tableField;
	}

}

class ProductPage_Controller extends Page_Controller {

}

Store.php:


class Store extends DataObject {

	static $db = array(
		'Name' => 'Varchar(100)'
	);

	static $belongs_many_many = array(
		'Products' => 'ProductPage'
	);

	static function field_list() {
		return array(
			'Name' => 'Name'
		);
	}

	function getCMSFields() {
		$fields = new FieldSet(
			new TextField('Name', 'Name of store')
		);

		return $fields;
	}

}

This means that you've got a many-to-many relation between ProductPage <-> Store, so a Product can have many Stores, and likewise a Store has many products.

I think this is how you'll want to set it up, let me know if I've assumed anything wrong.

Confused? ;-)

Cheers,
Sean

Avatar
Hammy

Community Member, 49 Posts

5 December 2008 at 10:22am

Edited: 05/12/2008 11:05am

Thanks Sean - Kinda there but not quite :)

I should have probably explained a little more about what I'm doing. I'm setting up a blog where I list products and stores that have that product. To help manage the different stores I have created the following.

- ProductPage (Page) - that is a list of products and its details (hasMany StoreList Objects)
- StorePage (Page) - that is a list of stores and its details (hasMany StoreList Objects)
- StoreList (DataObject) - that lists the url to that product for that store (hasOne ProductPage and hasOne StorePage)

Ideally what I'm kinda looking for is, when you go to a Product in the admin and add a Storelist item, it is automatically assigned to that Product (rather than going though a potential huge list of Storelist items to assign to a Product - eventually there will be hundreds of storelist items).

Also, when you are on each product in the admin, I want to only show the StoreList items related to that Product.

So I guess there are two things that are needed:

1. When adding a new StoreList item, how do you make it automatically related to the Product that you are creating the StoreList item from?

2. When viewing the list of StoreList items on a particular product, how do you filter it so that it only shows ShopList items related to that Product?

Any suggestions? I'm a bit of a novice at this but I'm learning ;)

This is what I have so far:

ProductPage.php

class ProductPage extends Page {
	
	static $db = array(
		"StartDate" => "Datetime",
		"EndDate" => "Datetime",
	);
	
	static $has_one = array(
		"ProductImage" => "Page_ResizeImages",
		"Category" => "CategoryPage",
		"Brand" => "BrandPage"
	);
	
	static $has_many = array(
		"HomeHighlight" => "HomeHighlight",
		"Stores" => "StoreList"
	);
	
	static $many_many = array(
		"Sections" => "SectionPage",
	);
	
	static $allowed_children = "none";
	
	static $default_parent = array('ProductHolder');
	
	static $icon = "themes/loaded/images/icons/product";
	
	function getCMSFields() {		
		$fields = parent::getCMSFields();
		$fields->removeFieldFromTab('Root.Content.Main', "MenuTitle");
		
		// Category Drop Down List
		$categories = DataObject::get('CategoryPage');
		$categoriesMap = $categories->toDropDownMap('ID', 'Title');
		
		// Brands Drop Down List
		$brands = DataObject::get('BrandPage');
		$brandsMap = $brands->toDropDownMap('ID', 'Title');
		
		// Sections Table Field List
		$sectionsTablefield = new ManyManyComplexTableField(
			$this,
			'Sections',
			'SectionPage',
			array('Title' => 'Sections'),
			'getCMSFields'
		); 
		$sectionsTablefield->setPermissions(array());
		
		// Store Table List
		$productID = $this->ID;
		$stores = DataObject::get('StoreList');
		$storesTablefield = new ComplexTableField(
			$this,
			'Stores',
			'StoreList',
			array(
				'StoreName' => "Store Name"
			),
			'getCMSFields_forPopup'
		);
		
		// Create Fields in CMS
		$fields->addFieldToTab('Root.Content.Main', new DropdownField('CategoryID','Category',$categoriesMap,$this,'null',true));
		$fields->addFieldToTab('Root.Content.Main', new DropdownField('BrandID',"Brand",$brandsMap,$this,'null',true));
		$fields->addFieldToTab('Root.Content.Main', $sectionsTablefield);
		$fields->addFieldToTab('Root.Content.Main', new PopupDateTimeField('StartDate','Start Date'));
		$fields->addFieldToTab('Root.Content.Main', new PopupDateTimeField('EndDate','End Date'));

		$fields->addFieldToTab('Root.Content.Stores', $storesTablefield);
		
		$fields->addFieldToTab('Root.Content.Images', new ImageField('ProductImage','Product Image'));
			
		return $fields;
	}
}

class ProductPage_Controller extends Page_Controller {
	
}

StoreList.php

class StoreList extends DataObject {
	
	static $db = array(
		'StoreName' => 'Text',
		'ProductUrl' => 'Text',
		'Price' => 'Currency',
		'PriceRange' => "Enum('Set Price,From Price','Set Price')",
	);
	
	static $has_one = array(
		'Currency' => 'CurrencyType',
		'Store' => 'StorePage',
		'ProductPage' => 'ProductPage',
	);
	
	static $belongs_many_many = array(
	);
 
	function getCMSFields_forPopup() {	
		$fields = new FieldSet();
		
		// Currency Drop Down List
		$currencies = DataObject::get("CurrencyType");
		
		if(!$currencies) {
			$currenciesMap = null;
		} else {
			$currenciesMap = $currencies->toDropDownMap('ID', 'Name');
		}
		
		$currenciesDropDown = new DropdownField(
			'CurrencyID',
			'Currency',
			$currenciesMap,
			$this,
			'null',
			true
		);
		
		// Store Drop Down List
		$stores = DataObject::get("StorePage");
		if(!$stores) {
			$storesMap = null;
		} else {
			$storesMap = $stores->toDropDownMap('ID', 'Title');
		}
		
		$storeDropDown = new DropdownField(
			'StoreID',
			'Store Tracking',
			$storesMap,
			$this,
			'null',
			true
		);
		
		$fields->push(new TextField( 'StoreName', 'Store Name' ));
		$fields->push($storeDropDown);
		$fields->push(new TextField( 'ProductUrl', 'Product Url' ));
		$fields->push($currenciesDropDown);
		$fields->push(new TextField( 'Price', 'Price' ));
		return $fields;
	}
}

Avatar
Hammy

Community Member, 49 Posts

6 December 2008 at 5:26pm

Edited: 06/12/2008 5:26pm

I've figured out point 2:

In ProductPage.php i've updated the $storesTablefield variable with the following:

...
		$storesTablefield = new ComplexTableField(
			$this,
			'Stores',
			'StoreList',
			array(
				'Store.Title' => 'Store',
				'ProductUrl' => 'Product Url',
				'Currency.Name' => 'Currency'
			),
			'getCMSFields_forPopup',
			'ProductID = '.$this->ID,
			'',
			''
		);
		$storesTablefield->setParentClass('ProductPage');
...

Each Product will now only list the StoreList items associated to it and also displays each StoreList items other related information from other classes (CurrencyType and StorePage) in the table field.

(Useful info about ComplexTableField http://api.silverstripe.com/forms/fields-relational/ComplexTableField.html#sec-method-summary)

Now just need to figure out how to automatically assign the ProductID to the StoreList item...

Avatar
Hammy

Community Member, 49 Posts

8 December 2008 at 11:44am

Not sure if I missed something when I started on this (unless I've added something that i am unaware of) but when using complexTableField, when you add a new dataobject from a related dataobject, it is automatically assigned to the item that you created it from.

So in my case, when you add a new Store item to a Product, it instantly creates the relationship.