Silverstripe:与同类相关的多对多关系

时间:2014-05-14 07:29:20

标签: orm many-to-many silverstripe

我有一个班级“表演”,并且对于每个表演,其他表演可以作为建议链接。经过一些试验和错误后,我使用ORM进行半工作:

public static $many_many = array(
    'Recommendations'       => 'Performance'
);

public static $belongs_many_many = array(
    'Recommendations'       => 'Performance'
);

上面的内容让我指明了建议,但是在正常情况下(两个类之间),也可以使用相反的关系。这不是。关于如何在“性能”类上显示反向关系而不创建反对多对多并在那里手动插入反向关系的任何线索?

更新(2014年5月22日):现在我得出的结论是,没有开箱即用的解决方案来解决这个问题。我根据@ FinBoWa的解决方案做了以下最小的例子,它显示了“未找到Degree.InterestingDegreesReversed(Degree)的反向组件”:

class Degree extends DataObject {

    private static $db = array(
        "Name"  => "Varchar(255)",
    );

    private static $many_many = array(
        'InterestingDegrees' => 'Degree'
    );

    private static $belongs_many_many = array(
        'InterestingDegreesReversed' => 'Degree.InterestingDegrees'
    );

}

class DegreeAdmin extends ModelAdmin {
    public static $managed_models       = array('Degree'); 
    static $url_segment                 = 'degrees'; 
    static $menu_title                  = 'Degrees';
}

我也试过了@ g4b0的解决方案,但这有一个严重的缺点,就是它没有在管理员中显示反向关系。目前我正在使用他的解决方案,但这不是解决问题的真正方法。所以我现在不接受答案......

3 个答案:

答案 0 :(得分:2)

您应该能够在关系中使用点符号。

我们的一个项目有学位,我们希望使用相同的课程来关联有趣的学位:

private static $many_many = array(
    'InterestingDegrees' => 'Degree'
);

private static $belongs_many_many = array(
    'InterestingDegreesReversed' => 'Degree.InterestingDegrees'
);

如果您在关联网站树时手动添加编辑器,则此方法有效。

但是如果您使用模型管理员,则必须手动声明字段,否则您将获得错误。因此,如果您使用模型管理员,那么一个工作示例将是:

class Degree extends DataObject {

    private static $db = array(
        "Name"  => "Varchar(255)",
    );

    private static $many_many = array(
        'InterestingDegrees' => 'Degree'
    );

    private static $belongs_many_many = array(
        'InterestingDegreesReversed' => 'Degree.InterestingDegrees'
    );

    public function getCMSFields() {

        $fields =  new FieldList();

        $fields->add(new TextField("Name"));

        // dont show the field untill we have something to relate to 
        if($this->ID){
            //Interesting degrees
            $gfc = GridFieldConfig_RelationEditor::create();
            //Remove add and edit features
            $gfc->removeComponentsByType('GridFieldAddNewButton');
            $gfc->removeComponentsByType('GridFieldEditButton');
            $gf = new GridField('InterestingDegrees', null, $this->InterestingDegrees(), $gfc);
            $fields->add($gf);
        }
        return $fields;
    }
}

class DegreeAdmin extends ModelAdmin {
    public static $managed_models       = array('Degree'); 
    static $url_segment                 = 'degrees'; 
    static $menu_title                  = 'Degrees';
}

答案 1 :(得分:2)

您必须为many_many和belongs_many_many指定两个不同的名称,以便您可以访问它们。例如:

public static $many_many = array(
    'RelatedRecommendations' => 'Performance'
);

public static $belongs_many_many = array(
    'Recommendations'        => 'Performance'
);

答案 2 :(得分:0)

我已经完成了这两个想法,这就是我为我正在进行的项目(我使用Brand模型)提出的建议。 这是受两种解决方案的启发,我添加的唯一附加项是onAfterWrite方法。在那里,我只是遍历所有品牌,并添加另一面。

只需通过Brands标签即可对所有品牌进行修改。另一个应该在getCMSFields中删除,如下所示:$fields->removeByName('RelatedBrands');

<?php
class Brand extends DataObject {
    private static $many_many = [
        'Brands' => 'Brand' //part 1 of brand-brand relation
    ];

    private static $belongs_many_many = [
        'RelatedBrands' => 'Brand' //part 2 of brand-brand relation
    ];

    public function onAfterWrite() {
        parent::onAfterWrite();

        foreach ($this->Brands() as $brand) {
            $this->RelatedBrands()->add($brand);
        }
    }
}