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.

Data Model Questions /

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

ModelAdmin & Relationship Questions - $belongs_many_many


Go to End


8 Posts   3825 Views

Avatar
Liam

Community Member, 470 Posts

4 November 2010 at 3:43pm

I have a dataobject called Parent that is managed in ModelAdmin. I attach multiple of these dataobjects to a custom page type in the CMS called ParentPage. From the ParentPage page type in the CMS, users can attach/select the Parent dataobjects as I've used a CheckboxSetField. All works fine.

In ModelAdmin when I pull up a Parent dataobject, a pages tab is created which displays which ParentPages this dataobject is linked to. It is listed in a complextablefied I believe and allows users to edit/delete and add ParentPages from the Model/Admin interface.

I don't want this ability. I'd rather the users create the pages from the CMS SiteTree and do it that way. So back in ModelAdmin for the Parent object, I'd rather it just list out which pages the dataobject is linked to, without the ability to add/edit them.

Parent.php Relevant Code:

public static $belongs_many_many = array(
      	'Pages' => 'ParentPage'
	);

ParentPage.php Relevant Code:

	public static $many_many = array(
    	'Parents' => 'Parent'
	);

//in getcmsfields
$map = array();
		if($parents = DataObject::get('Parent')) $map = $parents->toDropdownMap();
		$fields->addFieldToTab('Root.Content.Parents', new CheckboxSetField('Parents', 'Parents', $map));

Avatar
swaiba

Forum Moderator, 1899 Posts

4 November 2010 at 9:04pm

Hi Liam,

Was there a question there? It looks like you have the solution (to add checkbox field in getcmsfields)... I'd suggest using $fields->removeByName('<tab name>'); to remove the tab and possibly using http://silverstripe.org/multiselectfield-module/

Barry

Avatar
Liam

Community Member, 470 Posts

5 November 2010 at 4:53am

Hi Barry,

Sorry for the bit of confusing post, was written late at night.

From the "Pages" part of the CMS, the PageType functionality is perfect. I'll look into using that module you linked to. I totally forgot about it, as I remember it from when it was first released.

All I'm trying to do is limit the functionality on the Parent object within ModelAdmin. When you load the ModelAdmin for Parent, and display an object, there is a tab that displays a complextablefield of the PageType the object is linked to based on the relationship I set up. This is done by default from ModelAdmin based on the relationship I set it. I'm not writing any code to do this.

From that complextablefield it allows the user to add a new page and link it to that object in the pop up window. I don't want the tab removed entirely, rather just list which pages the object is linked to and maybe remove the association from the object, but not delete it entirely from the sitetree if possible.

From the Parent object, I tried adding something like this with the addition of setting permissions to remove add functionality (just copied and pasted from the demo to save time, mine was set to the proper names and full code and such)

$modulesTablefield = new ManyManyComplexTableField(
         $this,
         'Modules',
         'Module',
         array(
	    'Name' => 'Name'
         ),
         'getCMSFields_forPopup'
      );
      $modulesTablefield->setAddTitle( 'A Module' );
 
      $fields->addFieldToTab( 'Root.Content.Modules', $modulesTablefield );

But I'm adding this to the Parent object, which has a $belongs_many_many relation set. That's the trouble I'm running into, if this makes more sense. It still not be a bit confusing.

Cheers,

Avatar
swaiba

Forum Moderator, 1899 Posts

6 November 2010 at 2:21am

I think I'm getting there... you wnat the users to be able to create / edit in the sitetree, but select / view only in ModelAdmin?

If that is the case I am not sure how this can be done. If I were to...

*have selection only in model admin, I'd remove the tab and use multiselectfield.
*have selection and view in model admin, I'd use the tab and and put the following in the child data object (the one in the tab)

canEdit(){return false;}
canCreate(){return false;}

but the second solution there would remove the permissions (to create and edit) from the sitetree too I think. Could have a ModelAdmin user and a Sitetree user - so the sitetree user has all permissions and model admin user is restricted - requires some custom stuff in canEdit() & canCreate()

Avatar
Liam

Community Member, 470 Posts

17 November 2010 at 6:48pm

Thanks for the help. I just left it alone, as it seemed like it wasn't possible or too much work to be worth it.

I have another question.

I have a dataobject set and want to link 2 objects to a page via a dropdownmenu. On the page, I want to link a "foo" and a "Bar" from the same dataobject set. I want to be able to pick them via a dropdown menu. The dataobjects will be linked to more than 1 page in some cases.

So do I just setup a $has_one and a $has_many relationship via a dot notation like in this example? http://doc.silverstripe.org/datamodel?s[]=has&s[]=one#has_many

My first instinct was in my pagetype to setup it up like this

	public static $has_one = array(
		'Foo' => 'DataObject',
		'Bar' => 'DataObject'
	);

Then just add a dropdownfield for each in my getcmsfields function

But reading the doc I linked above, says not to link to the same object more than once. What is the reasoning behind that? I'm a designer, so as you can tell my programming knowledge isn't great. Just wrapping my head around the concept.

Cheers,

Avatar
swaiba

Forum Moderator, 1899 Posts

18 November 2010 at 10:44pm

Edited: 19/11/2010 12:15am

"not to link to the same object more than once. What is the reasoning behind that? "

Couldn't say as I am not a core developer! But I think that may not be the whole truth... for example I have many objects with...

static $has_one = array(
	'ImageA' => 'Image',
	'ImageB' => 'Image',
	'ImageC' => 'Image',
);

I have, however, found that if you use circular links like...

class Obj extends DataObject
{
...
static $has_one = array(
	'PreviousObj ' => 'Obj ',
);
...
}

then ModelAdmin will not work, it takes ages to load and then shows a blank main panel with ok message. this can be programmed around by moving has_one to PreviousObjID => Int and just using DataObject::get_by_id for that special case. Also could note that the same issue (fail to edit in ModelAdmin) happens when the ORM is not fully specified (i.e. a 1-to-many isn't specified on BOTH sides of the relation with a has_one matching a has_many)

Avatar
Liam

Community Member, 470 Posts

19 November 2010 at 8:48am

Ya the Image example I do all the time, which is why I got pretty confused because it seemed to go against what the doc article I linked to suggested (using a has_one and only referencing something once).

I think I should be okay. I'll setup the dataobject to have a has_many and the pagetype to use a has_one for both the foo and bar and see how it goes.

I just wanted a better understanding of the reasoning behind it or to make sure I wasn't doing a sin ;)

Avatar
tsg

Community Member, 7 Posts

8 July 2012 at 9:50am

Old topic I know - but for anyone who is looking for a solution.

Remove the Pages tab from the dataobject and replace it with a checkboxset of relevant pages.

public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->removeByName('Pages');
$pages=DataObject::get("Page");
$fields->addFieldToTab("Root.Pages", new CheckboxsetField('Pages', 'Pages', $pages->toDropdownMap('ID','Title')));
return $fields;
}

}