SilverStripe 如何从多种页面类型中获取 Children(back-end 并输出)

SilverStripe How to get Children from multiple page types (back-end and output)

我不知道如何只用文字来写这个问题,所以在我开始解释之前,这里有一个漂亮的小 ascii 图,供您参考...

                                                +-----+
  Department             Department             |Shows |
       +                     +                  +--+--+
       |                     |                     ^
       +->ShowAssignment     +>ShowAssignment       |
                +                                  |
      +------------------------+                   |
      |         |              |                   |
      v         v              v                   |
AssignShow   AssignShow   AssignShow                |
 +                                                 |
 |   +------+                                      |
 +-->Content|                                      |
 |          |                                      |
 +-->Content+--------------------------------------+
 |          |
 +-->Content|
     +------+

顺便说一句 - 让我们假设我们正在尝试获得第一个 AssignShow,其中有 3 child 篇文章。

好的,现在您已经了解了发生了什么,让我们开始吧。

在每个 Department 中有一个 ShowAssignment 页面,在它下面每个 child 页面是一个 AssignShow 页面,可以有 Content 个页面与特定部门在节目中所做的工作。

Shows 页面中有一个部分可以找到所有已分配给它的部门并将其列在页面上。我已经能够检索所有指定的部门,但似乎无法深入了解每个部门为该节目所做的所有内容...

更多视觉效果 :) 我有大蓝色的部门,'Static fo da mo' 是我需要那些文章的标题和一个 link它的页面

这是我目前拥有的代码:

Shows.php

 # Get Departments assigned to this show
 public function getAssignedDepartments(){

    $result = new ArrayList();

    # use this shows ID to find out what shows have been selected by departments
    $assignedShowID = AssignShow::get()->filter('ShowsID', $this->ID);

    if(count($assignedShowID) > 0){

        foreach($assignedShowID as $dept){

            $department = Department::get()->byID($dept->DepartmentID);

            $result->add(new ArrayData(array(
                'DepartmentTitle' => $department->Title
                )
            ));

        # This here is where i'm super stuck... I've managed to drill down
        # this far but dont know how to get those darn kids!
        $x = $department
            ->Children()
            ->find('ClassName', 'ShowAssignments')
            ->Children();
        }

        # Title (on the first echo) returns the
        # show title so I know it's targeting correctly...
        foreach ($x as $key) {
            echo $key->Title . '<br>';
            echo $key->Children()->Title . '<br>';
        }

        return $result;
    }
    else
        return null;
 }

所以总而言之,我最近尝试获得 children 得到了 AssignShow 页面的标题,但使用类似 $key->Children() 的东西却没有让我再深入一步...我需要做什么?


编辑,新信息

Righty-o,所以我设法获得了 children 并能够通过 bummzack

提供的帮助访问他们的信息

Update

If you just need to traverse the hierarchy in code, you should be aware that Children is a List, so something like $this->Children()->Title won't work. You'll need something like:

 $children2LevelsBelow = array();
 foreach ($this->Children() as $child) {
    // Go one level deeper…
    foreach ($child->Children() as $subChild) {
        $children2LevelsBelow[] = $subChild;
    }
 }

I think this is the key part that was missing from the code posted with your question.


我目前的代码是这样的(仍在开发中所以有点不完整,但是上面的答案帮助我更接近了)

Show.php

 # Get Departments assigned to this show
 public function getAssignedDepartments(){

     $result = new ArrayList();

     # use this shows ID to find out what shows have been selected in departments
     $assignedShowID = AssignShow::get()->filter('ShowsID', $this->ID);

     if(count($assignedShowID) > 0){

         foreach($assignedShowID as $dept){

             $department = Department::get()->byID($dept->DepartmentID);

             $result->add(new ArrayData(array(
                 'DepartmentTitle' => $department->Title,
                 'Link' => '/film/departments/' . $department->URLSegment
                 )
             ));

             # this gets me what I need... ALMOST -_-
             foreach($dept->Children() as $x) {
                 echo '<br>' . $x->Title . '<br>'; # get AssignShow child Title
                 echo $x->Content; # gets AssignShow child content (not that i need it)
             }
         }
         return $result;
     }
     else
         return null;
 }  

我不明白的是如何输出每个部门下的内容列表...
因此,对于下面 HTML 中的每个 grid-listing,在下一个块运行之前,它需要 1 个或更多 <li> 来配合它...

这是 HTML / 模板的片段,我将其用于

Shows.ss

 <% loop AssignedDepartments %>

    <div class="grid-listing">

        <h2><a href="$Link">$DepartmentTitle</a></h2>

        <ul>
            <%-- How do I loop in a loop to get a list of ALL li --%>
            <%-- before moving onto the next department in the main loop? --%>
            <li>&rsaquo; <a href="#NoLink">$ContentTitle</a></li>
            <%-- end_loop --%>
        </ul>

    </div><!-- . grid-listing -->

 <% end_loop %>

我猜你有从 ShowsDepartment 的关系,也许是 has_manymany_many

所以你应该能够在你的 Shows 模板中做这样的事情:

