【问题标题】:How to dynamically change a Field's Type in SilverStripe如何在 SilverStripe 中动态更改字段的类型
【发布时间】:2023-11-22 00:12:01
【问题描述】:

我正在尝试根据 SilverStripe 中的一些条件动态更改字段的类型。

我有一个字段,例如CheckboxField() 我需要将其复制并更改为其他类型,例如DropdownField() 或任何其他类型的字段。

有没有办法在将对象推送到表单之前执行此操作?这里的最佳做法是什么?

【问题讨论】:

  • 这是为后端 SilverStripe CMS(又名。getCMSFields)还是其他什么?它应该像CheckboxField 中的removeByName 一样简单,然后是addFieldToTab(或push)你想要的任何新领域。如果是getCMSFields,您能否向我们展示您目前拥有的内容,以便我们根据您的问题创建适合的答案?
  • 另外,当您回到我之前的问题时,您打算如何存储不同的数据?我假设您的意图是将数据存储为不同的数据库或has_one 属性?只需向我们提供更多信息:)
  • @Turnerj 用于前端用户表单...表单。我正在创建一个可以更改为任何其他类型字段的自定义字段,但我不确定如何正确执行此部分。
  • 我目前只是使用条件语句来切换 - github.com/mediabeastnz/campaign-monitor-userform/blob/master/…
  • AHHHH,CheckboxSetField,不是CheckboxField!我想你真的已经有了关于如何去做的问题的解决方案,你真正的问题是最好的方法是什么?您链接到的代码是更优化的方法之一,我可能会以类似的方式实现它。如果那是您的代码,那么这是一种很好的方法。

标签: php forms object field silverstripe


【解决方案1】:

您可以使用 replaceField http://api.silverstripe.org/3.1/class-FieldList.html#_replaceField

function getCMSFields() {
  $fields = parent::getCMSFields();
  $fields->replaceField('MyField', DropdownField::create('MyField', 'My field'));
  return $fields;
}

【讨论】:

  • 其中一个问题是CheckboxField 从根本上存储的数据与DropdownField 不同。他很可能需要使用不同的数据库属性。因此,尽管他仍然可以利用 replaceField 函数,但他可能需要为 DropdownField 取一个不同的名称。
  • 你最好使用显示逻辑github.com/unclecheese/silverstripe-display-logic你可以根据某些条件隐藏和显示字段,例如如果选中了一个复选框,那么你可以显示下拉字段。
【解决方案2】:

您可以在 getCMSField 中添加条件

function getCMSFields() {
    $fields = parent::getCMSFields();
    $source = SomeDataObject::get();
    $fields->removeByName('MyField');
    if($source->count() > 1) {
        $fields->addFieldToTab('MyTab', DropdownField::create('MyField', 'My field', $source->map()->toArray()));
    } else {
        $fields->addFieldToTab('MyTab', CheckboxField::create('MyField', 'My field', $source->first()->Name));
    }
    return $fields;
}

希望对你有帮助。

【讨论】:

  • 虽然这是一个潜在的解决方案,但如果这是针对ModelAdmin 中的DataObject,由于脚手架,该字段实际上已经存在,因此您的示例将再次添加该字段。同样正如我在另一个答案中提到的那样,它有一个基本的存储缺陷,即DropdownField 存储的数据与CheckboxField 不同。您的 CheckboxField 将值转换为 01,因此即使传递源列表中的名字,也不会按预期存储在 MyField 属性中。
  • 我目前正在这样做(请参阅上面的链接),但不确定这是否是最佳做法?
  • @Turnerj 您可以删除条件前带有removeByName 的字段。 DropdownField 不存储任何数据,它不是DBField,而是FormFieldMyField 可以继承 TextField 并用于保存从下拉列表或复选框中选择的值。您甚至可以在写入数据库之前使用函数onBeforeWrite 来操作值。
  • @cbarberis,我知道您可以删除该字段,我刚刚提到它是因为您的原始帖子没有考虑到这一点。对于 getCMSFields 自动保存,MyField 需要是数据库属性或has_one 关系Form::saveInto 工作。虽然您可以将DBField 子类化以处理两种字段类型的值,但会出现问题,例如在保存选中的复选框时,您将提供的值将是 1,可能与 DB 对象的 ID 相同的值并且您赢了'不知道使用了什么字段类型。
  • @cbarberis(续)虽然您可能会解决这个问题,但这不是开箱即用的处理方式,因此任何查看此答案的人都可能会产生错误的印象。我们的几个 cmet 来回是唯一能向任何访问者描述潜在问题的东西。我想只是在你的回答中记下它。
最近更新 更多