$Pos from bottom inside <% loop DataObjects %> - silverstripe

can one inside a loop in template over a DataObject somehow tell wether you're at $Pos 24 but counted from bottom - something like:
<% if Pos = "-24" %>do stuff<% end_if %>
or like
<% if TotalItems - 24 = Pos %>do stuff<% end_if %>
or like
<% if Last(24) %>do stuff<% end_if %>

In Silverstripe 3, to be able to do:
<% if FromBottom(24) %>
Hello
<% end_if %>
you'll have to add MyCustomIteratorFunctions.php to your /code folder with the following contents:
<?php
class MyCustomIteratorFunctions implements TemplateIteratorProvider
{
protected $iteratorPos;
protected $iteratorTotalItems;
public static function get_template_iterator_variables()
{
return array('FromBottom');
}
public function iteratorProperties($pos, $totalItems)
{
$this->iteratorPos = $pos;
$this->iteratorTotalItems = $totalItems;
}
function FromBottom($num)
{
return (($this->iteratorTotalItems - $this->iteratorPos) == $num);
}
}
as seen here: https://groups.google.com/forum/#!msg/silverstripe-dev/DVBtzkblZqA/PWxanKGKDYIJ

Related

How compare date and current date in Silvrerstripe template?

In Silverstripe template I need to compare variable $date_ok with current date like this : if($date_ok < date("j, n, Y") {...};
<% loop $IzdMat %>
<tr>
<td>$num</td>
<td>$sert_otip </strong> <br>Valid from $date_start till
$date_ok</td>
<% if $date_ok < ****** %>
..............
<% end_if %>
.......
What I have to write insted of ****** ?
You can add a method to the DataObject rather than trying to do complicated logic in the templates. This is assuming that date_ok is a date field defined in the $db array.
class IzdMat extends DataObject {
public function IsDateOk() {
$today = date("Y-m-d");
return (strtotime($today) < strtotime($this->date_ok));
}
}
Then in your template.
<% loop $IzdMat %>
<tr>
<td>$num</td>
<td>$sert_otip </strong> <br>Valid from $date_start till
$date_ok</td>
<% if $IsDateOk %>
..............
<% end_if %>
</tr>
<% end_loop %>

Creating article pagination

Hi I'm using silverstripe 2.4.7 and I'm having difficulty getting the pagination to work. I've created a function in my page.php to get the latest articles like so
function AllNewsPosts($num=1) {
$news = DataObject::get_one("NewsHolder");
return ($news) ? DataObject::get("NewsEntry", "ParentID > 0", "Date DESC", "", $num) : false;
}
Then when i put this function into the control and pagination tags one article shows up however the links to the concurrent articles do not work - essentially the pagination is not working and I'm not sure how to fix it
<% if AllNewsPosts %>
<% control AllNewsPosts %>
<div class="event">
<h2>$MenuTitle |<span class="date"> $Date.Time $Date.Long</span></h2>
<p>$Content.FirstParagraph</p>
See more about this event
</div>
<% end_control %>
<% else %>
<div class="no-entry">'There are no entries'</div>
<% end_if %>
<% if AllNewsPosts.MoreThanOnePage %>
<div id="PageNumbers">
<p>
<% if AllNewsPosts.NotFirstPage %>
<a class="prev" href="$AllNewsPosts.PrevLink" title="View the previous page"><span class="yellow-background">Prev</span></a>
<% end_if %>
<span>
<% control AllNewsPosts.PaginationSummary(0) %>
<% if CurrentBool %>
<span class="current">$PageNum</span>
<% else %>
<% if Link %>
$PageNum
<% else %>
…
<% end_if %>
<% end_if %>
<% end_control %>
</span>
<% if AllNewsPosts.NotLastPage %>
<a class="next" href="$AllNewsPosts.NextLink" title="View the next page"><span class="yellow-background">Next</span></a>
<% end_if %>
</p>
</div>
<% end_if %>
Any help is much appreciated
Note: The following answer is for Silverstripe 2.4. This should not be used for Silverstripe 3.0+ sites. From 3.0 and onwards the PaginatedList object makes pagination much easier.
You are not setting a limit on how many entries to retrieve in your query, or where to start from.
The following tutorial explains how to apply pagination to a set of data objects exactly as you are trying to do:
http://www.ssbits.com/tutorials/2010/paginating-a-filtered-dataobjectset/
Here is an attempt at altering your function to include limit and start as needed for pagination:
PHP
function AllNewsPosts() {
if(!isset($_GET['start']) || !is_numeric($_GET['start']) || (int)$_GET['start'] < 1)
{
$_GET['start'] = 0;
}
$SQL_start = (int)$_GET['start'];
$newsEntries = DataObject::get('NewsEntry', '', 'Date DESC');
$doSet = new DataObjectSet();
foreach ($newsEntries as $newsEntry) {
if ($newsEntry->canView()) {
$doSet->push($newsEntry);
}
}
$doSet->setPageLimits($SQL_start, 10, $doSet->Count());
return $doSet;
}
Note the above will display 10 items per page. You can change this to however you need per page.

SilverStripe 3: Image Object in controller function

I'm trying to write a function that displays images from the child pages on the Holder Page.
Because SilverStripe lacks some functionality on templates I figured it will be best to process it all in the controller.
There are some conditional statements I require which can only be done in php.
Controller.php
public function LatestWork() {
$works = WorkPage::get();
$i = 1;
$html = "";
foreach ($works as $work) {
//Build the IMage Object so we can add it to the Work Object
$ImageObj = File::get()->byID($work->FeaturedImageID);
if ($this->is_odd($i)) {
$html .= "<div class='row'>";
$span = "span8";
} else {
$span = "span4";
}
$html .= "<div class = '$span'>" . $ImageObj->croppedImage(200,100) . "</div>";
if ($this->is_even($i) || $i == $works->Count()) {
$html .= "</div>";
}
$i++;
}
return $html;
}
When its processed in the view the divs and spans are there but the image is not. There are more conditions in the code but this is just the basic version.
It displays "Image_Cached" instead.
How can I make it display the image?
Controller:
public function LatestWork() {
$rows=new ArrayList();
foreach(WorkPage::get() as $workPage){
if (!isset($bucket)){
$bucket = new ArrayList();
$bucket->push($workPage);
$rows->push($bucket);
} else {
$bucket->push($workPage);
unset($bucket);
}
}
return $rows;
}
Template:
<% loop LatestWork %>
<div class="row">
<% if Odd %>
<div class="span-8">
<% with $Me.First %>$FeaturedImage.CroppedImage(200,100)<% end_with %>
</div>
<div class="span-4">
<% with $Me.Last %>$FeaturedImage.CroppedImage(100,50)<% end_with %>
</div>
<% else %>
<div class="span-4">
<% with $Me.First %>$FeaturedImage.CroppedImage(100,50)<% end_with %>
</div>
<div class="span-8">
<% with $Me.Last %>$FeaturedImage.CroppedImage(200,100)<% end_with %>
</div>
<% end_if %>
</div>
<% end_loop %>
would be the SS way to do it, so that your display logic doesn't clutter your controller

Silverstripe: Excluding current page from list of the parent's children

Using Silverstripe's "ChildrenOf" syntax, I've been successfully able to list all children of a page's parent. It's being used in a "see also" style list on a page.
I'd like to exclude the current page from the list but unsure how to determine which is the same as the current page, as within the control loop I'm in the parent's scope. Any ideas? Here's a pseudocode of what I'm doing:
<% control ChildrenOf(page-url) %>
<!-- Output some stuff, like the page's $Link and $Title -->
<% end_control %>
there's a built-in page control for this, so to exclude the current page from your list:
<% control ChildrenOf(page-url) %>
<% if LinkOrCurrent = current %>
<!-- exclude me -->
<% else %>
<!-- Output some stuff, like the page's $Link and $Title -->
<% end_if %>
<% end_control %>
see http://doc.silverstripe.org/sapphire/en/reference/built-in-page-controls#linkingmode-linkorcurrent-and-linkorsection
UPDATE
as you mentioned in your comment below that you'd like to use the $Pos control, you need to filter the dataobjectset before iterating over it.
add the following to your Page_Controller class:
function FilteredChildrenOf($pageUrl) {
$children = $this->ChildrenOf($pageUrl);
if($children) {
$filteredChildren = new DataObjectSet();
foreach($children as $child) {
if(!$child->isCurrent()) $filteredChildren->push($child);
}
return $filteredChildren;
}
}
then replace 'ChildrenOf' in your template by 'FilteredChildrenOf':
<% control FilteredChildrenOf(page-url) %>
//use $Pos here
<% end_control
In Silverstripe 3.1 you can use a method like this -
<% loop $Parent.Children %>
<% if $LinkingMode != current %>
<!-- Output some stuff, like the page's $Link and $Title , $Pos etc -->
<% end_if %>
<% end_loop %>
This way you can list all parent's children pages.
See https://docs.silverstripe.org/en/3.1/developer_guides/templates/common_variables/

HTML 'id' attribute for items in dropdown made from html helper

Can we set an id attribute as I would for something like a table column via:
for an html dropdown list element that is created with a helper such as:
<% for (int i = 0; i < Model.Trx.TransactionHolidayCityCollection.Count; i++)
{%>
<%= i > 0 ? "," : "" %>
<%= DropDownData.HolidayDays().ToList().Find(item => item.Value == Model.Trx.TransactionHolidayCityCollection[i].HolidayCityID.Value.ToString()).Text %>
<%} %>
You don't need a helper, necessarily:
<select id="holidayCities" name="holidayCities">
<% foreach (HolidayCity city in Model.Trx.TransactionHolidayCityCollection) { %>
<option
value="<%=city.HolidayCityID.Value %>"
id="holidayCity_<%=city.HolidayCityID.Value %>"
><%=city.Name %></option>
<% } %>
</select>
If you wanted to use the HtmlHelper you can write:
<%=Html.DropDownList("holidayCities", Model.HolidayCitiesSelectList) %>
Model.HolidayCitiesSelectList should be of type IEnumerable<SelectListItem>
This type of customization isn't avaiable for the built in helpers so you might end up creating your own Html.DropDownList helper method.
http://msdn.microsoft.com/en-us/library/system.web.mvc.selectlistitem(v=vs.98).aspx

Resources