<% loop $Departements %>
<div class="departement">
    <h1>$Title</h1>
    <% loop $Children %>
    <div class="show-assignment">
        <h2>$Title</h2>
        <% loop $Children %>
        <div class="assign-show">
            <h3>$Title</h3>
            <% loop $Children %>
                <div class="content">
                    <h4>$Title</h4>
                </div>
            <% end_loop %>
        </div>
        <% end_loop %>
    </div>
    <% end_loop %>
</div>
<% end_loop %>

虽然它看起来很迷人,但这样的模板相当丑陋,如果您打算更改层次结构,则效果不佳……

相反,您可以在 Page class 中使用一种特殊方法递归地呈现它的子项。

例如。在 Page class:

中创建这样的方法
public function RecursiveChildren(){
    return $this->renderWith(array('RC' . $this->ClassName, 'RCPage'));
}

这只是使用 RC<ClassName>RCPage 模板呈现当前页面,具体取决于可用的模板。所需的最小模板为 RCPage.ss,可能如下所示。

<div class="$ClassName">
    <h1>$Title</h1>
    <% if $Children %><% loop $Children %>
        $RecursiveChildren
    <% end_loop %><% end_if %>
</div>

然后您可以将上面的复杂模板替换为如下内容:

<% loop $Departements %>
$RecursiveChildren
<% end_loop %>

它会创建与上面的复杂模板几乎相同的输出。

要为每种页面类型设计不同的模板,您可以继续创建:RCDepartment.ssRCShowAssignment.ss 等,每个负责呈现所述页面类型的片段。

更新

如果你只是需要在代码中遍历层次结构,你应该知道 Children 是一个 List,所以像 $this->Children()->Title 这样的东西是行不通的。你需要这样的东西:

$children2LevelsBelow = array();
foreach ($this->Children() as $child) {
    // Go one level deeper…
    foreach ($child->Children() as $subChild) {
        $children2LevelsBelow[] = $subChild;
    }
}

我认为这是与您的问题一起发布的代码中缺少的关键部分。

我做到了!查询有点复杂,我打算使用 SQL 但设法坚持使用 SilverStripes ORM。此外,我试图在同一函数内获取数据并使用相同的 $result->add(),这可能就是我发现它如此困难的原因...

这是它的工作顺序。

Shows.php
我们得到分配给我们正在观看的节目的部门。我们为部门 ID 输入 return 值,稍后我们将使用它

 # Get Departments assigned to this show
 public function getAssignedDepartments(){

     $result = ArrayList::create();

     # use this shows ID to find out what shows have been selected in departments
     $assignedShowID = AssignShow::get()->filter('ShowsID', $this->ID);

     if(count($assignedShowID) > 0){

         foreach($assignedShowID as $dept){

             $department = Department::get()->byID($dept->DepartmentID);

             $result->add(ArrayData::create(array(
                 'Title' => $department->Title,
                 'Link' => '/film/departments/' . $department->URLSegment,
                 'DepartmentID' => $dept->DepartmentID
                 )
             ));
         }

         return $result;
     }
     else
         return null;
 }

Shows.ss
我们使用上面的方法获取分配给节目的部门并循环遍历它们。在循环时,我们需要第二个循环来获取该部门的 children,我们需要它在进入下一个部门循环之前遍历所有 children。为了确保我们获得正确的内容,我们在 DepartmentID 中传递以在 getDepartmentContent 函数中使用

 <% loop AssignedDepartments %>

     <div class="grid-listing">

         <h2><a href="$Link">$Title</a></h2>

         <ul>
             <% loop $Up.getDepartmentContent($DepartmentID) %>
             <li>&rsaquo; <a href="$Link">$Title</a></li>
             <% end_loop %>
         </ul>

     </div><!-- . grid-listing -->

 <% end_loop %>

Shows.php
现在我们得到 children,这是我遇到很多麻烦的部分。我们使用传入的 DepartmentID 来帮助我们过滤相关内容,否则它会获取分配给节目的所有内容并为每个部门输出,这是不准确的。我们还使用 URLSegments

构建 URL
 public function getDepartmentContent($DepartmentID){

     # filter result to get the AssignShow which matches this show
     # and the department id supplied param
     $assignedShowID = AssignShow::get()->filter(array(
         'ShowsID' => $this->ID,
         'DepartmentID' => $DepartmentID
         )
     );

     $result = ArrayList::create();

     foreach($assignedShowID as $key){

         foreach($key->Children() as $children){

             # AssignShow
             $assignShow = AssignShow::get()->byID($children->ParentID);

             # ShowAssignment
             $showAssignment = ShowAssignments::get()->byID($assignShow->ParentID);

             # Department
             $department = Department::get()->byID($showAssignment->ParentID);

             # full url path
             $link = $department->URLSegment . '/'
                     . $showAssignment->URLSegment . '/'
                     . $assignShow->URLSegment . '/'
                     . $children->URLSegment;

             $result->add(ArrayData::create(array(
                 'Title' => $children->Title,
                 'Link' => 'film/departments/' . $link
                 )
             ));
         }
     }

     return $result;
 }

这里的这种方式为我提供了我所需要的检索方式。它还保留了 Controller 中包含的所有内容以保持整洁。