在编辑表单中保存之前获取相关 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);
}
使用具有简单 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);
}