Skip to content

Commit

Permalink
Refactor|Homepage|Feed: Reworked Feed into a "dumb" abstraction layer
Browse files Browse the repository at this point in the history
The Feed class no longer provides a mechanism for generating HTML
content from the underlying feed.
  • Loading branch information
danij-deng committed Jul 1, 2013
1 parent 578618c commit 7af3f01
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 162 deletions.
184 changes: 55 additions & 129 deletions web/classes/feed.class.php
@@ -1,175 +1,101 @@
<?php
/**
* @file feed.class.php
* Abstract class which encapsulates a content feed behind an object interface.
/** @file feed.class.php Abstract feed.
*
* @section License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
* Encapsulates a content feed with object API and interface semantics.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
* @authors Copyright © 2009-2013 Daniel Swanson <danij@dengine.net>
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* @author Copyright &copy; 2009-2013 Daniel Swanson <danij@dengine.net>
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA</small>
*/

includeGuard('Feed');

require_once(DIR_CLASSES.'/visual.interface.php');
require_once(DIR_EXTERNAL.'/magpierss/rss_fetch.inc');

class Feed implements Visual, Iterator, Countable
class FeedItem
{
public static $name = 'pages';

private static $displayOptions = 0;
public $author;
public $timestamp; // unix
public $title;
public $link;
public $description;
}

private $maxItems;
class Feed implements Iterator, Countable
{
private $feedFormat;
private $feedUri;
private $feed;
private $position;

private $title = 'Untitled';
private $labelSpanClass = NULL;

// Callback to make when generating Html for a feed item.
private $func_genElementHtml = NULL;
private $func_genElementHtmlParams = NULL;

public function __construct($feedURL, $maxItems=5)
{
$this->feedUri = $feedURL;
$this->maxItems = intval($maxItems);
$this->feedFormat = 'RSS';
$this->position = 0;

$this->feed = fetch_rss($this->feedUri);
if(!$this->feed || $this->feed->ERROR)
{
$this->feed = NULL;
}
}

public function setTitle($title, $labelSpanClass=NULL)
{
$this->title = "$title";
if(!is_null($labelSpanClass))
$this->labelSpanClass = "$labelSpanClass";
}
private $items;
private $position;

public function setGenerateElementHtmlCallback($funcName, $params=NULL)
public function __construct($uri, $format = 'RSS')
{
$funcName = "$funcName";
if(!is_callable($funcName)) return FALSE;
$this->feedUri = (string)$uri;
$this->feedFormat = $format;

$this->func_genElementHtml = $funcName;
$this->func_genElementHtmlParams = $params;
return TRUE;
}

/**
* Implements Visual.
*/
public function displayOptions()
{
return $this->displayOptions;
}
$this->items = array();
$this->position = 0;

private function generateElementHtml(&$item)
{
if(!is_array($item))
throw new Exception('Received invalid item, array expected.');
$feed = fetch_rss($this->feedUri);
if(!$feed || $feed->ERROR)
return;

if(!is_null($this->func_genElementHtml))
foreach($feed->items as &$rawItem)
{
return call_user_func_array($this->func_genElementHtml, array($item, $this->func_genElementHtmlParams));
$newItem = new FeedItem();
$newItem->author = (string)$rawItem['author'];
$newItem->timestamp = $rawItem['date_timestamp'];
$newItem->title = (string)$rawItem['title'];
$newItem->link = (string)$rawItem['link'];
$newItem->description = (string)$rawItem['description'];

$this->items[] = $newItem;
}

$html = '<a href="'. preg_replace('/(&)/', '&amp;', $item['link'])
.'" title="'. date("m/d/y", $item['date_timestamp']) .' - '. htmlspecialchars($item['title'])
.'">'. htmlspecialchars($item['title']) .'</a>';
return $html;
}

public function generateHtml()
public function uri()
{
$feedTitle = "$this->title via $this->feedFormat";

?><a href="<?php echo preg_replace('/(&)/', '&amp;', $this->feedUri); ?>" class="link-rss" title="<?php echo htmlspecialchars($feedTitle); ?>"><span class="hidden"><?php echo htmlspecialchars($this->feedFormat); ?></span></a><?php

if(!is_null($this->labelSpanClass))
{
?>&nbsp;<span class="<?php echo $this->labelSpanClass; ?>"><?php
}

echo htmlspecialchars($feedTitle);

if(!is_null($this->labelSpanClass))
{
?></span><?php
}

?><ul><?php

if(is_object($this->feed) && count($this) > 0)
{
$n = (integer) 0;
foreach($this as $item)
{
$elementHtml = $this->generateElementHtml($item);

?><li><?php echo $elementHtml; ?></li><?php

if(++$n >= $this->maxItems) break;
}
}
else
{

?><li class="feed-error">...presently unavailable</li><?php

}

?></ul><?php
return $this->feedUri;
}

public function url()
public function format()
{
return $this->feedUri;
return $this->feedFormat;
}

/**
* Implements Countable.
*/
public function count()
{
if(is_object($this->feed) && is_array($this->feed->items))
return sizeof($this->feed->items);
return 0;
return count($this->items);
}

/**
* Implements Iterator.
*/
public function rewind()
{
reset($this->feed->items);
$this->position = key($this->feed->items);
reset($this->items);
$this->position = key($this->items);
}

public function current()
{
return $this->feed->items[$this->position];
return $this->items[$this->position];
}

public function key()
Expand All @@ -179,12 +105,12 @@ public function key()

public function next()
{
next($this->feed->items);
$this->position = key($this->feed->items);
next($this->items);
$this->position = key($this->items);
}

public function valid()
{
return isset($this->feed->items[$this->position]);
return isset($this->items[$this->position]);
}
}
97 changes: 64 additions & 33 deletions web/classes/frontcontroller.class.php
Expand Up @@ -225,18 +225,21 @@ public function enqueueAction($actioner, $args=NULL)
* Feed item HTML generator for formatting the customised output used
* with feeds on the homepage.
*/
static public function generateFeedItemHtml(&$item, $params=NULL)
static public function generateFeedItemHtml(&$item, $params = NULL)
{
assert('$item instanceof FeedItem /*$item argument is not a FeedItem */');
assert('(is_null($params) || is_array($params)) /*$params argument is not an array */');

$patterns = array('/{title}/', '/{timestamp}/');
$replacements = array($item['title'], date("m/d/y", $item['date_timestamp']));
$replacements = array($item->title, date("m/d/y", $item->timestamp));

if(is_array($params) && isset($params['titleTemplate']))
{
$title = preg_replace($patterns, $replacements, $params['titleTemplate']);
}
else
{
$title = $item['title'];
$title = $item->title;
}

if(is_array($params) && isset($params['labelTemplate']))
Expand All @@ -245,52 +248,84 @@ static public function generateFeedItemHtml(&$item, $params=NULL)
}
else
{
$label = $item['title'];
$label = $item->title;
}

