【问题标题】:Scaffold ListBox multiple select in ModelAdmin Filter for DataObject with Enum带有枚举的 DataObject 的 ModelAdmin 过滤器中的脚手架 ListBox 多选
【发布时间】:2016-06-24 22:30:17
【问题描述】:

目前,存在枚举的搜索字段的自动脚手架会生成一个下拉列表,仅允许进行一个选择。我有兴趣使用现有的过滤器来更改它以允许多项选择。

给定以下数据对象...

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')
    );
}

非常感谢任何帮助。

【问题讨论】:

    标签: php silverstripe modeladmin


    【解决方案1】:

    从您的问题来看,您似乎打算将传递给可搜索字段的 filter 更改脚手架。我已经进行了一些挖掘,但似乎并非如此。但是,如果您改用 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')
        );
    }
    

    不幸的是,这并不容易,您会注意到,只要这样做,它就会出现“没有可用的选项”而不是复选框列表。这是因为当我们提供我之前提到的field 选项时,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 关系中的枚举时存在问题。这是由于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);
                }
            }
        }
    }
    

    【讨论】:

    • 这是一个绝妙的答案——因为它完全符合我的要求。唯一的缺点是现在我已经添加了这个 - 我也尝试了 CheckboxSetField... 但 ListboxField 只出来了
    • @barry,不是 100% 确定你的意思。如果在 DataObjects 可搜索字段上设置,则会出现 CheckboxSetField。你刷新缓存了吗? (即 ?flush=1)
    • 我在枚举上都试过了,我确实在每次更改时都刷新了缓存(一定喜欢这样做)并且每次它仍然是一个列表框
    • 顺便说一句,现在发现了一个更严重的问题......它似乎不适用于点符号......换句话说,如果可搜索字段使用一个有一个关系枚举,那么它不会显示/使用 ListBoxField :(
    • 非常感谢 - 出于某种原因,它仍然无法在我想要的代码中运行,但在全新安装中完美运行......所以现在是调试时间!再次感谢/
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-09
    • 1970-01-01
    • 2021-02-02
    • 1970-01-01
    • 2019-12-18
    • 2015-11-08
    相关资源
    最近更新 更多