Skip to content

Commit

Permalink
Merge pull request #515 from ArthurHoaro/template-feeds
Browse files Browse the repository at this point in the history
Refactor RSS feeds generation, and do it through templates
  • Loading branch information
ArthurHoaro committed Mar 25, 2016
2 parents b276488 + 528a6f8 commit f66a199
Show file tree
Hide file tree
Showing 16 changed files with 859 additions and 339 deletions.
279 changes: 279 additions & 0 deletions application/FeedBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
<?php

/**
* FeedBuilder class.
*
* Used to build ATOM and RSS feeds data.
*/
class FeedBuilder
{
/**
* @var string Constant: RSS feed type.
*/
public static $FEED_RSS = 'rss';

/**
* @var string Constant: ATOM feed type.
*/
public static $FEED_ATOM = 'atom';

/**
* @var string Default language if the locale isn't set.
*/
public static $DEFAULT_LANGUAGE = 'en-en';

/**
* @var int Number of links to display in a feed by default.
*/
public static $DEFAULT_NB_LINKS = 50;

/**
* @var LinkDB instance.
*/
protected $linkDB;

/**
* @var string RSS or ATOM feed.
*/
protected $feedType;

/**
* @var array $_SERVER.
*/
protected $serverInfo;

/**
* @var array $_GET.
*/
protected $userInput;

/**
* @var boolean True if the user is currently logged in, false otherwise.
*/
protected $isLoggedIn;

/**
* @var boolean Use permalinks instead of direct links if true.
*/
protected $usePermalinks;

/**
* @var boolean true to hide dates in feeds.
*/
protected $hideDates;

/**
* @var string PubSub hub URL.
*/
protected $pubsubhubUrl;

/**
* @var string server locale.
*/
protected $locale;

/**
* @var DateTime Latest item date.
*/
protected $latestDate;

/**
* Feed constructor.
*
* @param LinkDB $linkDB LinkDB instance.
* @param string $feedType Type of feed.
* @param array $serverInfo $_SERVER.
* @param array $userInput $_GET.
* @param boolean $isLoggedIn True if the user is currently logged in, false otherwise.
*/
public function __construct($linkDB, $feedType, $serverInfo, $userInput, $isLoggedIn)
{
$this->linkDB = $linkDB;
$this->feedType = $feedType;
$this->serverInfo = $serverInfo;
$this->userInput = $userInput;
$this->isLoggedIn = $isLoggedIn;
}

/**
* Build data for feed templates.
*
* @return array Formatted data for feeds templates.
*/
public function buildData()
{
// Optionally filter the results:
$linksToDisplay = $this->linkDB->filterSearch($this->userInput);

$nblinksToDisplay = $this->getNbLinks(count($linksToDisplay));

// Can't use array_keys() because $link is a LinkDB instance and not a real array.
$keys = array();
foreach ($linksToDisplay as $key => $value) {
$keys[] = $key;
}

$pageaddr = escape(index_url($this->serverInfo));
$linkDisplayed = array();
for ($i = 0; $i < $nblinksToDisplay && $i < count($keys); $i++) {
$linkDisplayed[$keys[$i]] = $this->buildItem($linksToDisplay[$keys[$i]], $pageaddr);
}

$data['language'] = $this->getTypeLanguage();
$data['pubsubhub_url'] = $this->pubsubhubUrl;
$data['last_update'] = $this->getLatestDateFormatted();
$data['show_dates'] = !$this->hideDates || $this->isLoggedIn;
// Remove leading slash from REQUEST_URI.
$data['self_link'] = $pageaddr . escape(ltrim($this->serverInfo['REQUEST_URI'], '/'));
$data['index_url'] = $pageaddr;
$data['usepermalinks'] = $this->usePermalinks === true;
$data['links'] = $linkDisplayed;

return $data;
}

/**
* Build a feed item (one per shaare).
*
* @param array $link Single link array extracted from LinkDB.
* @param string $pageaddr Index URL.
*
* @return array Link array with feed attributes.
*/
protected function buildItem($link, $pageaddr)
{
$link['guid'] = $pageaddr .'?'. smallHash($link['linkdate']);
// Check for both signs of a note: starting with ? and 7 chars long.
if ($link['url'][0] === '?' && strlen($link['url']) === 7) {
$link['url'] = $pageaddr . $link['url'];
}
if ($this->usePermalinks === true) {
$permalink = '<a href="'. $link['url'] .'" title="Direct link">Direct link</a>';
} else {
$permalink = '<a href="'. $link['guid'] .'" title="Permalink">Permalink</a>';
}
$link['description'] = format_description($link['description']) . PHP_EOL .'<br>&#8212; '. $permalink;

$date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']);

if ($this->feedType == self::$FEED_RSS) {
$link['iso_date'] = $date->format(DateTime::RSS);
} else {
$link['iso_date'] = $date->format(DateTime::ATOM);
}

// Save the more recent item.
if (empty($this->latestDate) || $this->latestDate < $date) {
$this->latestDate = $date;
}

$taglist = array_filter(explode(' ', $link['tags']), 'strlen');
uasort($taglist, 'strcasecmp');
$link['taglist'] = $taglist;

return $link;
}

/**
* Assign PubSub hub URL.
*
* @param string $pubsubhubUrl PubSub hub url.
*/
public function setPubsubhubUrl($pubsubhubUrl)
{
$this->pubsubhubUrl = $pubsubhubUrl;
}

/**
* Set this to true to use permalinks instead of direct links.
*
* @param boolean $usePermalinks true to force permalinks.
*/
public function setUsePermalinks($usePermalinks)
{
$this->usePermalinks = $usePermalinks;
}

/**
* Set this to true to hide timestamps in feeds.
*
* @param boolean $hideDates true to enable.
*/
public function setHideDates($hideDates)
{
$this->hideDates = $hideDates;
}

/**
* Set the locale. Used to show feed language.
*
* @param string $locale The locale (eg. 'fr_FR.UTF8').
*/
public function setLocale($locale)
{
$this->locale = strtolower($locale);
}

/**
* Get the language according to the feed type, based on the locale:
*
* - RSS format: en-us (default: 'en-en').
* - ATOM format: fr (default: 'en').
*
* @return string The language.
*/
public function getTypeLanguage()
{
// Use the locale do define the language, if available.
if (! empty($this->locale) && preg_match('/^\w{2}[_\-]\w{2}/', $this->locale)) {
$length = ($this->feedType == self::$FEED_RSS) ? 5 : 2;
return str_replace('_', '-', substr($this->locale, 0, $length));
}
return ($this->feedType == self::$FEED_RSS) ? 'en-en' : 'en';
}

/**
* Format the latest item date found according to the feed type.
*
* Return an empty string if invalid DateTime is passed.
*
* @return string Formatted date.
*/
protected function getLatestDateFormatted()
{
if (empty($this->latestDate) || !$this->latestDate instanceof DateTime) {
return '';
}

$type = ($this->feedType == self::$FEED_RSS) ? DateTime::RSS : DateTime::ATOM;
return $this->latestDate->format($type);
}

/**
* Returns the number of link to display according to 'nb' user input parameter.
*
* If 'nb' not set or invalid, default value: $DEFAULT_NB_LINKS.
* If 'nb' is set to 'all', display all filtered links (max parameter).
*
* @param int $max maximum number of links to display.
*
* @return int number of links to display.
*/
public function getNbLinks($max)
{
if (empty($this->userInput['nb'])) {
return self::$DEFAULT_NB_LINKS;
}

if ($this->userInput['nb'] == 'all') {
return $max;
}

$intNb = intval($this->userInput['nb']);
if (! is_int($intNb) || $intNb == 0) {
return self::$DEFAULT_NB_LINKS;
}

return $intNb;
}
}
64 changes: 59 additions & 5 deletions application/LinkDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -341,17 +341,71 @@ public function getLinkFromUrl($url)
}

