为什么我的函数输出“方法 'forTemplate' 在 'SilverStripe\View\ArrayData 上不存在”
Why does my function output " the method 'forTemplate' does not exist on 'SilverStripe\View\ArrayData"
这将是我在这里的第一个问题。我希望我能给你所有你需要的信息。
我是运行一个使用silverstripe v4.8的个人项目
在我的模板中,我有一个 optionsetfield,它基本上只是一个无线电场。
选项中的前 3 个项目,我已经硬编码了。
我为其余部分编写了另一个函数,基本上可以获取所有可以创建事件的人的名字,遍历它们并将它们添加为选项。
当我转储我的结果时,它似乎以我想要的方式出现:
array (size=1)
'Rick' => string 'Rick' (length=4)
但是当我试图在我的模板中看到它时,它给了我:
Object->__call(): the method 'forTemplate' does not exist on 'SilverStripe\View\ArrayData'
现在,当我不将该函数添加到我的选项集时,前 3 个硬编码项工作正常。
我将 post 我的 OptionsField 和下面的其他函数。
提前谢谢你
public function createEventsFilterForm()
{
$form = Form::create();
$form = FieldList::create([
OptionsetField::create('Eventfilters')
->setTitle('')
->setSource([
'past' => 'Verlopen',
'today' => 'Vandaag',
'future' => 'Toekomst',
$this->getFirstNameOfEvents()
])
]);
return $form;
}
public function getFirstNameOfEvents()
{
$allEvents = UpcomingEvents::get();
foreach ($allEvents as $event) {
$firstName = 'NVT';
$memberProfileID = $event->MemberProfileID;
if ($memberProfileID) {
$firstName = [MemberProfile::get()->byID($memberProfileID)->FirstName];
}
$output = ArrayLib::valuekey($firstName);
return $output;
}
}
tl;博士:
SilverStripe 模板无法处理数组。我猜数组自动转换为 ArrayData
对象。
如果你想更明确一点,你可以这样写:
return new ArrayData([
'Name' => "FOOBAR"
]);
然后在模板中:
$FirstNameOfEvent <!-- this will also cause this error, because SSViwer does not know how to render ArrayData -->
<!-- but you can access object properties, like the Name that we defined: -->
$FirstNameOfEvent.Name <!-- will output FOOBAR -->
详细解释:
forTemplate
是SSViewer在渲染对象时调用的。
基本上,它是等同于 __toString()
的 SilverStripe,每当您尝试在 SilverStripe 模板中将对象输出到浏览器时,SSViewer(渲染器)将对该对象调用 forTemplate
。
举个例子:
class Foo extends VieableData {
public $message = 'Hello World';
public function forTemplate() {
return "This is a foo object with the message '{$this->message}'";
}
}
class PageController extends ContentController {
public function MyFooObject() {
return new Foo();
}
}
因此,如果在您的 Page.ss
模板中调用 $MyFooObject
,它将调用同名函数并获取一个对象。因为它是一个对象,SSViewer 不知道如何渲染并将调用 Foo->forTemplate()。然后将导致输出 This is a foo object with the message 'Hello World'
ArrayData
没有 forTemplate
方法,因此会出现错误。有两种方法可以解决这个问题[1]:
- 子类 ArrayData 并实现一个
forTemplate
方法,将您的数据转换为可以输出到浏览器的字符串(或 DBField
对象)
- 不要尝试在您的模板中呈现 ArrayData,而是直接访问数据(就像上面的 tl;dr,所以
$MyArrayData.MyField
)[2]
[1]:所有对象同理
[2]:直接访问对象属性始终是可能的,即使您有 forTemplate
方法。 forTemplate
只是默认设置,如果您不指定 属性。
编辑:
抱歉,我部分误解了您的 question/problem。
我上面说的所有内容仍然是正确的,理解起来很重要,但它没有回答你的问题。
我以为您是在模板中调用 $getFirstNameOfEvents
,但实际上,您是在 DropDownField
中使用它(错过了那部分)。
关于 SilverStripe CMS 的事情是,它也使用与前端相同的模板系统来处理它自己的事情。所以DropDownField
也会使用SSViewer来渲染。所以我的解释仍然是正确的,它只是发生在内置模板文件 DropDownField.ss
中。它做这样的事情:
<select>
<% loop $Source %>
<option value="$Key">$Value</option>
<% end_loop %>
</select>
$Source
这是您的数组 ['past' => 'Verlopen', 'today' => 'Vandaag', 'future' => 'Toekomst', $this->getFirstNameOfEvents()]
,它会自动转换为 ArrayData 对象。
现在,问题是,它并不像您认为的那样工作:
// the result you want:
['past' => 'Verlopen', 'today' => 'Vandaag', 'future' => 'Toekomst', 'Rick' => 'Rick']
// the result your code produces:
['past' => 'Verlopen', 'today' => 'Vandaag', 'future' => 'Toekomst', 0 => ['Rick' => 'Rick']]
注意你如何在一个数组中包含一个数组。因为getFirstNameOfEvents
returns一个数组。
那么你实际应该做什么:
$source = ['past' => 'Verlopen', 'today' => 'Vandaag', 'future' => 'Toekomst'];
$source = array_merge($source, $this->getFirstNameOfEvents());
$form = FieldList::create([
OptionsetField::create('Eventfilters')
->setTitle('')
->setSource($source)
]);
这将是我在这里的第一个问题。我希望我能给你所有你需要的信息。
我是运行一个使用silverstripe v4.8的个人项目 在我的模板中,我有一个 optionsetfield,它基本上只是一个无线电场。 选项中的前 3 个项目,我已经硬编码了。 我为其余部分编写了另一个函数,基本上可以获取所有可以创建事件的人的名字,遍历它们并将它们添加为选项。
当我转储我的结果时,它似乎以我想要的方式出现:
array (size=1)
'Rick' => string 'Rick' (length=4)
但是当我试图在我的模板中看到它时,它给了我:
Object->__call(): the method 'forTemplate' does not exist on 'SilverStripe\View\ArrayData'
现在,当我不将该函数添加到我的选项集时,前 3 个硬编码项工作正常。
我将 post 我的 OptionsField 和下面的其他函数。 提前谢谢你
public function createEventsFilterForm()
{
$form = Form::create();
$form = FieldList::create([
OptionsetField::create('Eventfilters')
->setTitle('')
->setSource([
'past' => 'Verlopen',
'today' => 'Vandaag',
'future' => 'Toekomst',
$this->getFirstNameOfEvents()
])
]);
return $form;
}
public function getFirstNameOfEvents()
{
$allEvents = UpcomingEvents::get();
foreach ($allEvents as $event) {
$firstName = 'NVT';
$memberProfileID = $event->MemberProfileID;
if ($memberProfileID) {
$firstName = [MemberProfile::get()->byID($memberProfileID)->FirstName];
}
$output = ArrayLib::valuekey($firstName);
return $output;
}
}
tl;博士:
SilverStripe 模板无法处理数组。我猜数组自动转换为 ArrayData
对象。
如果你想更明确一点,你可以这样写:
return new ArrayData([
'Name' => "FOOBAR"
]);
然后在模板中:
$FirstNameOfEvent <!-- this will also cause this error, because SSViwer does not know how to render ArrayData -->
<!-- but you can access object properties, like the Name that we defined: -->
$FirstNameOfEvent.Name <!-- will output FOOBAR -->
详细解释:
forTemplate
是SSViewer在渲染对象时调用的。
基本上,它是等同于 __toString()
的 SilverStripe,每当您尝试在 SilverStripe 模板中将对象输出到浏览器时,SSViewer(渲染器)将对该对象调用 forTemplate
。
举个例子:
class Foo extends VieableData {
public $message = 'Hello World';
public function forTemplate() {
return "This is a foo object with the message '{$this->message}'";
}
}
class PageController extends ContentController {
public function MyFooObject() {
return new Foo();
}
}
因此,如果在您的 Page.ss
模板中调用 $MyFooObject
,它将调用同名函数并获取一个对象。因为它是一个对象,SSViewer 不知道如何渲染并将调用 Foo->forTemplate()。然后将导致输出 This is a foo object with the message 'Hello World'
ArrayData
没有 forTemplate
方法,因此会出现错误。有两种方法可以解决这个问题[1]:
- 子类 ArrayData 并实现一个
forTemplate
方法,将您的数据转换为可以输出到浏览器的字符串(或DBField
对象) - 不要尝试在您的模板中呈现 ArrayData,而是直接访问数据(就像上面的 tl;dr,所以
$MyArrayData.MyField
)[2]
[1]:所有对象同理
[2]:直接访问对象属性始终是可能的,即使您有 forTemplate
方法。 forTemplate
只是默认设置,如果您不指定 属性。
编辑:
抱歉,我部分误解了您的 question/problem。
我上面说的所有内容仍然是正确的,理解起来很重要,但它没有回答你的问题。
我以为您是在模板中调用 $getFirstNameOfEvents
,但实际上,您是在 DropDownField
中使用它(错过了那部分)。
关于 SilverStripe CMS 的事情是,它也使用与前端相同的模板系统来处理它自己的事情。所以DropDownField
也会使用SSViewer来渲染。所以我的解释仍然是正确的,它只是发生在内置模板文件 DropDownField.ss
中。它做这样的事情:
<select>
<% loop $Source %>
<option value="$Key">$Value</option>
<% end_loop %>
</select>
$Source
这是您的数组 ['past' => 'Verlopen', 'today' => 'Vandaag', 'future' => 'Toekomst', $this->getFirstNameOfEvents()]
,它会自动转换为 ArrayData 对象。
现在,问题是,它并不像您认为的那样工作:
// the result you want:
['past' => 'Verlopen', 'today' => 'Vandaag', 'future' => 'Toekomst', 'Rick' => 'Rick']
// the result your code produces:
['past' => 'Verlopen', 'today' => 'Vandaag', 'future' => 'Toekomst', 0 => ['Rick' => 'Rick']]
注意你如何在一个数组中包含一个数组。因为getFirstNameOfEvents
returns一个数组。
那么你实际应该做什么:
$source = ['past' => 'Verlopen', 'today' => 'Vandaag', 'future' => 'Toekomst'];
$source = array_merge($source, $this->getFirstNameOfEvents());
$form = FieldList::create([
OptionsetField::create('Eventfilters')
->setTitle('')
->setSource($source)
]);