$html = '<a href="'. preg_replace('/(&)/', '&amp;', $item['link'])
$html = '<a href="'. preg_replace('/(&)/', '&amp;', $item->link)
.'" title="'. htmlspecialchars($label)
.'">'. htmlspecialchars($title) .'</a>';

if(time() < strtotime('+2 days', $item['date_timestamp']))
if(time() < strtotime('+2 days', $item->timestamp))
{
$html .= '<span class="new-label">&nbsp;NEW</span>';
}

return $html;
}

private function outputNewsFeed()
private function generateFeedHtml(&$feed, $maxItems = 3,
$feedTitle = "", $labelSpanClass = "", $params = NULL)
{
require_once(DIR_CLASSES.'/feed.class.php');
$fullFeedTitle = "$feedTitle via {$feed->format()}";
$labelSpanClass = (string)$labelSpanClass;
$maxItems = (int)$maxItems;

$feed = new Feed('http://dengine.net/forums/rss.php?mode=news', 3);
$feed->setTitle('Project News', 'projectnews-label');
$feed->setGenerateElementHTMLCallback('FrontController::generateFeedItemHtml');
$feed->generateHTML();
}
?><a href="<?php echo preg_replace('/(&)/', '&amp;', $feed->uri()); ?>" class="link-rss" title="<?php echo htmlspecialchars($feedTitle); ?>"><span class="hidden"><?php echo htmlspecialchars($feed->format()); ?></span></a><?php

private function outputBuildsFeed()
{
require_once(DIR_CLASSES.'/feed.class.php');
if(!empty($labelSpanClass))
{
?>&nbsp;<span class="<?php echo $labelSpanClass; ?>"><?php
}

echo htmlspecialchars($fullFeedTitle);

$feed = new Feed('http://dl.dropboxusercontent.com/u/11948701/builds/events.rss', 3);
$feed->setTitle('Build News', 'projectnews-label');
$feed->setGenerateElementHTMLCallback('FrontController::generateFeedItemHtml',
array('titleTemplate'=>'{title} complete',
'labelTemplate'=>'Read more about {title}, completed on {timestamp}'));
$feed->generateHTML();
if(!empty($labelSpanClass))
{
?></span><?php
}

?><ul><?php

if($feed->count() > 0)
{
$n = (integer) 0;
foreach($feed as $item)
{
$elementHtml = $this->generateFeedItemHtml($item, $params);

?><li><?php echo $elementHtml; ?></li><?php

if(++$n >= $maxItems) break;
}
}
else
{

?><li class="feed-error">...presently unavailable</li><?php

}

?></ul><?php
}

private function outputDevBlogFeed()
private function outputNewsFeed()
{
require_once(DIR_CLASSES.'/feed.class.php');

$feed = new Feed('http://dengine.net/forums/rss.php?f=24', 3);
$feed->setTitle('Developer Blog', 'projectnews-label');
$feed->setGenerateElementHTMLCallback('FrontController::generateFeedItemHtml',
array('labelTemplate'=>'Read more about {title}, posted on {timestamp}'));
$feed->generateHTML();
{
$feed = new Feed('http://dengine.net/forums/rss.php?mode=news');
$this->generateFeedHtml($feed, 3, 'Project News', 'projectnews-label');
}
{
$feed = new Feed('http://dl.dropboxusercontent.com/u/11948701/builds/events.rss');
$this->generateFeedHtml($feed, 3, 'Build News', 'projectnews-label',
array('titleTemplate'=>'{title} complete',
'labelTemplate'=>'Read more about {title}, completed on {timestamp}'));
}
{
$feed = new Feed('http://dengine.net/forums/rss.php?f=24');
$this->generateFeedHtml($feed, 3, 'Developer Blog', 'projectnews-label',
array('labelTemplate'=>'Read more about {title}, posted on {timestamp}'));
}
}

/**
Expand Down Expand Up @@ -526,10 +561,6 @@ public function endPage()

$this->outputNewsFeed();

$this->outputBuildsFeed();

$this->outputDevBlogFeed();

?> </div><?php

?> <div id="servers"><?php
Expand Down

0 comments on commit 7af3f01

Please sign in to comment.