目前,存在枚举的搜索字段的自动脚手架产生下拉列表,仅允许进行一次选择.我有兴趣使用现有的过滤器来更改它以允许多个选择.
鉴于以下数据对象……
class MyDataObject extends DataObject {
static $db = array(
'Name' => "Varchar(255)",
'MyEnum' => "Enum('Option1,Option2,Option3','Option1')"
);
}
……以及以下的ModelAdmin ……
class MyModelAdmin extends ModelAdmin {
static $mangaged_models = array(
'MyDataObject',
);
static $url_segment = 'mymodeladmin';
static $menu_title = 'MyModelAdmin';
static $menu_priority = 9;
}
…我正在寻找一个模块或某种简单的过滤器来将Enum搭建到多选列表框中
多选列表框定义为…
>允许多项选择
>输入一些字符后提供建议
我要求一个通用的解决方案 – 我可以为每个模型管理员构建一个搜索上下文,但这非常令人沮丧.
使用现有的过滤器(ExactMatchMultiFilter看起来很完美,但似乎没有实际工作),或者如果模块中有一个或者有人可以建议如何修改现有的过滤器,这将是很好的.
class MyDataObject extends DataObject {
static $db = array(
'Name' => "Varchar(255)",
'MyEnum' => "Enum('Option1,Option2,Option3','Option1')"
);
public static $searchable_fields = array (
'MyEnum' => array('filter' => 'ExactMatchMultiFilter')
);
}
任何帮助深表感谢.
解决方法:
从您的问题来看,您似乎打算将传递给可搜索字段的过滤器更改脚手架.我做了一些挖掘,但似乎并非如此.但是,如果您使用了field
选项,则可能实现您想要的效果.
你特别提到了ListboxField
,虽然它支持多个,但是which is how it would be instantiated字段的默认构造函数没有启用它.
你想要的东西可以通过开箱即用的方式完成CheckboxSetField
.(我承认,在ModelAdmin中使用UI时有点平均)
生成的代码看起来像这样:
class MyDataObject extends DataObject {
static $db = array(
'Name' => "Varchar(255)",
'MyEnum' => "Enum('Option1,Option2,Option3','Option1')"
);
public static $searchable_fields = array (
'MyEnum' => array('field' => 'CheckboxSetField')
);
}
不幸的是,它并不那么容易,你会注意到它会出现“没有可用选项”而不是复选框列表.这是因为当我们提供前面提到的字段选项时,SilverStripe的行为会有所不同.
这种解决方法并不是很好,但可以说仍然是通用的.我创建了一个ModelAdmin的扩展类,它在搜索表单中查找CheckboxSetField并为其设置Enum值.
class MyModelAdminExtension extends Extension {
public function updateSearchForm($form) {
$modelClass = $form->getController()->modelClass;
foreach ($form->Fields() as $field) {
if ($field->class == 'CheckboxSetField') {
//We need to remove the "q[]" around the field name set by ModelAdmin
$fieldName = substr($field->getName(), 2, -1);
$dbObj = singleton($modelClass)->dbObject($fieldName);
if ($dbObj->class == 'Enum') {
$enumValues = $dbObj->enumValues();
$field->setSource($enumValues);
}
}
}
}
}
这是一个相对安全的ModelAdmin扩展,因为它专门查找映射到CheckboxSetField的Enum的组合,这只能在您手动指定时发生.
到目前为止,我们实际上可以回顾ListboxField,克服禁用的多个选项并用值填充它(因为它会遇到上面提到的相同问题).这个解决方案将不那么通用,因为我们将强制从Enum映射的所有ListboxField都是倍数,但如果我们想要一个更好的解决方案,这就是我们如何得到它.
class MyModelAdminExtension extends Extension {
public function updateSearchForm($form) {
$modelClass = $form->getController()->modelClass;
foreach ($form->Fields() as $field) {
if ($field->class == 'ListboxField') {
//We need to remove the "q[]" around the field name set by ModelAdmin
$fieldName = substr($field->getName(), 2, -1);
$dbObj = singleton($modelClass)->dbObject($fieldName);
if ($dbObj->class == 'Enum') {
$field->setMultiple(true);
$enumValues = $dbObj->enumValues();
$field->setSource($enumValues);
}
}
}
}
}
而对于我们的模型……
class MyDataObject extends DataObject {
private static $db = array(
'Name' => "Varchar(255)",
'MyEnum' => "Enum('Option1,Option2,Option3','Option1')"
);
public static $searchable_fields = array (
'MyEnum' => array('field' => 'ListboxField')
);
}
你现在拥有你想要的东西 – 一个带有枚举值的多选ListBoxField.
您现在可能会问,我为什么要覆盖CheckboxSetField?嗯,我认为重要的是要考虑所有可能的解决方案.我通过尝试CheckboxSetField找到了我提供的解决方案,它实际上只是最后一分钟,我通过一些小修改实现了,我可以让它适用于ListboxField.
正如您所提出的,上述代码在HasOne关系中处理Enum存在问题.这是因为ModelAdmin扩展获取了字段名称,并且在表单的模型类上将其视为数据库字段(通过dbObject
).相反,我们可以检测字段名称上的双下划线的关系,用点语法替换它,并将其视为关系(通过relObject
).
我们更新的updateSearchForm函数如下所示:
public function updateSearchForm($form) {
$modelClass = $form->getController()->modelClass;
foreach ($form->Fields() as $field) {
if ($field->class == 'ListboxField') {
//We need to remove the "q[]" around the field name set by Model Admin
$fieldName = substr($field->getName(), 2, -1);
$dbObj = null;
//Check if the field name represents a value across a relationship
if (strpos($fieldName, '__') !== false) {
//To use "relObject", we need dot-syntax
$fieldName = str_replace('__', '.', $fieldName);
$dbObj = singleton($modelClass)->relObject($fieldName);
}
else {
$dbObj = singleton($modelClass)->dbObject($fieldName);
}
if ($dbObj != null && $dbObj->class == 'Enum') {
$field->setMultiple(true);
$enumValues = $dbObj->enumValues();
$field->setSource($enumValues);
}
}
}
}