/**
* Filter links.
* Returns the shaare corresponding to a smallHash.
*
* @param string $type Type of filter.
* @param mixed $request Search request, string or array.
* @param string $request QUERY_STRING server parameter.
*
* @return array $filtered array containing permalink data.
*
* @throws LinkNotFoundException if the smallhash is malformed or doesn't match any link.
*/
public function filterHash($request)
{
$request = substr($request, 0, 6);
$linkFilter = new LinkFilter($this->_links);
return $linkFilter->filter(LinkFilter::$FILTER_HASH, $request);
}

/**
* Returns the list of articles for a given day.
*
* @param string $request day to filter. Format: YYYYMMDD.
*
* @return array list of shaare found.
*/
public function filterDay($request) {
$linkFilter = new LinkFilter($this->_links);
return $linkFilter->filter(LinkFilter::$FILTER_DAY, $request);
}

/**
* Filter links according to search parameters.
*
* @param array $filterRequest Search request content. Supported keys:
* - searchtags: list of tags
* - searchterm: term search
* @param bool $casesensitive Optional: Perform case sensitive filter
* @param bool $privateonly Optional: Returns private links only if true.
*
* @return array filtered links
* @return array filtered links, all links if no suitable filter was provided.
*/
public function filter($type = '', $request = '', $casesensitive = false, $privateonly = false)
public function filterSearch($filterRequest = array(), $casesensitive = false, $privateonly = false)
{
// Filter link database according to parameters.
$searchtags = !empty($filterRequest['searchtags']) ? escape($filterRequest['searchtags']) : '';
$searchterm = !empty($filterRequest['searchterm']) ? escape($filterRequest['searchterm']) : '';

// Search tags + fullsearch.
if (empty($type) && ! empty($searchtags) && ! empty($searchterm)) {
$type = LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT;
$request = array($searchtags, $searchterm);
}
// Search by tags.
elseif (! empty($searchtags)) {
$type = LinkFilter::$FILTER_TAG;
$request = $searchtags;
}
// Fulltext search.
elseif (! empty($searchterm)) {
$type = LinkFilter::$FILTER_TEXT;
$request = $searchterm;
}
// Otherwise, display without filtering.
else {
$type = '';
$request = '';
}

$linkFilter = new LinkFilter($this->_links);
return $linkFilter->filter($type, $request, $casesensitive, $privateonly);
}
Expand Down
14 changes: 13 additions & 1 deletion application/LinkFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public function __construct($links)
* Filter links according to parameters.
*
* @param string $type Type of filter (eg. tags, permalink, etc.).
* @param string $request Filter content.
* @param mixed $request Filter content.
* @param bool $casesensitive Optional: Perform case sensitive filter if true.
* @param bool $privateonly Optional: Only returns private links if true.
*
Expand Down Expand Up @@ -110,6 +110,8 @@ private function noFilter($privateonly = false)
* @param string $smallHash permalink hash.
*
* @return array $filtered array containing permalink data.
*
* @throws LinkNotFoundException if the smallhash doesn't match any link.
*/
private function filterSmallHash($smallHash)
{
Expand All @@ -121,6 +123,11 @@ private function filterSmallHash($smallHash)
return $filtered;
}
}

if (empty($filtered)) {
throw new LinkNotFoundException();
}

return $filtered;
}

Expand Down Expand Up @@ -318,3 +325,8 @@ public static function tagsStrToArray($tags, $casesensitive)
return array_filter(explode(' ', trim($tagsOut)), 'strlen');
}
}

class LinkNotFoundException extends Exception
{
protected $message = 'The link you are trying to reach does not exist or has been deleted.';
}
Loading

0 comments on commit f66a199

Please sign in to comment.