Make FeedBuilder instance creation independant of the request stack

This commit is contained in:
ArthurHoaro 2020-05-18 13:03:13 +02:00
parent c56a540c6e
commit f4929b1188
3 changed files with 87 additions and 129 deletions

View file

@ -43,21 +43,9 @@ class FeedBuilder
*/ */
protected $formatter; protected $formatter;
/** /** @var mixed[] $_SERVER */
* @var string RSS or ATOM feed.
*/
protected $feedType;
/**
* @var array $_SERVER
*/
protected $serverInfo; protected $serverInfo;
/**
* @var array $_GET
*/
protected $userInput;
/** /**
* @var boolean True if the user is currently logged in, false otherwise. * @var boolean True if the user is currently logged in, false otherwise.
*/ */
@ -77,7 +65,6 @@ class FeedBuilder
* @var string server locale. * @var string server locale.
*/ */
protected $locale; protected $locale;
/** /**
* @var DateTime Latest item date. * @var DateTime Latest item date.
*/ */
@ -88,37 +75,36 @@ class FeedBuilder
* *
* @param BookmarkServiceInterface $linkDB LinkDB instance. * @param BookmarkServiceInterface $linkDB LinkDB instance.
* @param BookmarkFormatter $formatter instance. * @param BookmarkFormatter $formatter instance.
* @param string $feedType Type of feed.
* @param array $serverInfo $_SERVER. * @param array $serverInfo $_SERVER.
* @param array $userInput $_GET.
* @param boolean $isLoggedIn True if the user is currently logged in, false otherwise. * @param boolean $isLoggedIn True if the user is currently logged in, false otherwise.
*/ */
public function __construct($linkDB, $formatter, $feedType, $serverInfo, $userInput, $isLoggedIn) public function __construct($linkDB, $formatter, array $serverInfo, $isLoggedIn)
{ {
$this->linkDB = $linkDB; $this->linkDB = $linkDB;
$this->formatter = $formatter; $this->formatter = $formatter;
$this->feedType = $feedType;
$this->serverInfo = $serverInfo; $this->serverInfo = $serverInfo;
$this->userInput = $userInput;
$this->isLoggedIn = $isLoggedIn; $this->isLoggedIn = $isLoggedIn;
} }
/** /**
* Build data for feed templates. * Build data for feed templates.
* *
* @param string $feedType Type of feed (RSS/ATOM).
* @param array $userInput $_GET.
*
* @return array Formatted data for feeds templates. * @return array Formatted data for feeds templates.
*/ */
public function buildData() public function buildData(string $feedType, ?array $userInput)
{ {
// Search for untagged bookmarks // Search for untagged bookmarks
if (isset($this->userInput['searchtags']) && empty($this->userInput['searchtags'])) { if (isset($this->userInput['searchtags']) && empty($userInput['searchtags'])) {
$this->userInput['searchtags'] = false; $userInput['searchtags'] = false;
} }
// Optionally filter the results: // Optionally filter the results:
$linksToDisplay = $this->linkDB->search($this->userInput); $linksToDisplay = $this->linkDB->search($userInput);
$nblinksToDisplay = $this->getNbLinks(count($linksToDisplay)); $nblinksToDisplay = $this->getNbLinks(count($linksToDisplay), $userInput);
// Can't use array_keys() because $link is a LinkDB instance and not a real array. // Can't use array_keys() because $link is a LinkDB instance and not a real array.
$keys = array(); $keys = array();
@ -130,11 +116,11 @@ class FeedBuilder
$this->formatter->addContextData('index_url', $pageaddr); $this->formatter->addContextData('index_url', $pageaddr);
$linkDisplayed = array(); $linkDisplayed = array();
for ($i = 0; $i < $nblinksToDisplay && $i < count($keys); $i++) { for ($i = 0; $i < $nblinksToDisplay && $i < count($keys); $i++) {
$linkDisplayed[$keys[$i]] = $this->buildItem($linksToDisplay[$keys[$i]], $pageaddr); $linkDisplayed[$keys[$i]] = $this->buildItem($feedType, $linksToDisplay[$keys[$i]], $pageaddr);
} }
$data['language'] = $this->getTypeLanguage(); $data['language'] = $this->getTypeLanguage($feedType);
$data['last_update'] = $this->getLatestDateFormatted(); $data['last_update'] = $this->getLatestDateFormatted($feedType);
$data['show_dates'] = !$this->hideDates || $this->isLoggedIn; $data['show_dates'] = !$this->hideDates || $this->isLoggedIn;
// Remove leading slash from REQUEST_URI. // Remove leading slash from REQUEST_URI.
$data['self_link'] = escape(server_url($this->serverInfo)) $data['self_link'] = escape(server_url($this->serverInfo))
@ -146,45 +132,6 @@ class FeedBuilder
return $data; return $data;
} }
/**
* Build a feed item (one per shaare).
*
* @param Bookmark $link Single link array extracted from LinkDB.
* @param string $pageaddr Index URL.
*
* @return array Link array with feed attributes.
*/
protected function buildItem($link, $pageaddr)
{
$data = $this->formatter->format($link);
$data['guid'] = $pageaddr . '?' . $data['shorturl'];
if ($this->usePermalinks === true) {
$permalink = '<a href="'. $data['url'] .'" title="'. t('Direct link') .'">'. t('Direct link') .'</a>';
} else {
$permalink = '<a href="'. $data['guid'] .'" title="'. t('Permalink') .'">'. t('Permalink') .'</a>';
}
$data['description'] .= PHP_EOL . PHP_EOL . '<br>&#8212; ' . $permalink;
$data['pub_iso_date'] = $this->getIsoDate($data['created']);
// atom:entry elements MUST contain exactly one atom:updated element.
if (!empty($link->getUpdated())) {
$data['up_iso_date'] = $this->getIsoDate($data['updated'], DateTime::ATOM);
} else {
$data['up_iso_date'] = $this->getIsoDate($data['created'], DateTime::ATOM);
}
// Save the more recent item.
if (empty($this->latestDate) || $this->latestDate < $data['created']) {
$this->latestDate = $data['created'];
}
if (!empty($data['updated']) && $this->latestDate < $data['updated']) {
$this->latestDate = $data['updated'];
}
return $data;
}
/** /**
* Set this to true to use permalinks instead of direct bookmarks. * Set this to true to use permalinks instead of direct bookmarks.
* *
@ -215,22 +162,64 @@ class FeedBuilder
$this->locale = strtolower($locale); $this->locale = strtolower($locale);
} }
/**
* Build a feed item (one per shaare).
*
* @param string $feedType Type of feed (RSS/ATOM).
* @param Bookmark $link Single link array extracted from LinkDB.
* @param string $pageaddr Index URL.
*
* @return array Link array with feed attributes.
*/
protected function buildItem(string $feedType, $link, $pageaddr)
{
$data = $this->formatter->format($link);
$data['guid'] = $pageaddr . '?' . $data['shorturl'];
if ($this->usePermalinks === true) {
$permalink = '<a href="'. $data['url'] .'" title="'. t('Direct link') .'">'. t('Direct link') .'</a>';
} else {
$permalink = '<a href="'. $data['guid'] .'" title="'. t('Permalink') .'">'. t('Permalink') .'</a>';
}
$data['description'] .= PHP_EOL . PHP_EOL . '<br>&#8212; ' . $permalink;
$data['pub_iso_date'] = $this->getIsoDate($feedType, $data['created']);
// atom:entry elements MUST contain exactly one atom:updated element.
if (!empty($link->getUpdated())) {
$data['up_iso_date'] = $this->getIsoDate($feedType, $data['updated'], DateTime::ATOM);
} else {
$data['up_iso_date'] = $this->getIsoDate($feedType, $data['created'], DateTime::ATOM);
}
// Save the more recent item.
if (empty($this->latestDate) || $this->latestDate < $data['created']) {
$this->latestDate = $data['created'];
}
if (!empty($data['updated']) && $this->latestDate < $data['updated']) {
$this->latestDate = $data['updated'];
}
return $data;
}
/** /**
* Get the language according to the feed type, based on the locale: * Get the language according to the feed type, based on the locale:
* *
* - RSS format: en-us (default: 'en-en'). * - RSS format: en-us (default: 'en-en').
* - ATOM format: fr (default: 'en'). * - ATOM format: fr (default: 'en').
* *
* @param string $feedType Type of feed (RSS/ATOM).
*
* @return string The language. * @return string The language.
*/ */
public function getTypeLanguage() protected function getTypeLanguage(string $feedType)
{ {
// Use the locale do define the language, if available. // Use the locale do define the language, if available.
if (!empty($this->locale) && preg_match('/^\w{2}[_\-]\w{2}/', $this->locale)) { if (!empty($this->locale) && preg_match('/^\w{2}[_\-]\w{2}/', $this->locale)) {
$length = ($this->feedType === self::$FEED_RSS) ? 5 : 2; $length = ($feedType === self::$FEED_RSS) ? 5 : 2;
return str_replace('_', '-', substr($this->locale, 0, $length)); return str_replace('_', '-', substr($this->locale, 0, $length));
} }
return ($this->feedType === self::$FEED_RSS) ? 'en-en' : 'en'; return ($feedType === self::$FEED_RSS) ? 'en-en' : 'en';
} }
/** /**
@ -238,32 +227,35 @@ class FeedBuilder
* *
* Return an empty string if invalid DateTime is passed. * Return an empty string if invalid DateTime is passed.
* *
* @param string $feedType Type of feed (RSS/ATOM).
*
* @return string Formatted date. * @return string Formatted date.
*/ */
protected function getLatestDateFormatted() protected function getLatestDateFormatted(string $feedType)
{ {
if (empty($this->latestDate) || !$this->latestDate instanceof DateTime) { if (empty($this->latestDate) || !$this->latestDate instanceof DateTime) {
return ''; return '';
} }
$type = ($this->feedType == self::$FEED_RSS) ? DateTime::RSS : DateTime::ATOM; $type = ($feedType == self::$FEED_RSS) ? DateTime::RSS : DateTime::ATOM;
return $this->latestDate->format($type); return $this->latestDate->format($type);
} }
/** /**
* Get ISO date from DateTime according to feed type. * Get ISO date from DateTime according to feed type.
* *
* @param string $feedType Type of feed (RSS/ATOM).
* @param DateTime $date Date to format. * @param DateTime $date Date to format.
* @param string|bool $format Force format. * @param string|bool $format Force format.
* *
* @return string Formatted date. * @return string Formatted date.
*/ */
protected function getIsoDate(DateTime $date, $format = false) protected function getIsoDate(string $feedType, DateTime $date, $format = false)
{ {
if ($format !== false) { if ($format !== false) {
return $date->format($format); return $date->format($format);
} }
if ($this->feedType == self::$FEED_RSS) { if ($feedType == self::$FEED_RSS) {
return $date->format(DateTime::RSS); return $date->format(DateTime::RSS);
} }
return $date->format(DateTime::ATOM); return $date->format(DateTime::ATOM);
@ -275,21 +267,22 @@ class FeedBuilder
* If 'nb' not set or invalid, default value: $DEFAULT_NB_LINKS. * If 'nb' not set or invalid, default value: $DEFAULT_NB_LINKS.
* If 'nb' is set to 'all', display all filtered bookmarks (max parameter). * If 'nb' is set to 'all', display all filtered bookmarks (max parameter).
* *
* @param int $max maximum number of bookmarks to display. * @param int $max maximum number of bookmarks to display.
* @param array $userInput $_GET.
* *
* @return int number of bookmarks to display. * @return int number of bookmarks to display.
*/ */
public function getNbLinks($max) protected function getNbLinks($max, ?array $userInput)
{ {
if (empty($this->userInput['nb'])) { if (empty($userInput['nb'])) {
return self::$DEFAULT_NB_LINKS; return self::$DEFAULT_NB_LINKS;
} }
if ($this->userInput['nb'] == 'all') { if ($userInput['nb'] == 'all') {
return $max; return $max;
} }
$intNb = intval($this->userInput['nb']); $intNb = intval($userInput['nb']);
if (!is_int($intNb) || $intNb == 0) { if (!is_int($intNb) || $intNb == 0) {
return self::$DEFAULT_NB_LINKS; return self::$DEFAULT_NB_LINKS;
} }

View file

@ -452,15 +452,13 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM
$feedGenerator = new FeedBuilder( $feedGenerator = new FeedBuilder(
$bookmarkService, $bookmarkService,
$factory->getFormatter(), $factory->getFormatter(),
$feedType,
$_SERVER, $_SERVER,
$_GET,
$loginManager->isLoggedIn() $loginManager->isLoggedIn()
); );
$feedGenerator->setLocale(strtolower(setlocale(LC_COLLATE, 0))); $feedGenerator->setLocale(strtolower(setlocale(LC_COLLATE, 0)));
$feedGenerator->setHideDates($conf->get('privacy.hide_timestamps') && !$loginManager->isLoggedIn()); $feedGenerator->setHideDates($conf->get('privacy.hide_timestamps') && !$loginManager->isLoggedIn());
$feedGenerator->setUsePermalinks(isset($_GET['permalinks']) || !$conf->get('feed.rss_permalinks')); $feedGenerator->setUsePermalinks(isset($_GET['permalinks']) || !$conf->get('feed.rss_permalinks'));
$data = $feedGenerator->buildData(); $data = $feedGenerator->buildData($feedType, $_GET);
// Process plugin hook. // Process plugin hook.
$pluginManager->executeHooks('render_feed', $data, array( $pluginManager->executeHooks('render_feed', $data, array(

View file

@ -64,23 +64,6 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
); );
} }
/**
* Test GetTypeLanguage().
*/
public function testGetTypeLanguage()
{
$feedBuilder = new FeedBuilder(null, self::$formatter, FeedBuilder::$FEED_ATOM, null, null, false);
$feedBuilder->setLocale(self::$LOCALE);
$this->assertEquals(self::$ATOM_LANGUAGUE, $feedBuilder->getTypeLanguage());
$feedBuilder = new FeedBuilder(null, self::$formatter, FeedBuilder::$FEED_RSS, null, null, false);
$feedBuilder->setLocale(self::$LOCALE);
$this->assertEquals(self::$RSS_LANGUAGE, $feedBuilder->getTypeLanguage());
$feedBuilder = new FeedBuilder(null, self::$formatter, FeedBuilder::$FEED_ATOM, null, null, false);
$this->assertEquals('en', $feedBuilder->getTypeLanguage());
$feedBuilder = new FeedBuilder(null, self::$formatter, FeedBuilder::$FEED_RSS, null, null, false);
$this->assertEquals('en-en', $feedBuilder->getTypeLanguage());
}
/** /**
* Test buildData with RSS feed. * Test buildData with RSS feed.
*/ */
@ -89,13 +72,11 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
$feedBuilder = new FeedBuilder( $feedBuilder = new FeedBuilder(
self::$bookmarkService, self::$bookmarkService,
self::$formatter, self::$formatter,
FeedBuilder::$FEED_RSS, static::$serverInfo,
self::$serverInfo,
null,
false false
); );
$feedBuilder->setLocale(self::$LOCALE); $feedBuilder->setLocale(self::$LOCALE);
$data = $feedBuilder->buildData(); $data = $feedBuilder->buildData(FeedBuilder::$FEED_RSS, null);
// Test headers (RSS) // Test headers (RSS)
$this->assertEquals(self::$RSS_LANGUAGE, $data['language']); $this->assertEquals(self::$RSS_LANGUAGE, $data['language']);
$this->assertRegExp('/Wed, 03 Aug 2016 09:30:33 \+\d{4}/', $data['last_update']); $this->assertRegExp('/Wed, 03 Aug 2016 09:30:33 \+\d{4}/', $data['last_update']);
@ -140,13 +121,11 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
$feedBuilder = new FeedBuilder( $feedBuilder = new FeedBuilder(
self::$bookmarkService, self::$bookmarkService,
self::$formatter, self::$formatter,
FeedBuilder::$FEED_ATOM, static::$serverInfo,
self::$serverInfo,
null,
false false
); );
$feedBuilder->setLocale(self::$LOCALE); $feedBuilder->setLocale(self::$LOCALE);
$data = $feedBuilder->buildData(); $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
$this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
$this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['last_update']); $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['last_update']);
$link = $data['links'][array_keys($data['links'])[2]]; $link = $data['links'][array_keys($data['links'])[2]];
@ -166,13 +145,11 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
$feedBuilder = new FeedBuilder( $feedBuilder = new FeedBuilder(
self::$bookmarkService, self::$bookmarkService,
self::$formatter, self::$formatter,
FeedBuilder::$FEED_ATOM, static::$serverInfo,
self::$serverInfo,
$criteria,
false false
); );
$feedBuilder->setLocale(self::$LOCALE); $feedBuilder->setLocale(self::$LOCALE);
$data = $feedBuilder->buildData(); $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, $criteria);
$this->assertEquals(1, count($data['links'])); $this->assertEquals(1, count($data['links']));
$link = array_shift($data['links']); $link = array_shift($data['links']);
$this->assertEquals(41, $link['id']); $this->assertEquals(41, $link['id']);
@ -190,13 +167,11 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
$feedBuilder = new FeedBuilder( $feedBuilder = new FeedBuilder(
self::$bookmarkService, self::$bookmarkService,
self::$formatter, self::$formatter,
FeedBuilder::$FEED_ATOM, static::$serverInfo,
self::$serverInfo,
$criteria,
false false
); );
$feedBuilder->setLocale(self::$LOCALE); $feedBuilder->setLocale(self::$LOCALE);
$data = $feedBuilder->buildData(); $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, $criteria);
$this->assertEquals(3, count($data['links'])); $this->assertEquals(3, count($data['links']));
$link = $data['links'][array_keys($data['links'])[2]]; $link = $data['links'][array_keys($data['links'])[2]];
$this->assertEquals(41, $link['id']); $this->assertEquals(41, $link['id']);
@ -211,14 +186,12 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
$feedBuilder = new FeedBuilder( $feedBuilder = new FeedBuilder(
self::$bookmarkService, self::$bookmarkService,
self::$formatter, self::$formatter,
FeedBuilder::$FEED_ATOM, static::$serverInfo,
self::$serverInfo,
null,
false false
); );
$feedBuilder->setLocale(self::$LOCALE); $feedBuilder->setLocale(self::$LOCALE);
$feedBuilder->setUsePermalinks(true); $feedBuilder->setUsePermalinks(true);
$data = $feedBuilder->buildData(); $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
$this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
$this->assertTrue($data['usepermalinks']); $this->assertTrue($data['usepermalinks']);
// First link is a permalink // First link is a permalink
@ -247,14 +220,12 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
$feedBuilder = new FeedBuilder( $feedBuilder = new FeedBuilder(
self::$bookmarkService, self::$bookmarkService,
self::$formatter, self::$formatter,
FeedBuilder::$FEED_ATOM, static::$serverInfo,
self::$serverInfo,
null,
false false
); );
$feedBuilder->setLocale(self::$LOCALE); $feedBuilder->setLocale(self::$LOCALE);
$feedBuilder->setHideDates(true); $feedBuilder->setHideDates(true);
$data = $feedBuilder->buildData(); $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
$this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
$this->assertFalse($data['show_dates']); $this->assertFalse($data['show_dates']);
@ -262,14 +233,12 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
$feedBuilder = new FeedBuilder( $feedBuilder = new FeedBuilder(
self::$bookmarkService, self::$bookmarkService,
self::$formatter, self::$formatter,
FeedBuilder::$FEED_ATOM, static::$serverInfo,
self::$serverInfo,
null,
true true
); );
$feedBuilder->setLocale(self::$LOCALE); $feedBuilder->setLocale(self::$LOCALE);
$feedBuilder->setHideDates(true); $feedBuilder->setHideDates(true);
$data = $feedBuilder->buildData(); $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
$this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
$this->assertTrue($data['show_dates']); $this->assertTrue($data['show_dates']);
} }
@ -289,13 +258,11 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
$feedBuilder = new FeedBuilder( $feedBuilder = new FeedBuilder(
self::$bookmarkService, self::$bookmarkService,
self::$formatter, self::$formatter,
FeedBuilder::$FEED_ATOM,
$serverInfo, $serverInfo,
null,
false false
); );
$feedBuilder->setLocale(self::$LOCALE); $feedBuilder->setLocale(self::$LOCALE);
$data = $feedBuilder->buildData(); $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
$this->assertEquals( $this->assertEquals(
'http://host.tld:8080/~user/shaarli/index.php?do=feed', 'http://host.tld:8080/~user/shaarli/index.php?do=feed',