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
Related
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.
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
Currently I have 4 spans with alternating CSS tags.
<% var index =0 ; %>
<% foreach (var item in Model.Take(4)) {
var css = (index%2==0)?"even":"odd";
%>
<span class="featured-products <%= css %>">
<%= Html.Photo(PhotoExtensions.PhotoSizeType.HomepageThumb, item.DefaultPhoto)%>
<%= item.ProductName%>
</span>
<%
index ++ ;
} %>
But I need for the last span to contain an extra CSS tag "last". Ive tried a couple of different methods but they all failed. Any help? Thanks.
Have you tried using the :last-child CSS selector? It may not be necessary to add additional markup if you can achieve what you want through CSS.
If you don't want to use CSS.
<% var index = 0; %>
<% var items = Model.Take(4); %>
<% foreach (var item in items) {
var css = (index%2==0)?"":"odd";
if(index == items.Count - 1)
{
css = " last";
}
%>
<span class="featured-products <%= css %>">
<%= Html.Photo(PhotoExtensions.PhotoSizeType.HomepageThumb, item.DefaultPhoto)%>
<%= item.ProductName%>
</span>
<%
index ++ ;
} %>
Also, I would recommend cleaning this code up. You don't need to put <% and %> everywhere.
Update: A bit cleaner way of writing what you're doing. Definately not the cleanest but a good start.
<%
var index = 0;
var items = Model.Take(4);
foreach (var item in items) {
var css = (index%2==0)?"":"odd";
if(index == items.Count - 1)
{
css = " last";
}
%>
<span class="featured-products <%= css %>">
<%= Html.Photo(PhotoExtensions.PhotoSizeType.HomepageThumb, item.DefaultPhoto)%>
<%= item.ProductName%>
</span>
<%
index ++ ;
}
%>
I want to display an image that I loop it from the folder.
<div class="blah">
<% System.IO.FileInfo[] files = new System.IO.DirectoryInfo(Server.MapPath("/MyPath/"))
.GetFiles();
var exefiles = from System.IO.FileInfo f in files
where f.Extension == ".jpg" ||f.Extension == ".jpeg"
|| f.Extension == "JPG"
select f;
foreach (System.IO.FileInfo f in exefiles) { %>
<img src="blahblah.jpg" />
<% } %>
</div>
Problem : The div display all the images that store in the folder.
But I want to display only 1 image in my div.
Thank you so much.
Should be able to do this with Directory.GetFiles Method (String, String) (System.IO)
something like:
<div class="blah">
<%
string path = "images/";
string[] files = System.IO.Directory.GetFiles(Server.MapPath(path), "*jp*g");
if (files.Length > 0) { %>
<img src="<%= path + System.IO.Path.GetFileName(files[0])%>" />
<% } %>
</div>
You shouldn't have any login inside your view, that's why it's called Model View Controller. Put your logic inside the Action and pass it to the view inside the model or the ViewBag.
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/