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.

DataObjectManager Module /

Discuss the DataObjectManager module, and the related ImageGallery module.

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

ManyManyDataObjectManager to manage two subclasses of DataObject


Go to End


9 Posts   4489 Views

Avatar
Bright Eyes David

Community Member, 26 Posts

22 December 2010 at 1:26pm

I'm new to SilverStripe (and OO PHP) and am hoping someone can pick out what's wrong with or what I need to do to the code I currently have.

Requirements:

A parts list.
A bundles list.
Recording which bundles contain which parts.

I've got so far as successfully creating the CMS fields for the two lists, but am stuck on controlling which parts are in which bundles.

After a /dev/build, I get this in the admin:

[User Warning] I could not find the relation PartsBundles in PartsHolder or any of its ancestors.
GET /admin
Line 54 in /data/htdocs/ac/dataobject_manager/code/ManyManyDataObjectManager.php

I think I may need to change '$this' in the '$manager_parts_bundles' DOM subclass in PartsHolder.php to something else to let SilverStripe know that it needs to look into one of the other two files to establish the relationship, but I'm not sure how to go about this.

Here are my files:

PartsHolder.php

class PartsHolder extends Page {
	
	static $has_many = array(
		'Parts' => 'Part',
		'Bundles' => 'PartsBundle'
	);
	
	public function getCMSFields() {
		$fields = parent::getCMSFields();
		
		$manager_parts = new DataObjectManager(
			$this,
			'Parts',
			'Part'
		);
		$fields->addFieldToTab('Root.Content.Parts', $manager_parts);
		
		$manager_bundles = new DataObjectManager(
			$this,
			'Bundles',
			'PartsBundle'
		);
		$fields->addFieldToTab('Root.Content.Bundles', $manager_bundles);
		
		$manager_parts_bundles = new ManyManyDataObjectManager(
			$this,
			'PartsBundles',
			'PartsBundle'
		);
		$fields->addFieldToTab('Root.Content.Bundles', $manager_parts_bundles);
		
		return $fields;
	}
	
}

class PartsHolder_Controller extends Page_Controller {
	
}

Part.php

class Part extends DataObject {
	
	static $db = array(
		'PartNumber' => 'Varchar',
		'Description' => 'Text',
		'PurchasePrice' => 'Varchar',
		'SupplierPartNumber' => 'Varchar',
		'SupplierDescription' => 'Text',
		'SupplierTerms' => 'Text',
		'SalesPrice' => 'Varchar'
	);
	
	static $has_one = array(
		'PartsHolder' => 'PartsHolder',
		'Image' => 'Image'
	);
	
	static $belongs_many_many = array(
		'Bundles' => 'PartsBundle'
	);
	
	static $summary_fields = array(
		'PartNumber' => 'PartNumber',
		'Description' => 'Description',
		'PurchasePrice' => 'PurchasePrice',
		'SalesPrice' => 'SalesPrice'
	);
	
	function getCMSFields() {
		return new FieldSet(
			new TextField('PartNumber'),
			new TextAreaField('Description'),
			new NumericField('PurchasePrice'),
			new TextField('SupplierPartNumber'),
			new TextAreaField('SupplierDescription'),
			new TextAreaField('SupplierTerms'),
			new NumericField('SalesPrice'),
			new ImageField('Image')
		);
	}

}

PartsBundle.php

class PartsBundle extends DataObject {
	
	static $db = array(
		'Description' => 'Text',
		'SalesPrice' => 'Varchar'
	);
	
	static $has_one = array(
		'PartsHolder' => 'PartsHolder'
	);
	
	static $many_many = array(
		'Parts' => 'Part'
	);
	
	static $summary_fields = array(
		'Description' => 'Description',
		'SalesPrice' => 'SalesPrice'
	);
	
	function getCMSFields() {
		return new FieldSet(
			new TextAreaField('Description'),
			new NumericField('SalesPrice')
		);
	}
	
}

Many thanks!

Avatar
Bright Eyes David

Community Member, 26 Posts

1 January 2011 at 12:45am

Friendly bump as I still haven't sorted this. :) Let me know if I need to clarify anything. Thanks.

Avatar
Bright Eyes David

Community Member, 26 Posts

9 January 2011 at 2:06am

Any pointers on this still appreciated.

Avatar
Puppy

Community Member, 10 Posts

9 February 2011 at 8:19am

I am having a similar problem using ModelAdmin to show editable relations between Organisations and Persons.

Organisation.php


class Organisation extends DataObject {
		static $db = array(
				"Name" => "Varchar",
				"Type" => "Enum('Registered Business, Freelancer, Sole Trader, Charity, Public Sector')",
				"RegNum" => "Varchar(100)",
				"Website" => "Varchar",
				"Phone" => "Varchar",
				'Email' => 'Varchar',
				'Address' => 'Varchar',
				'Postcode' => 'Varchar(10)'
					);
		
		static $has_one = array(
				);
		
		static $belongs_many_many = array(
			"Persons" => "Person"
		 );
		
		static $summary_fields = array(
		'Name' => 'Name',
		'Phone' => 'Phone',
		'Email' => 'Email'
		);
		
		static $searchable_fields = array (
		'Name',
		'Type'
    	);
		
