Reputation: 460
I didn't know how to write the question using just words so here's a nifty little ascii diagram of what I got going on for your reference before I begin explaining...
+-----+
Department Department |Shows |
+ + +--+--+
| | ^
+->ShowAssignment +>ShowAssignment |
+ |
+------------------------+ |
| | | |
v v v |
AssignShow AssignShow AssignShow |
+ |
| +------+ |
+-->Content| |
| | |
+-->Content+--------------------------------------+
| |
+-->Content|
+------+
BTW - moving forward lets pretend that we're trying to get the first AssignShow
with it's 3 child articles.
Alrighty, so now you've got a visual of what's up let's get to it.
In every Department
there is a ShowAssignment
page and under it every child page is an AssignShow
page that can have Content
pages relating to the work a particular department is doing on a show.
In the Shows
pages there is a section which finds all the departments that have been assigned to it and lists it out on the page. I have been able to get as far as retrieving all the assigned departments but cannot seem to be able to get down to getting the all the content of what each department is doing for that show...
More visuals :) I have the departments in big blue and where 'Static fo da mo' is I need the title of those articles and a link to its page
Here is the code I currently have :
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;
}
So all in all my latest attempt of getting the children got me as far as getting the Title of the AssignShow
page but using something like that $key->Children()
doesn't let me go 1 step deeper... What do I need to do?
Edit, new info
Righty-o, so I've managed to get the children and able to access their info from the help given by 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.
The code I have at the moment is like this (still in development so its a bit incomplete, but the answer above has assisted me in getting closer)
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;
}
What I don't understand is how do I output a list of content under every department...
So for every grid-listing
in the HTML below it'll need 1 or more <li>
's to go with it before the next block runs...
Here is a snippet of the HTML / template I'm using this for
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>› <a href="#NoLink">$ContentTitle</a></li>
<%-- end_loop --%>
</ul>
</div><!-- . grid-listing -->
<% end_loop %>
Upvotes: 2
Views: 1044
Reputation: 460
I done did it! It was the querying that was a bit complicated and I was going to resort to using SQL but managed to stick with SilverStripes ORM. Additionally I was trying to get the data within the same function and using the same $result->add()
which is probably why I found it so difficult...
This is the order of how it works.
Shows.php
We get the departments that are assigned to the show we're viewing. We put in a return value for the ID of the department, we'll be using that later
# 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
We use the above to get the departments assigned to the show and loop through them. While looping we need a second loop to get the children of that department, we need it to loop through all the children before moving onto the next department loop. To ensure we're getting the right content we pass in the DepartmentID
to use in the getDepartmentContent
function
<% loop AssignedDepartments %>
<div class="grid-listing">
<h2><a href="$Link">$Title</a></h2>
<ul>
<% loop $Up.getDepartmentContent($DepartmentID) %>
<li>› <a href="$Link">$Title</a></li>
<% end_loop %>
</ul>
</div><!-- . grid-listing -->
<% end_loop %>
Shows.php
Now we get the children, this was the part I had quite a lot of trouble with. We use the DepartmentID
we passed in to help us filter relevant content, otherwise it'll get all the content assigned to the show and output it for every department, which isn't accurate. We also build the URL using the URLSegments
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;
}
This way here provides me with exactly what I needed to retrieve in the way I needed it. It also kept everything contained in the Controller
to keep it neat.
Upvotes: 0
Reputation: 5875
I guess you have a relation from Shows
to Department
, maybe has_many
or many_many
?
So you should be able to do something like this in your Shows
template:
<% 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 %>
While it looks mesmerizing, a template like this is rather ugly and doesn't play well if you ever plan to change the hierarchy…
Instead, you could just have a special method in your Page
class that renders it's children recursively.
Eg. create a method like this in your Page
class:
public function RecursiveChildren(){
return $this->renderWith(array('RC' . $this->ClassName, 'RCPage'));
}
This simply renders the current page with an RC<ClassName>
, or RCPage
template, depending on what is available. The minimal required template would be RCPage.ss
and could look like this.
<div class="$ClassName">
<h1>$Title</h1>
<% if $Children %><% loop $Children %>
$RecursiveChildren
<% end_loop %><% end_if %>
</div>
What you can then do, is replace the complex template above with something like this:
<% loop $Departements %>
$RecursiveChildren
<% end_loop %>
And it will create pretty much the same output as the complex template above.
To design different templates for each page type, you could go ahead and create: RCDepartment.ss
, RCShowAssignment.ss
etc. each responsible for rendering the fragment of said page-type.
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.
Upvotes: 2