如何将 JSON 加载到 Silverstripe 数据对象的字段中

How to load JSON into field of Silverstripe Dataobject

最近升级到 4.3.1 的 Silverstripe 版本似乎破坏了一些将数据对象作为 JSON 加载到文本字段中的功能。

对象看起来像这样:

class Foo extends DataObject 

  private static $db = [
    'Name' => 'Varchar',
    'Description' => 'Text',
    'Models' => 'Text',
  ];

然后有一个函数可以使用从表单请求生成的 JSON 加载对象:

$data = json_decode($request->getBody(), true);
$foo = new Foo();
$foo->update($data);

下面是 JSON $data 的示例:

"Name":"Test",
"Description":"Wangle fangle blurble wurgle.",
"Models":{
   "fish":{"trout":10,"salmon":15,"sturgeon":20},
   "vegetable":{"carrot":1,"cabbage":2,"leek":3},
   "sauce":{"chipotle":6,"tomato":4,"soy":2}
 }

直到最近,"Models" 结构将作为文本保存到 "Models" 字段中:

 "fish":{"trout":10,"salmon":15,"sturgeon":20},
 "vegetable":{"carrot":1,"cabbage":2,"leek":3},
 "sauce":{"chipotle":6,"tomato":4,"soy":2}

但是现在我们得到以下错误:

DataObject::setField: Models only accepts scalars at /var/www/example/vendor/silverstripe/framework/src/ORM/DataObject.php:2648

DataObject.php 中的第 2640 行说:

If this is a proper database field, we shouldn't be getting non-DBField objects

是否有最近的安全修复程序阻止了将 JSON 对象加载到字段中的尝试?

任何人都可以帮助将模型 JSON 保存到文本字段中吗?

@wmk 在这里,这是防止安全漏洞的预期行为(请参阅 SS-2018-021)。 4.3.1 中的更改是为了防止您在将 DB 字段指定为标量类型时无意中允许用户将非标量值插入到您的数据模型中。

在您的情况下,您正在尝试将数组写入文本字段,而该文本字段已被 silverstripe/framework 正确阻止。

这里最简单的解决方法是重新编码数据数组中您知道要存储为 JSON 文本 blob 的部分,例如:

$data = json_decode($request->getBody(), true);
$data['Models'] = json_encode($data['Models']); // re-encode as JSON before saving
$foo = new Foo();
$foo->update($data);

这将确保您仍在将 JSON 作为文本写入文本字段。

另外正如@wmk 提到的,另一个可行的选择是编写您自己的 DBField,它接受非标量值并负责将它们安全地写入数据库。如果您正在编写处理 GIS or spatial data 的 DBField,这将很有用。在您的特定示例中,我认为您可以像我的示例一样确保它仍然被编码为字符串。