Почему моя функция выводит «метод» forTemplate «не существует в» SilverStripeViewArrayData»

#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. Ааа, да. Огромное спасибо. Я никогда не понимал, что пытаюсь вставить массив в массив, и это будет выглядеть так!