在编辑表单中保存之前获取相关 class 实例的可靠方法

Robust method for getting the related class instance before saving in the edit form

使用具有简单 has_one 关系的两个对象的标准 ModelAdmin。我希望在编辑 MyDataObject 时单击 "Add HasManyDataObject" 后访问相关对象。包括一个我不满意但有效的真正黑客。另一个技巧是从 URL 中刮取 ID。都不好.

class MyModelAdmin extends ModelAdmin {
    static $managed_models = array('MyDataObject');
    static $url_segment = 'mymodeladmin';
    static $menu_title = 'MyModelAdmin';
    static $model_importers = array();
}

class MyDataObject extends DataObject {
    private static $db = array('Name' => 'Varchar(255)');
    private static $has_many = array('HasManyDataObjects' => 'HasManyDataObject');

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

    Session::set('MyDataObjectID',$this->ID);
    Session::save();

        return $fields;
    }
}

class HasManyDataObject extends DataObject {
    private static $db = array('Name' => 'Varchar(255)');
    private static $has_one = array('MyDataObject' => 'MyDataObject');

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

        $myDataObject = MyDataObject::get()->ByID(Session::get('MyDataObjectID'));

        return $fields;
    }
}

我会期望像这样工作...

$myDataObject = $this->MyDataObject();

...但是没有。

令人沮丧的是,它确实在编辑表单中将该对象指示为只读字段,因此它必须以某种方式可用!

非常感谢所有答案。

我一次又一次遇到这种情况。正如您所发现的,您无法访问主要模型对象的原因是,在保存次要模型之前,这些模型的每个数据库表之间 没有关系 。因此,SilverStripe 无法为您提供模型的实例,如果它尚未保存以创建 DataObject 子类实例。

如您所见,解决方法是 "scrape" 主模型 ID 的 URL 并将该状态保存在某处,例如会话或 HTML5 localStorage。虽然通过使用 getURL() 查询当前控制器的 SS_HTTPRequest 实例,但提取该 ID 的方法稍微简单一些。您还可以从 params() 中获得一些好处 - 将其转储以查看您可以访问的内容。让框架帮助您进行黑客攻击:-)

祝你好运。

这里有一个旧的论坛帖子,用各种解决方案处理同样的问题: http://www.silverstripe.org/community/forums/data-model-questions/show/21517?start=8

有些通过 GridFieldEditForm 注入 ParentID,有些则从当前的 Controller 参数中获取。

添加和使用以下函数 returns "parent" 对象...

public static function GetParentObject($class) {
    $obj = null;

    $controller = Controller::curr();
    if ($controller->request->Param('ModelClass') == $class)
        $obj = $class::get()->ByID($controller->request->Param('ID'));

    if ($obj)
        return $obj;

    $url = $_SERVER['REQUEST_URI'];
    $start = $class.'/item/';
    $end = '/';
    $startpos = strpos($url,$start);
    $id = null;
    if ($startpos != false) {
        $startpos += strlen($start);
        $endpos = strpos($url,$end,$startpos);
        $id = substr($url,$startpos,$endpos - $startpos);
    }

    return $class::get()->ByID($id);
}