		function getCMSFields() {
					
			$fields = new Fieldset();
			$fields->push(new TextField('Name', 'Name'));
			$fields->push(new DropdownField("Type", "Type of Organisation", $this->dbObject('Type')->enumValues()));
			$fields->push(new TextField('RegNum', 'Company/Charity Number'));
			
			$fields->push(new TextField('Email', 'Email')); 
			$fields->push(new TextField('Phone', 'Phone')); 
			$fields->push(new TextField('Website', 'Website')); 
			
			$fields->push(new TextareaField('Address', 'Address')); 
			$fields->push(new TextField('Postcode', 'Postcode')); 
			
			return $fields;
		
		}

Person.php

class Person extends DataObject {
	
		static $db = array(
				"Title" => "Enum('Mr, Mrs, Ms, Dr')",
				"FirstName" => "Varchar",
				"Surname" => "Varchar",
				"FullName" => "Varchar",
				'Email' => 'Varchar',
				'Phone' => 'Varchar',
				'Mobile' => 'Varchar',
				'Address' => 'Varchar',
				'Postcode' => 'Varchar(10)'
					);
		static $has_one = array(
				"User" => "Member"
				);
		
		static $many_many = array(
				"Organisations" => "Organisation"
				);
		
		static $defaults = array(   
								 
   		 );
		
		static $summary_fields = array(
		'FullName' => 'Full Name',
		'Member' => 'Member',
		'Phone' => 'Phone',
		'Email' => 'Email'
		);
		
		static $searchable_fields = array (
		'FullName',
		'Surname',
		'FirstName'
    	);
		
		function getCMSFields() {
			
			$userManager = new HasOneDataObjectManager($this, 'User', 'Member');
			$userManager->setPermissions(
					array(
						"show",
						"edit"
					));
			
			$organisation = new ManyManyDataObjectManager($this, 'Organisation', 'Organisation');
			
$fields = parent::getCMSFields(); 			 
$fields->addFieldToTab("Root.Main", new ReadonlyField('FullName', 'Full Name'));

$fields->addFieldToTab("Root.Main", new DropdownField("Title", "Title", $this->dbObject('Title')->enumValues()));
$fields->addFieldToTab("Root.Main", new TextField('FirstName', 'First Name'));
$fields->addFieldToTab("Root.Main", new TextField('Surname', 'Surname')); 

$fields->addFieldToTab("Root.Main", new TextField('Email', 'Email')); 
$fields->addFieldToTab("Root.Main", new TextField('Phone', 'Phone')); 
$fields->addFieldToTab("Root.Main", new TextField('Mobile', 'Mobile')); 

$fields->addFieldToTab("Root.Main", new TextareaField('Address', 'Address')); 
$fields->addFieldToTab("Root.Main", new TextField('Postcode', 'Postcode')); 

$fields->addFieldToTab("Root.UserAccount", $userManager);

$fields->addFieldToTab("Root.Organisations", $organisation);



			return $fields;
		
		}

Looking into, have you found anything else?

Avatar
BoWa

Community Member, 2 Posts

10 February 2011 at 6:37am

Edited: 10/02/2011 6:38am

Hi,

didnt see the flaw per ce, but heres an alternative way to do this,

for the PartsBundle change the getCMSFields to inlcude the ManyManyDataObjectManager for the parts

eg

function getCMSFields() {
      return new FieldSet(
         new TextAreaField('Description'),
         new NumericField('SalesPrice'),
         new ManyManyDataObjectManager(
         $this,
         'Parts',
         'Part'
       )
      );
   }

and for the PartsHolder comment out the two other editors and just leave the one for the bundles,

 $manager_bundles = new DataObjectManager(
         $this,
         'Bundles',
         'PartsBundle'
      );
      $fields->addFieldToTab('Root.Content.Bundles', $manager_bundles);

this way youll get one tab for bundles and when adding creating a bundle you can select existing to it or add new ones.

Cheers,
BoWa

Avatar
Bright Eyes David

Community Member, 26 Posts

10 February 2011 at 7:22am

Thanks Bowa,

Funnily enough, this is about what I have now after I chatted to you on IRC (it was you, wasn't it?), but now I've come across the issue where Parts that are ticked are not saved by the ManyManyComplexTableField because it's in a pop-up which is something many are finding (seemingly for about a year or more).

I'm now trying to figure out how to get the ManyManyComplexTableField not to be in a pop-up so that it works.

Avatar
BoWa

Community Member, 2 Posts

10 February 2011 at 10:02am

Cheers,

And im a fraid it was me :), selection at the admin end seemed to work for the inner "manymanyeditor" for me at least.

But if you have an issue with it theres a nifty workaround, instead of the inner editor use the CheckboxSetField to manage the selections.

Below a snipped of a working idea, wont copy the whole thing here ;P

$doTravellerTag = DataObject::get("TravellerTag");
$mapTravellerTag = $doTravellerTag ? $mapTravellerTag = $doTravellerTag->toDropdownMap('ID','Name') : array();
$fields->push(new CheckboxSetField('TravellerTags','TravellerTags', $mapTravellerTag));

TravellerTag is a many_many relation for that Data Object. Off course with this you need one tab were you "build" the bundles packages but the relations are managed with a simple checkboxlist.

Or just crate a site tree with pages to hide the underliying "datamodel" it really depents how "politically correct" you want to be with your relations ;)

Cheers,
Olli

Avatar
Bright Eyes David

Community Member, 26 Posts

10 February 2011 at 10:08am

Got this sorted now. I made another Holder class for the bundles and separated them out. Not what I was hoping for, but it works. :)

I think the issue may be that DOM is not supposed to handle relationships between DataObjects and DataObjects (only Pages and DataObjects)?

Go to Top