带有枚举的 DataObject 的 ModelAdmin 过滤器中的脚手架列表框多个 select

Scaffold ListBox multiple select in ModelAdmin Filter for DataObject with Enum

目前,有枚举的搜索字段的自动脚手架会生成一个下拉列表,只允许创建一个 selection。我有兴趣使用现有过滤器来更改它以允许多个 select 离子。

给定以下数据对象...

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

...我正在寻找一个模块或某种简单的过滤器来将枚举搭建成多个 select 列表框

多个 select 列表框定义为...

我要求一个 通用 解决方案 - 我可以为每个模型管理员构建一个搜索上下文,但这非常令人沮丧。 使用现有过滤器(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')
    );
}

非常感谢任何帮助。

从您的问题来看,您似乎打算将传递给可搜索字段的 filter 更改为脚手架。我做了一些挖掘,但似乎并非如此。但是,如果您改为使用 field 选项,则可能会达到您想要的效果。

你确实特别提到了 ListboxField and while it does support multiple, it isn't enabled by the default constructor on the field which is how it would be instantiated

你想要的可以通过开箱即用的方式完成 CheckboxSetField。 (我承认,UI 在 ModelAdmin 中使用时有点平均)

生成的代码可能如下所示:

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

不幸的是,这并不是那么容易,您会注意到这样做会出现 "No options available" 而不是复选框列表。这是因为当我们提供我之前提到的 field 选项时,SilverStripe 的行为有所不同。

这种解决方法不是很好,但可以说仍然是通用的。我对 ModelAdmin 进行了扩展 class,它在搜索表单中查找 CheckboxSetField 并为其设置枚举值。

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,克服被禁用的多个选项并用值填充它(因为它会遇到上述相同的问题)。该解决方案将不那么通用,因为我们将强制从枚举映射的所有 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')
    );
}

您现在拥有了想要的东西 - 具有枚举值的多 select ListBoxField

你现在可能会问,我为什么要报道 CheckboxSetField?好吧,我认为研究所有可能的解决方案很重要。我通过尝试 CheckboxSetField 找到了我提供的解决方案,这真的只是最后一分钟的事情,我意识到通过一些小的修改,我可以让它在 ListboxField.

上工作

如您所提,上面的代码在 HasOne 关系中处理 Enum 存在问题。这是由于 ModelAdmin 扩展采用字段名称并将其作为数据库字段专门处理(通过 dbObject) on the model class of the form. Instead, we can detect a relationship from the dual underscores on the field name, replacing it with dot-syntax and treating that instead like a relationship (via 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);
            }
        }
    }
}