Функции циклов шаблона Silverstripe 3 и вложенные циклы

Доброе утро,

Я боролся с Silverstripe, и это синтаксический анализ шаблонов в отношении вложенных циклов и функций внутри циклов уже некоторое время, что это становится безумием.

Если я смогу получить альтернативное решение помимо ajax (это должен быть чистый php/html/ss), это будет приемлемо, спасибо.

[Situation]
I have 2 Data Objects: ObjectA [has_many ObjectB], and ObjectB [has_one ObjectA].
I've implemented a tab-pane using CSS-Bootstrap, and would like to display these two objects linked in their respective tabs.

Example:
ObjectA_Car is mapped to [ObjectB_Process1, ObjectB_Process2]
ObjectA_Plane is mapped to [ObjectB_Process3, ObjectB_Process4]

Сценарий 1.
См. пример псевдокода ниже:

///>sample.ss snippet
<% loop ObjectA_DataList %>
    <div class="tab-pane">
        <h3>$ObjectA_DataList.Title</h3> <!-- Prints ObjectA Title -->
        <hr />
        <h4>$ObjectA_DataList.Description</h4> <!-- Prints ObjectA Description -->
        DEBUG: $Pos <!-- Prints ObjectA loop count/index -->

        <!-- PROBLEM STARTS HERE -->    
        <% loop ObjectB_DataList %>
             DEBUG: ObjectA Count: $Top.Pos <!-- Always prints 1, regardless -->
             DEBUG: ObjectA Count2: $Up.Pos <!-- Same issue as above -->
             DEBUG: $Pos <!-- due to scope, this now prints ObjectB loop count/index -->
        <% end_loop %>
    </div> <!--//#tab-pane-->
<% end_loop %>   

Моя цель в приведенном выше примере заключалась в том, что я пытался сопоставить ObjectA $Pos внутри цикла ObjectB с идентификатором, принадлежащим ObjectB. Не работает, потому что я не могу получить текущий цикл ObjectA $Pos, находясь внутри ObjectB.

Сценарий 2.
Далее я попытался использовать функцию.

///>sample extension code
public function testfn(){
    return "<pre>testfn called!</pre>";
}//testfn

///>sample.ss
$testfn <!-- WORKS OUTSIDE OF LOOP -->
<% loop ObjectA_DataList %>
    $testfn <!-- DOES NOT WORK! -->
<% end_loop %>

Сценарий 3
Мне надоели попытки заставить вышеперечисленные сценарии работать, и я попытался использовать контроллер.
Итак, я решил передать ArrayList в шаблон и выполнить итерацию. над ним с помощью одного цикла.
Но я не могу получить значения. См. ниже:

///>sample_controller.php
public function sample(SS_HTTPRequest $request){
    ///... snippet ...
    $buildArr = array();
    foreach($ObjectA as $objA){
       $buildArr[$objA->ID]['objA'] = $objA; //store ObjectA
       $objB = ObjectB::get()->filter(array('Status'=>'Enabled','ObjectA_ID'=>$objA->ID));
       $buildArr[$objA->ID]['objB'] = $objB; //store ObjectB
    }//foreach loop

    $sample_data = new ArrayList($buildArr);
    //if I do a var_dump here, everything looks great.
    //so nothing seems to be the problem with the $sample_data array

    $data = array('mysample' => $sample_data);
    return $this->customise($data)->renderWith(array('sample', 'Page'));
}//sample

///>sample.ss
<% loop mysample %>
      <!-- I don't know how to get the data out -->
      <!-- I've tried $Title, $mysample.Title, $mysample.ObjectA.Title -->
      <!-- nothing seems to work. -->
<% end_loop %>

Любая оказанная помощь очень ценится, спасибо.


person add    schedule 19.11.2014    source источник


Ответы (1)


Доброе утро!

Я могу помочь вам прийти к решению, используя ваши сценарии 2 и 3. Для первого я бы не знал, как правильно обратиться к области действия первого цикла.

Сценарий 2

Это довольно просто. Вам просто нужно обратиться к общему объему Top:

///>sample extension code
public function testfn(){
    return "<pre>testfn called!</pre>";
}//testfn

///>sample.ss
$testfn <!-- WORKS OUTSIDE OF LOOP -->
<% loop ObjectA_DataList %>
    $Top.testfn <!-- SHOULD WORK LIKE THIS -->
<% end_loop %>

Сценарий 3

Я скорректировал третий сценарий, чтобы выполнить работу здесь:

///>sample_controller.php
public function sample(SS_HTTPRequest $request){
    // get ObjectA
    $ObjectA = ObjectA::get();

    // run through all ObjectA and add the
    // information from ObjectB to a list of both
    $data = new ArrayList();
    foreach($ObjectA as $objA){
        $objB = ObjectB::get()->filter(array(
            'Status' => 'Enabled',
            'ObjectA_ID' => $objA->ID
        ));
        $data->add(array(
            'ObjA' => $objA,
            'ObjB' => $objB
        ));
    }//foreach loop

    return $this->customise(array('mysample' => $data))
        ->renderWith(array('sample', 'Page'));
}//sample

///>sample.ss
<% loop $mysample %>
    <!-- for a single DataObject -->
    <p>ObjA: $ObjA.ID</p>

    <!-- for a DataList -->
    <% loop $ObjB %>
        <p>ObjB: $ID</p>
    <% end_loop %>
<% end_loop %>

Этот подход должен работать как с одним DataObject, так и со списком DataList (аналогично ArrayList). В зависимости от того, какие данные вы добавляете в ArrayList в контроллере, вам нужно настроить свой SS-файл.

Дайте мне знать, если у вас возникнут дополнительные вопросы.

Отказ от ответственности: непроверено и без каких-либо гарантий, все еще должно работать

person spekulatius    schedule 19.11.2014
comment
Обычно я возвращаю деньги с процентами. Наверное, поэтому мои неправильные ответы всегда воспринимаются очень хорошо. Но, учитывая сценарии 2 и 3, я должен согласиться с @spekulatius. Меня также очень интересует сценарий 1, так как я столкнулся с той же проблемой. Может быть, можно что-то сделать с частями шаблона, которые возвращаются из контроллера, чтобы вы могли смешивать шаблон с обычным кодом? - person jberculo; 20.11.2014
comment
@spekulatius: Большое спасибо. Оба ваших решения работают. В сценарии 3 у вас просто есть небольшая опечатка в начале при получении $ObjectA. Должно быть $ObjectA = ObjectA::get(), вы сделали ошибку и присвоили B A, а также конструктору для ArrayList нужен параметр массива. Итак, новый ArrayList() должен быть new ArrayList(array()); Спасибо миллион, отличное решение. - person add; 20.11.2014
comment
Что касается последней части комментария «jberculo»: может быть, можно что-то сделать с частями шаблона, которые возвращаются из контроллера, чтобы вы могли смешивать шаблон с обычным кодом? Я поддерживаю это. Это очень поможет. - person add; 20.11.2014
comment
Я исправил ObjectB::get(). О списке массивов. Его можно вызывать с массивом или без него. __construct(array $items = array()) { устанавливает пустой массив по умолчанию, если в качестве параметра ничего не указано. Для сценария №1 я все еще думаю над решением. Если появится, добавлю. - person spekulatius; 21.11.2014
comment
Любой возврат, завернутый в объект HTMLCode, будет распечатан. Это часто делается с помощью функции forTemplate. Дополнительную информацию можно найти по адресу: groups.google.com/forum/# !topic/silverstripe-dev/Cw8pmtuBd_0 Если у вас есть вопросы по этому поводу, просто задайте другой вопрос :) - person spekulatius; 21.11.2014