Silverstripe $many_many relationship with an attribute on the relationship
Asked Answered
A

2

5

When adding a many_many relationship much like the projects to mentors relationship in the silverstripe guide:

http://doc.silverstripe.org/framework/en/tutorials/5-dataobject-relationship-management

I'd like to record an attribute against the relationship. So for example "active" - yes /no field for the mentor on the project. But the mentor might have a different value for active for different projects she is related to.

Whats the best way to achieve this with Silverstripe's built in tools?

UPDATE with some help from IRC & the answer below. ive gotten a bit closer, bit its not working. Ive found this: https://github.com/chillu/silverstripe-framework/blob/c8136f5d4c8a37a4da274cd1c93907c0a2af86a7/docs/en/reference/grid-field.md which seems very relevant.

so DebatePages have many_many panelists who can vote differently on each debate.

DebatePage.php

  private static $many_many = array(
    'Panelists'     => 'Panelist',
    'RelationTags'  => 'Tag'
  );
  public static $many_many_extraFields = array(
    'Panelists' => array('Motion' => 'Boolean')
  );




public function getCMSFields() {
    .....
    if($this->ID) {
            $panelistFields = singleton('Panelist')->getCMSFields();
            $panelistFields->addFieldToTab(
                'Root.Main',
                // Please follow the "ManyMany[<extradata-name>]" convention
                new TextField('ManyMany[Motion]', 'Agree with Motion')
            );
            $config = GridFieldConfig_RelationEditor::create();
            $config->getComponentByType('GridFieldDetailForm')->setFields($panelistFields);
            $gridField = new GridField('Panelists', 'Panelists', $this->Panelists(), $config);
            $fields->findOrMakeTab('Root.Panelists')->replaceField('Panelist', $gridField);
        }        
    }
Albur answered 30/7, 2013 at 1:13 Comment(0)
T
9

you could use $many_many_extraFields on the $many_many relation, like this (here on the Project class I guess):

static $many_many = array(
    'Mentors' => 'Mentor'
);

static $many_many_extraFields = array(
    'Mentors' => array(
        'Active' => 'Boolean'
    )
);

Then for each Project a specific Mentor can be active or not (you can always add other fields than 'Active'...).

If you are using SS 3.1 you can have those extra fields edited easily via a GridField with the GridFieldDetailForm component:

function getCMSFields(){

    --[snip]--

    $detailFormFields = new FieldList();
    $detailFormFields->push( new CheckBoxField(
        'ManyMany[Active]',
        'Is Mentor active?'
    ));
    $detailFormFields->push( new TextField(
        'SomeOtherField',
        'Some other title'
    ));
    $config = new GridFieldConfig_RelationEditor();
    $config->getComponentByType('GridFieldDetailForm')->setFields($detailFormFields);

    $f = new GridField('Mentors', 'Mentors', $this->Mentors(), $config);
    //push() or addFieldToTab() $f to CMSFields

    --[snip]--

}

Doc on this is here: http://doc.silverstripe.com/framework/en/3.1/reference/grid-field#customizing-detail-forms

And when retrieving the data in your code, you can use the getExtraData($componentName, $itemID) method on the ManyManyList to retrieve those extra fields values: http://api.silverstripe.org/3.1/source-class-ManyManyList.html#178-210

Trometer answered 30/7, 2013 at 6:52 Comment(6)
ok thanks. I'm on 3.0 but it looks like maybe this is available there too right? Is there any documentation on this at all? can't quite get it to workAlbur
the $config var - what is that. its causing a "Call to a member function getComponentByType() on a non-object" errorAlbur
Editing ManyMany fields via a GridField was introduced in SS 3.1 beta 1, so if you are on 3.0, you can not use it. You can either look at the commit and port it to 3.0 (github.com/silverstripe/silverstripe-framework/commit/…) or upgrade to 3.1 which is probably a good idea and doesn't take much. the $config var is part of creating the GridField, it was a very short snippet so didn't have all the parts before, I've edited the answer above with the whole code for the GridField and added a link to the doc.Trometer
thanks. I have upgraded to 3.1 and found some example in the source code & had a go with that. I got "I can't handle sub-URLs of a CMSForm object." error. Ill go through your snippet now & see if it sheds some lightAlbur
Can you post the full code for DebatePage.php and Panelist.php either here or better as a Gist. Might be able to test and help better?Trometer
What you had above worked great, with the extra field value available just as a variable as usual - $Motion. Thanks so much for your help. Really appreciated. If anyone wants the full snippet for ref let me know.Albur
W
2

(See: SS3.1 - http://api.silverstripe.org/3.1/class-CheckboxSetField.html)

Try this:

private static $many_many = array(
    'Mentors' => 'Mentor'
); 
$mentors = Mentor::get();   
$mentorFields = new CheckboxSetField(    
    'Mentors',   
    'Mentor',   
    $mentors->map(),   
    $value="1"   
);  
$fields->addFieldToTab('Root.Mentors', $mentorFields);
Whetstone answered 2/6, 2015 at 2:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.