#php #arrays #silverstripe
Вопрос:
Это будет мой самый первый вопрос здесь. Я надеюсь, что дам вам всю необходимую информацию.
Я запускаю личный проект, используя silverstripe v4.8. В моем шаблоне у меня есть поле optionsetfield, которое в основном является просто радиополем. Первые 3 пункта в опциях я жестко закодировал. Я написал еще одну функцию для остальных, чтобы в основном получить все имена людей, которые могут создавать события, просматривать их и добавлять в качестве опций.
Когда я отказываюсь от своего результата, кажется, что он выходит так, как я хочу:
array (size=1)
'Rick' => string 'Rick' (length=4)
Но когда я пытаюсь увидеть это в своем шаблоне, это дает мне:
Object->__call(): the method 'forTemplate' does not exist on 'SilverStripeViewArrayData'
Теперь, когда я не добавляю функцию в свой набор опций, первые 3 жестко закодированных элемента работают нормально.
Я опубликую свое поле OptionsetField и другую функцию ниже. Заранее спасибо
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;
}
}
Ответ №1:
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 при визуализации объектов.
По сути, это эквивалент SilverStripe __toString()
, когда вы пытаетесь вывести объект в браузер в шаблоне 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
метода, поэтому вы получаете ошибку. Есть 2 способа обойти это[1]:
- подкласс ArrayData и реализуйте
forTemplate
метод, который превращает ваши данные в строку (илиDBField
объект), которую можно вывести в браузер - Не пытайтесь отображать данные массива в своем шаблоне, вместо этого получите прямой доступ к данным (как в tl;dr выше, так
$MyArrayData.MyField
что )[2]
[1]: то же самое верно для всех объектов
[2]: прямой доступ к свойствам объекта всегда возможен, даже если у вас есть forTemplate
метод. forTemplate
это просто то, что нужно делать по умолчанию, если вы не указали свойство.
Редактировать:
извините, я частично неправильно понял ваш вопрос/проблему.
Все, что я сказал выше, по-прежнему верно и важно понять, но это не ответ на ваш вопрос.
Я думал, что вы вызываете $getFirstNameOfEvents
шаблон, но на самом деле вы используете его в DropDownField
(пропустили эту часть).
Особенность CMS SilverStripe в том, что она также использует ту же систему шаблонов, что и интерфейс для своих собственных вещей. Поэтому 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
что возвращает массив.
Так что же вам на самом деле следует сделать:
$source = ['past' => 'Verlopen', 'today' => 'Vandaag', 'future' => 'Toekomst'];
$source = array_merge($source, $this->getFirstNameOfEvents());
$form = FieldList::create([
OptionsetField::create('Eventfilters')
->setTitle('')
->setSource($source)
]);
Комментарии:
1. Большое вам спасибо за вашу реакцию @Zauberfisch. Я понимаю ваше объяснение. Это в основном возвращает массив данных, который шаблон не умеет интерпретировать. Единственная проблема, с которой я сейчас сталкиваюсь, заключается в том, что я не могу использовать пример, приведенный в вашей части tl;dr, потому что я визуализирую форму php в своем шаблоне следующим образом:
<div class="filter-holder">$createEventsFilterForm</div>
я что-то упускаю или мне нужно изменить способ представления своей формы? Заранее спасибо, ваш ответ очень хорошо объяснен!2. Я неправильно понял часть своего вопроса. Обновлен ответ (нижняя половина новая)
3. Ааа, да. Огромное спасибо. Я никогда не понимал, что пытаюсь вставить массив в массив, и это будет выглядеть так!