From 427b41f892c2f69c9747907f420c92f4651994fd Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Sun, 17 Apr 2016 19:34:54 -0400 Subject: [PATCH] Upgrade to PicoFeed v0.1.23 - OPML import/export with categories - New Feed export (bookmarks) --- composer.json | 2 +- controllers/bookmark.php | 47 ++-- controllers/common.php | 3 - controllers/config.php | 21 +- controllers/console.php | 2 - controllers/feed.php | 27 +-- controllers/history.php | 5 +- controllers/item.php | 22 +- controllers/user.php | 3 - models/feed.php | 69 ++++-- models/group.php | 18 +- models/proxy.php | 4 +- vendor/autoload.php | 2 +- vendor/composer/autoload_classmap.php | 18 +- vendor/composer/autoload_real.php | 10 +- vendor/composer/installed.json | 12 +- .../picofeed/lib/PicoFeed/Client/Curl.php | 20 +- .../picofeed/lib/PicoFeed/Parser/Atom.php | 48 ++-- .../picofeed/lib/PicoFeed/Parser/Feed.php | 130 ++++++++++- .../picofeed/lib/PicoFeed/Parser/Item.php | 158 ++++++++++++- .../picofeed/lib/PicoFeed/Parser/Parser.php | 8 +- .../picofeed/lib/PicoFeed/Parser/Rss10.php | 63 ++--- .../picofeed/lib/PicoFeed/Parser/Rss20.php | 76 +++---- .../lib/PicoFeed/Parser/XmlParser.php | 39 ++-- .../lib/PicoFeed/Rules/www.sciencemag.org.php | 2 +- .../lib/PicoFeed/Serialization/Export.php | 122 ---------- .../lib/PicoFeed/Serialization/Import.php | 162 ------------- .../PicoFeed/Serialization/Subscription.php | 175 ++++++++++++++ .../Serialization/SubscriptionList.php | 75 ++++++ .../Serialization/SubscriptionListBuilder.php | 204 +++++++++++++++++ .../Serialization/SubscriptionListParser.php | 100 ++++++++ .../Serialization/SubscriptionParser.php | 142 ++++++++++++ .../lib/PicoFeed/Syndication/Atom.php | 215 ------------------ .../PicoFeed/Syndication/AtomFeedBuilder.php | 65 ++++++ .../lib/PicoFeed/Syndication/AtomHelper.php | 139 +++++++++++ .../PicoFeed/Syndication/AtomItemBuilder.php | 63 +++++ .../lib/PicoFeed/Syndication/FeedBuilder.php | 185 +++++++++++++++ .../lib/PicoFeed/Syndication/ItemBuilder.php | 209 +++++++++++++++++ .../lib/PicoFeed/Syndication/Rss20.php | 206 ----------------- .../PicoFeed/Syndication/Rss20FeedBuilder.php | 76 +++++++ .../lib/PicoFeed/Syndication/Rss20Helper.php | 115 ++++++++++ .../PicoFeed/Syndication/Rss20ItemBuilder.php | 67 ++++++ .../lib/PicoFeed/Syndication/Writer.php | 95 -------- 43 files changed, 2153 insertions(+), 1071 deletions(-) delete mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Export.php delete mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Import.php create mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Subscription.php create mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php create mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php create mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php create mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php delete mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Atom.php create mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php create mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomHelper.php create mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php create mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php create mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php delete mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20.php create mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php create mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php create mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php delete mode 100644 vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Writer.php diff --git a/composer.json b/composer.json index 36c5875..26e2ac8 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ "fguillot/simple-validator": "v1.0.0", "fguillot/json-rpc": "v1.0.2", "fguillot/picodb": "v1.0.2", - "fguillot/picofeed": "v0.1.21" + "fguillot/picofeed": "v0.1.23" }, "require-dev": { "phpunit/phpunit": "4.8.3", diff --git a/controllers/bookmark.php b/controllers/bookmark.php index 50558df..b54fa33 100644 --- a/controllers/bookmark.php +++ b/controllers/bookmark.php @@ -1,10 +1,10 @@ title = t('Bookmarks').' - Miniflux'; - $writer->site_url = Helper\get_current_base_url(); - $writer->feed_url = $writer->site_url.'?action=bookmark-feed&token='.urlencode($feed_token); - $bookmarks = Model\Item\get_bookmarks(); + $feedBuilder = AtomFeedBuilder::create() + ->withTitle(t('Bookmarks').' - Miniflux') + ->withFeedUrl(Helper\get_current_base_url().'?action=bookmark-feed&token='.urlencode($feed_token)) + ->withSiteUrl(Helper\get_current_base_url()) + ->withDate(new DateTime()) + ; + foreach ($bookmarks as $bookmark) { - $article = Model\Item\get($bookmark['id']); + $articleDate = new DateTime(); + $articleDate->setTimestamp($article['updated']); - $writer->items[] = array( - 'id' => $article['id'], - 'title' => $article['title'], - 'updated' => $article['updated'], - 'url' => $article['url'], - 'content' => $article['content'], - ); + $feedBuilder + ->withItem(AtomItemBuilder::create($feedBuilder) + ->withId($article['id']) + ->withTitle($article['title']) + ->withUrl($article['url']) + ->withUpdatedDate($articleDate) + ->withPublishedDate($articleDate) + ->withContent($article['content']) + ); } - Response\xml($writer->execute()); + Response\xml($feedBuilder->build()); }); diff --git a/controllers/common.php b/controllers/common.php index 06595f4..f77db2e 100644 --- a/controllers/common.php +++ b/controllers/common.php @@ -2,7 +2,6 @@ // Called before each action Router\before(function($action) { - Session\open(BASE_URL_DIRECTORY, SESSION_SAVE_PATH, 0); // Select the requested database either from post param database or from the @@ -58,13 +57,11 @@ Router\before(function($action) { // Show help Router\get_action('show-help', function() { - Response\html(Template\load('show_help')); }); // Show the menu for the mobile view Router\get_action('more', function() { - Response\html(Template\layout('show_more', array('menu' => 'more'))); }); diff --git a/controllers/config.php b/controllers/config.php index 35848b2..e6ce984 100644 --- a/controllers/config.php +++ b/controllers/config.php @@ -4,9 +4,7 @@ use PicoDb\Database; // Display a form to add a new database Router\get_action('new-db', function() { - if (ENABLE_MULTIPLE_DB) { - Response\html(Template\layout('new_db', array( 'errors' => array(), 'values' => array( @@ -23,9 +21,7 @@ Router\get_action('new-db', function() { // Create a new database Router\post_action('new-db', function() { - if (ENABLE_MULTIPLE_DB) { - $values = Request\values(); Model\Config\check_csrf_values($values); list($valid, $errors) = Model\Database\validate($values); @@ -56,7 +52,6 @@ Router\post_action('new-db', function() { // Confirmation box before auto-update Router\get_action('confirm-auto-update', function() { - Response\html(Template\layout('confirm_auto_update', array( 'nb_unread_items' => Model\Item\count_by_status('unread'), 'menu' => 'config', @@ -66,13 +61,10 @@ Router\get_action('confirm-auto-update', function() { // Auto-update Router\get_action('auto-update', function() { - if (ENABLE_AUTO_UPDATE) { - if (Model\AutoUpdate\execute(Model\Config\get('auto_update_url'))) { Session\flash(t('Miniflux is updated!')); - } - else { + } else { Session\flash_error(t('Unable to update Miniflux, check the console for errors.')); } } @@ -82,7 +74,6 @@ Router\get_action('auto-update', function() { // Re-generate tokens Router\get_action('generate-tokens', function() { - if (Model\Config\check_csrf(Request\param('csrf'))) { Model\Config\new_tokens(); } @@ -92,7 +83,6 @@ Router\get_action('generate-tokens', function() { // Optimize the database manually Router\get_action('optimize-db', function() { - if (Model\Config\check_csrf(Request\param('csrf'))) { Database::getInstance('db')->getConnection()->exec('VACUUM'); } @@ -102,7 +92,6 @@ Router\get_action('optimize-db', function() { // Download the compressed database Router\get_action('download-db', function() { - if (Model\Config\check_csrf(Request\param('csrf'))) { Response\force_download('db.sqlite.gz'); Response\binary(gzencode(file_get_contents(Model\Database\get_path()))); @@ -111,7 +100,6 @@ Router\get_action('download-db', function() { // Display preferences page Router\get_action('config', function() { - Response\html(Template\layout('config', array( 'errors' => array(), 'values' => Model\Config\get_all() + array('csrf' => Model\Config\generate_csrf()), @@ -133,7 +121,6 @@ Router\get_action('config', function() { // Update preferences Router\post_action('config', function() { - $values = Request\values() + array('nocontent' => 0, 'image_proxy' => 0, 'favicons' => 0, 'debug_mode' => 0, 'original_marks_read' => 0); Model\Config\check_csrf_values($values); list($valid, $errors) = Model\Config\validate_modification($values); @@ -188,7 +175,6 @@ Router\post_action('get-config', function() { // Display help page Router\get_action('help', function() { - Response\html(Template\layout('help', array( 'config' => Model\Config\get_all(), 'nb_unread_items' => Model\Item\count_by_status('unread'), @@ -199,7 +185,6 @@ Router\get_action('help', function() { // Display about page Router\get_action('about', function() { - Response\html(Template\layout('about', array( 'csrf' => Model\Config\generate_csrf(), 'config' => Model\Config\get_all(), @@ -212,7 +197,6 @@ Router\get_action('about', function() { // Display database page Router\get_action('database', function() { - Response\html(Template\layout('database', array( 'csrf' => Model\Config\generate_csrf(), 'config' => Model\Config\get_all(), @@ -225,7 +209,6 @@ Router\get_action('database', function() { // Display API page Router\get_action('api', function() { - Response\html(Template\layout('api', array( 'config' => Model\Config\get_all(), 'nb_unread_items' => Model\Item\count_by_status('unread'), @@ -236,7 +219,6 @@ Router\get_action('api', function() { // Display bookmark services page Router\get_action('services', function() { - Response\html(Template\layout('services', array( 'errors' => array(), 'values' => Model\Config\get_all() + array('csrf' => Model\Config\generate_csrf()), @@ -247,7 +229,6 @@ Router\get_action('services', function() { // Update bookmark services Router\post_action('services', function() { - $values = Request\values() + array('pinboard_enabled' => 0, 'instapaper_enabled' => 0); Model\Config\check_csrf_values($values); diff --git a/controllers/console.php b/controllers/console.php index c6e4929..74bbe25 100644 --- a/controllers/console.php +++ b/controllers/console.php @@ -2,14 +2,12 @@ // Flush console messages Router\get_action('flush-console', function() { - @unlink(DEBUG_FILENAME); Response\redirect('?action=console'); }); // Display console Router\get_action('console', function() { - Response\html(Template\layout('console', array( 'content' => @file_get_contents(DEBUG_FILENAME), 'nb_unread_items' => Model\Item\count_by_status('unread'), diff --git a/controllers/feed.php b/controllers/feed.php index fef46c2..1bfcf62 100644 --- a/controllers/feed.php +++ b/controllers/feed.php @@ -1,8 +1,9 @@ 0, @@ -65,7 +64,6 @@ Router\post_action('edit-feed', function() { // Confirmation box to remove a feed Router\get_action('confirm-remove-feed', function() { - $id = Request\int_param('feed_id'); Response\html(Template\layout('confirm_remove_feed', array( @@ -78,7 +76,6 @@ Router\get_action('confirm-remove-feed', function() { // Remove a feed Router\get_action('remove-feed', function() { - $id = Request\int_param('feed_id'); if ($id && Model\Feed\remove($id)) { @@ -93,7 +90,6 @@ Router\get_action('remove-feed', function() { // Refresh one feed and redirect to unread items Router\get_action('refresh-feed', function() { - $feed_id = Request\int_param('feed_id'); $redirect = Request\param('redirect', 'unread'); @@ -103,7 +99,6 @@ Router\get_action('refresh-feed', function() { // Ajax call to refresh one feed Router\post_action('refresh-feed', function() { - $feed_id = Request\int_param('feed_id', 0); Response\json(array( @@ -136,7 +131,6 @@ Router\get_action('feeds', function() { // Display form to add one feed Router\get_action('add', function() { - $values = array( 'download_content' => 0, 'rtl' => 0, @@ -157,13 +151,11 @@ Router\get_action('add', function() { // Add a feed with the form or directly from the url, it can be used by a bookmarklet by example Router\action('subscribe', function() { - if (Request\is_post()) { $values = Request\values(); Model\Config\check_csrf_values($values); $url = isset($values['url']) ? $values['url'] : ''; - } - else { + } else { $values = array(); $url = Request\param('url'); $token = Request\param('token'); @@ -247,14 +239,12 @@ Router\action('subscribe', function() { // OPML export Router\get_action('export', function() { - Response\force_download('feeds.opml'); Response\xml(Model\Feed\export_opml()); }); // OPML import form Router\get_action('import', function() { - Response\html(Template\layout('import', array( 'errors' => array(), 'nb_unread_items' => Model\Item\count_by_status('unread'), @@ -265,15 +255,12 @@ Router\get_action('import', function() { // OPML importation Router\post_action('import', function() { - - if (Model\Feed\import_opml(Request\file_content('file'))) { - + try { + Model\Feed\import_opml(Request\file_content('file')); Session\flash(t('Your feeds have been imported.')); Response\redirect('?action=feeds'); - } - else { - - Session\flash_error(t('Unable to import your OPML file.')); + } catch (MalformedXmlException $e) { + Session\flash_error(t('Unable to import your OPML file.').' ('.$e->getMessage().')'); Response\redirect('?action=import'); } }); diff --git a/controllers/history.php b/controllers/history.php index 43ce8d1..c7a14d3 100644 --- a/controllers/history.php +++ b/controllers/history.php @@ -2,10 +2,10 @@ // Display history page Router\get_action('history', function() { - $offset = Request\int_param('offset', 0); $group_id = Request\int_param('group_id', null); $feed_ids = array(); + if (! is_null($group_id)) { $feed_ids = Model\Group\get_feeds_by_group($group_id); } @@ -44,6 +44,7 @@ Router\get_action('history', function() { // Confirmation box to flush history Router\get_action('confirm-flush-history', function() { $group_id = Request\int_param('group_id', null); + Response\html(Template\layout('confirm_flush_items', array( 'group_id' => $group_id, 'nb_unread_items' => Model\Item\count_by_status('unread'), @@ -55,10 +56,12 @@ Router\get_action('confirm-flush-history', function() { // Flush history Router\get_action('flush-history', function() { $group_id = Request\int_param('group_id', null); + if (!is_null($group_id)) { Model\Item\mark_group_as_removed($group_id); } else { Model\Item\mark_all_as_removed(); } + Response\redirect('?action=history'); }); diff --git a/controllers/item.php b/controllers/item.php index 0cd3986..aab3cb4 100644 --- a/controllers/item.php +++ b/controllers/item.php @@ -2,7 +2,6 @@ // Display unread items Router\get_action('unread', function() { - Model\Item\autoflush_read(); Model\Item\autoflush_unread(); @@ -54,7 +53,6 @@ Router\get_action('unread', function() { // Show item Router\get_action('show', function() { - $id = Request\param('id'); $menu = Request\param('menu'); $item = Model\Item\get($id); @@ -101,7 +99,6 @@ Router\get_action('show', function() { // Display feed items page Router\get_action('feed-items', function() { - $feed_id = Request\int_param('feed_id', 0); $offset = Request\int_param('offset', 0); $nb_items = Model\Item\count_by_feed($feed_id); @@ -143,28 +140,24 @@ Router\post_action('download-item', function() { // Ajax call to mark item read Router\post_action('mark-item-read', function() { - Model\Item\set_read(Request\param('id')); Response\json(array('Ok')); }); // Ajax call to mark item as removed Router\post_action('mark-item-removed', function() { - Model\Item\set_removed(Request\param('id')); Response\json(array('Ok')); }); // Ajax call to mark item unread Router\post_action('mark-item-unread', function() { - Model\Item\set_unread(Request\param('id')); Response\json(array('Ok')); }); // Mark unread items as read Router\get_action('mark-all-read', function() { - $group_id = Request\int_param('group_id', null); if (!is_null($group_id)) { @@ -179,11 +172,9 @@ Router\get_action('mark-all-read', function() { // Mark all unread items as read for a specific feed Router\get_action('mark-feed-as-read', function() { - $feed_id = Request\int_param('feed_id'); Model\Item\mark_feed_as_read($feed_id); - Response\redirect('?action=feed-items&feed_id='.$feed_id); }); @@ -192,7 +183,6 @@ Router\get_action('mark-feed-as-read', function() { // that where marked read from the frontend, since the number of unread items // on page 2+ is unknown. Router\post_action('mark-feed-as-read', function() { - Model\Item\mark_feed_as_read(Request\int_param('feed_id')); $nb_items = Model\Item\count_by_status('unread'); @@ -201,41 +191,35 @@ Router\post_action('mark-feed-as-read', function() { // Mark item as read and redirect to the listing page Router\get_action('mark-item-read', function() { - $id = Request\param('id'); $redirect = Request\param('redirect', 'unread'); $offset = Request\int_param('offset', 0); $feed_id = Request\int_param('feed_id', 0); Model\Item\set_read($id); - - Response\Redirect('?action='.$redirect.'&offset='.$offset.'&feed_id='.$feed_id.'#item-'.$id); + Response\redirect('?action='.$redirect.'&offset='.$offset.'&feed_id='.$feed_id.'#item-'.$id); }); // Mark item as unread and redirect to the listing page Router\get_action('mark-item-unread', function() { - $id = Request\param('id'); $redirect = Request\param('redirect', 'history'); $offset = Request\int_param('offset', 0); $feed_id = Request\int_param('feed_id', 0); Model\Item\set_unread($id); - - Response\Redirect('?action='.$redirect.'&offset='.$offset.'&feed_id='.$feed_id.'#item-'.$id); + Response\redirect('?action='.$redirect.'&offset='.$offset.'&feed_id='.$feed_id.'#item-'.$id); }); // Mark item as removed and redirect to the listing page Router\get_action('mark-item-removed', function() { - $id = Request\param('id'); $redirect = Request\param('redirect', 'history'); $offset = Request\int_param('offset', 0); $feed_id = Request\int_param('feed_id', 0); Model\Item\set_removed($id); - - Response\Redirect('?action='.$redirect.'&offset='.$offset.'&feed_id='.$feed_id); + Response\redirect('?action='.$redirect.'&offset='.$offset.'&feed_id='.$feed_id); }); Router\post_action('latest-feeds-items', function() { diff --git a/controllers/user.php b/controllers/user.php index ed9ae61..10dcc82 100644 --- a/controllers/user.php +++ b/controllers/user.php @@ -2,14 +2,12 @@ // Logout and destroy session Router\get_action('logout', function() { - Model\User\logout(); Response\redirect('?action=login'); }); // Display form login Router\get_action('login', function() { - if (Model\User\is_loggedin()) { Response\redirect('?action=unread'); } @@ -26,7 +24,6 @@ Router\get_action('login', function() { // Check credentials and redirect to unread items Router\post_action('login', function() { - $values = Request\values(); Model\Config\check_csrf_values($values); list($valid, $errors) = Model\User\validate_login($values); diff --git a/models/feed.php b/models/feed.php index 3e778b2..e2629d2 100644 --- a/models/feed.php +++ b/models/feed.php @@ -2,6 +2,10 @@ namespace Model\Feed; +use PicoFeed\Serialization\Subscription; +use PicoFeed\Serialization\SubscriptionList; +use PicoFeed\Serialization\SubscriptionListBuilder; +use PicoFeed\Serialization\SubscriptionListParser; use UnexpectedValueException; use Model\Config; use Model\Item; @@ -11,11 +15,8 @@ use Helper; use SimpleValidator\Validator; use SimpleValidator\Validators; use PicoDb\Database; -use PicoFeed\Serialization\Export; -use PicoFeed\Serialization\Import; use PicoFeed\Reader\Reader; use PicoFeed\PicoFeedException; -use PicoFeed\Client\InvalidUrlException; const LIMIT_ALL = -1; @@ -53,43 +54,61 @@ function update(array $values) // Export all feeds function export_opml() { - $opml = new Export(get_all()); - return $opml->execute(); + $feeds = get_all(); + $subscriptionList = SubscriptionList::create()->setTitle(t('Subscriptions')); + + foreach ($feeds as $feed) { + $groups = Group\get_feed_groups($feed['id']); + $category = ''; + + if (!empty($groups)) { + $category = $groups[0]['title']; + } + + $subscriptionList->addSubscription(Subscription::create() + ->setTitle($feed['title']) + ->setSiteUrl($feed['site_url']) + ->setFeedUrl($feed['feed_url']) + ->setCategory($category) + ); + } + + return SubscriptionListBuilder::create($subscriptionList)->build(); } // Import OPML file function import_opml($content) { - $import = new Import($content); - $feeds = $import->execute(); + $subscriptionList = SubscriptionListParser::create($content)->parse(); - if ($feeds) { + $db = Database::getInstance('db'); + $db->startTransaction(); - $db = Database::getInstance('db'); - $db->startTransaction(); + foreach ($subscriptionList->subscriptions as $subscription) { + if (! $db->table('feeds')->eq('feed_url', $subscription->getFeedUrl())->exists()) { + $db->table('feeds')->insert(array( + 'title' => $subscription->getTitle(), + 'site_url' => $subscription->getSiteUrl(), + 'feed_url' => $subscription->getFeedUrl(), + )); - foreach ($feeds as $feed) { + if ($subscription->getCategory() !== '') { + $feed_id = $db->getLastId(); + $group_id = Group\get_group_id($subscription->getCategory()); - if (! $db->table('feeds')->eq('feed_url', $feed->feed_url)->count()) { + if (empty($group_id)) { + $group_id = Group\create($subscription->getCategory()); + } - $db->table('feeds')->save(array( - 'title' => $feed->title, - 'site_url' => $feed->site_url, - 'feed_url' => $feed->feed_url - )); + Group\add($feed_id, array($group_id)); } } - - $db->closeTransaction(); - - Config\write_debug(); - - return true; } + $db->closeTransaction(); Config\write_debug(); - return false; + return true; } // Add a new feed from an URL @@ -339,7 +358,7 @@ function update_cache($feed_id, $last_modified, $etag) function remove($feed_id) { Group\remove_all($feed_id); - + // Items are removed by a sql constraint $result = Database::getInstance('db')->table('feeds')->eq('id', $feed_id)->remove(); Favicon\purge_favicons(); diff --git a/models/group.php b/models/group.php index 4682552..11bc136 100644 --- a/models/group.php +++ b/models/group.php @@ -80,6 +80,16 @@ function get_feed_group_ids($feed_id) ->findAllByColumn('id'); } +function get_feed_groups($feed_id) +{ + return Database::getInstance('db') + ->table('groups') + ->columns('groups.id', 'groups.title') + ->join('feeds_groups', 'group_id', 'id') + ->eq('feed_id', $feed_id) + ->findAll(); +} + /** * Get the id of a group * @@ -143,7 +153,7 @@ function create($title) * @param array $group_ids array of group ids * @return boolean true on success, false on error */ -function add($feed_id, $group_ids) +function add($feed_id, array $group_ids) { foreach ($group_ids as $group_id){ $data = array('feed_id' => $feed_id, 'group_id' => $group_id); @@ -167,7 +177,7 @@ function add($feed_id, $group_ids) * @param array $group_ids array of group ids * @return boolean true on success, false on error */ -function remove($feed_id, $group_ids) +function remove($feed_id, array $group_ids) { $result = Database::getInstance('db') ->table('feeds_groups') @@ -212,7 +222,7 @@ function purge_groups() $groups = Database::getInstance('db') ->table('groups') ->join('feeds_groups', 'group_id', 'id') - ->isnull('feed_id') + ->isNull('feed_id') ->findAllByColumn('id'); if (! empty($groups)) { @@ -231,7 +241,7 @@ function purge_groups() * @param string $create_group group to create and assign to feed * @return boolean */ -function update_feed_groups($feed_id, $group_ids, $create_group = '') +function update_feed_groups($feed_id, array $group_ids, $create_group = '') { if ($create_group !== '') { $id = create($create_group); diff --git a/models/proxy.php b/models/proxy.php index 2e0cca3..ed752a3 100644 --- a/models/proxy.php +++ b/models/proxy.php @@ -4,6 +4,7 @@ namespace Model\Proxy; use Helper; use Model\Config; +use PicoFeed\Client\ClientException; use PicoFeed\Config\Config as PicoFeedConfig; use PicoFeed\Filter\Filter; use PicoFeed\Client\Client; @@ -51,7 +52,6 @@ function rewrite_html($html, $website, $proxy_images, $cloak_referrer) function download($url) { try { - if ((bool) Config\get('debug_mode')) { Logger::enable(); } @@ -61,7 +61,7 @@ function download($url) $client->enablePassthroughMode(); $client->execute($url); } - catch (\PicoFeed\Client\ClientException $e) {} + catch (ClientException $e) {} Config\write_debug(); } diff --git a/vendor/autoload.php b/vendor/autoload.php index c30dbd7..8281fd2 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer' . '/autoload_real.php'; -return ComposerAutoloaderInit00bf4499632e34ac01e60c409b852c25::getLoader(); +return ComposerAutoloaderInitfd7e8d436e1dc450edc3153ac8bc31b4::getLoader(); diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 0a48966..67e7ac6 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -78,11 +78,19 @@ return array( 'PicoFeed\\Scraper\\RuleLoader' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Scraper/RuleLoader.php', 'PicoFeed\\Scraper\\RuleParser' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Scraper/RuleParser.php', 'PicoFeed\\Scraper\\Scraper' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Scraper/Scraper.php', - 'PicoFeed\\Serialization\\Export' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Serialization/Export.php', - 'PicoFeed\\Serialization\\Import' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Serialization/Import.php', - 'PicoFeed\\Syndication\\Atom' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Syndication/Atom.php', - 'PicoFeed\\Syndication\\Rss20' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20.php', - 'PicoFeed\\Syndication\\Writer' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Syndication/Writer.php', + 'PicoFeed\\Serialization\\Subscription' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Serialization/Subscription.php', + 'PicoFeed\\Serialization\\SubscriptionList' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php', + 'PicoFeed\\Serialization\\SubscriptionListBuilder' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php', + 'PicoFeed\\Serialization\\SubscriptionListParser' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php', + 'PicoFeed\\Serialization\\SubscriptionParser' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php', + 'PicoFeed\\Syndication\\AtomFeedBuilder' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php', + 'PicoFeed\\Syndication\\AtomHelper' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Syndication/AtomHelper.php', + 'PicoFeed\\Syndication\\AtomItemBuilder' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php', + 'PicoFeed\\Syndication\\FeedBuilder' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php', + 'PicoFeed\\Syndication\\ItemBuilder' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php', + 'PicoFeed\\Syndication\\Rss20FeedBuilder' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php', + 'PicoFeed\\Syndication\\Rss20Helper' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php', + 'PicoFeed\\Syndication\\Rss20ItemBuilder' => $vendorDir . '/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php', 'SimpleValidator\\Validator' => $vendorDir . '/fguillot/simple-validator/src/SimpleValidator/Validator.php', 'SimpleValidator\\Validators\\Alpha' => $vendorDir . '/fguillot/simple-validator/src/SimpleValidator/Validators/Alpha.php', 'SimpleValidator\\Validators\\AlphaNumeric' => $vendorDir . '/fguillot/simple-validator/src/SimpleValidator/Validators/AlphaNumeric.php', diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 1069239..1c93b6c 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit00bf4499632e34ac01e60c409b852c25 +class ComposerAutoloaderInitfd7e8d436e1dc450edc3153ac8bc31b4 { private static $loader; @@ -19,9 +19,9 @@ class ComposerAutoloaderInit00bf4499632e34ac01e60c409b852c25 return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInit00bf4499632e34ac01e60c409b852c25', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInitfd7e8d436e1dc450edc3153ac8bc31b4', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); - spl_autoload_unregister(array('ComposerAutoloaderInit00bf4499632e34ac01e60c409b852c25', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInitfd7e8d436e1dc450edc3153ac8bc31b4', 'loadClassLoader')); $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { @@ -42,14 +42,14 @@ class ComposerAutoloaderInit00bf4499632e34ac01e60c409b852c25 $includeFiles = require __DIR__ . '/autoload_files.php'; foreach ($includeFiles as $file) { - composerRequire00bf4499632e34ac01e60c409b852c25($file); + composerRequirefd7e8d436e1dc450edc3153ac8bc31b4($file); } return $loader; } } -function composerRequire00bf4499632e34ac01e60c409b852c25($file) +function composerRequirefd7e8d436e1dc450edc3153ac8bc31b4($file) { require $file; } diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 2fbeb75..66309ea 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -163,17 +163,17 @@ }, { "name": "fguillot/picofeed", - "version": "v0.1.21", - "version_normalized": "0.1.21.0", + "version": "v0.1.23", + "version_normalized": "0.1.23.0", "source": { "type": "git", "url": "https://github.com/fguillot/picoFeed.git", - "reference": "2baff3240ef187c9f443656ab26b0b626aec5776" + "reference": "a7c3d420c239fe9ffc39b0d06b6e57db39ce3797" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fguillot/picoFeed/zipball/2baff3240ef187c9f443656ab26b0b626aec5776", - "reference": "2baff3240ef187c9f443656ab26b0b626aec5776", + "url": "https://api.github.com/repos/fguillot/picoFeed/zipball/a7c3d420c239fe9ffc39b0d06b6e57db39ce3797", + "reference": "a7c3d420c239fe9ffc39b0d06b6e57db39ce3797", "shasum": "" }, "require": { @@ -188,7 +188,7 @@ "suggest": { "ext-curl": "PicoFeed will use cURL if present" }, - "time": "2016-03-31 00:39:41", + "time": "2016-04-17 22:31:55", "bin": [ "picofeed" ], diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Client/Curl.php b/vendor/fguillot/picofeed/lib/PicoFeed/Client/Curl.php index 69f22bb..dfbb024 100644 --- a/vendor/fguillot/picofeed/lib/PicoFeed/Client/Curl.php +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Client/Curl.php @@ -354,15 +354,15 @@ class Curl extends Client { switch ($errno) { case 78: // CURLE_REMOTE_FILE_NOT_FOUND - throw new InvalidUrlException('Resource not found'); + throw new InvalidUrlException('Resource not found', $errno); case 6: // CURLE_COULDNT_RESOLVE_HOST - throw new InvalidUrlException('Unable to resolve hostname'); + throw new InvalidUrlException('Unable to resolve hostname', $errno); case 7: // CURLE_COULDNT_CONNECT - throw new InvalidUrlException('Unable to connect to the remote host'); + throw new InvalidUrlException('Unable to connect to the remote host', $errno); case 23: // CURLE_WRITE_ERROR - throw new MaxSizeException('Maximum response size exceeded'); + throw new MaxSizeException('Maximum response size exceeded', $errno); case 28: // CURLE_OPERATION_TIMEDOUT - throw new TimeoutException('Operation timeout'); + throw new TimeoutException('Operation timeout', $errno); case 35: // CURLE_SSL_CONNECT_ERROR case 51: // CURLE_PEER_FAILED_VERIFICATION case 58: // CURLE_SSL_CERTPROBLEM @@ -372,13 +372,15 @@ class Curl extends Client case 66: // CURLE_SSL_ENGINE_INITFAILED case 77: // CURLE_SSL_CACERT_BADFILE case 83: // CURLE_SSL_ISSUER_ERROR - throw new InvalidCertificateException('Invalid SSL certificate'); + $msg = 'Invalid SSL certificate caused by CURL error number ' . + $errno; + throw new InvalidCertificateException($msg, $errno); case 47: // CURLE_TOO_MANY_REDIRECTS - throw new MaxRedirectException('Maximum number of redirections reached'); + throw new MaxRedirectException('Maximum number of redirections reached', $errno); case 63: // CURLE_FILESIZE_EXCEEDED - throw new MaxSizeException('Maximum response size exceeded'); + throw new MaxSizeException('Maximum response size exceeded', $errno); default: - throw new InvalidUrlException('Unable to fetch the URL'); + throw new InvalidUrlException('Unable to fetch the URL', $errno); } } } diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Atom.php b/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Atom.php index 6325923..19f841b 100644 --- a/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Atom.php +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Atom.php @@ -41,7 +41,7 @@ class Atom extends Parser */ public function findFeedUrl(SimpleXMLElement $xml, Feed $feed) { - $feed->feed_url = $this->getUrl($xml, 'self'); + $feed->setFeedUrl($this->getUrl($xml, 'self')); } /** @@ -52,7 +52,7 @@ class Atom extends Parser */ public function findSiteUrl(SimpleXMLElement $xml, Feed $feed) { - $feed->site_url = $this->getUrl($xml, 'alternate', true); + $feed->setSiteUrl($this->getUrl($xml, 'alternate', true)); } /** @@ -66,7 +66,7 @@ class Atom extends Parser $description = XmlParser::getXPathResult($xml, 'atom:subtitle', $this->namespaces) ?: XmlParser::getXPathResult($xml, 'subtitle'); - $feed->description = (string) current($description); + $feed->setDescription(XmlParser::getValue($description)); } /** @@ -80,7 +80,7 @@ class Atom extends Parser $logo = XmlParser::getXPathResult($xml, 'atom:logo', $this->namespaces) ?: XmlParser::getXPathResult($xml, 'logo'); - $feed->logo = (string) current($logo); + $feed->setLogo(XmlParser::getValue($logo)); } /** @@ -94,7 +94,7 @@ class Atom extends Parser $icon = XmlParser::getXPathResult($xml, 'atom:icon', $this->namespaces) ?: XmlParser::getXPathResult($xml, 'icon'); - $feed->icon = (string) current($icon); + $feed->setIcon(XmlParser::getValue($icon)); } /** @@ -108,7 +108,7 @@ class Atom extends Parser $title = XmlParser::getXPathResult($xml, 'atom:title', $this->namespaces) ?: XmlParser::getXPathResult($xml, 'title'); - $feed->title = Filter::stripWhiteSpace((string) current($title)) ?: $feed->getSiteUrl(); + $feed->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $feed->getSiteUrl()); } /** @@ -122,7 +122,7 @@ class Atom extends Parser $language = XmlParser::getXPathResult($xml, '*[not(self::atom:entry)]/@xml:lang', $this->namespaces) ?: XmlParser::getXPathResult($xml, '@xml:lang'); - $feed->language = (string) current($language); + $feed->setLanguage(XmlParser::getValue($language)); } /** @@ -136,7 +136,7 @@ class Atom extends Parser $id = XmlParser::getXPathResult($xml, 'atom:id', $this->namespaces) ?: XmlParser::getXPathResult($xml, 'id'); - $feed->id = (string) current($id); + $feed->setId(XmlParser::getValue($id)); } /** @@ -150,7 +150,7 @@ class Atom extends Parser $updated = XmlParser::getXPathResult($xml, 'atom:updated', $this->namespaces) ?: XmlParser::getXPathResult($xml, 'updated'); - $feed->date = $this->getDateParser()->getDateTime((string) current($updated)); + $feed->setDate($this->getDateParser()->getDateTime(XmlParser::getValue($updated))); } /** @@ -172,11 +172,11 @@ class Atom extends Parser $updated = !empty($updated) ? $this->getDateParser()->getDateTime((string) current($updated)) : null; if ($published === null && $updated === null) { - $item->date = $feed->getDate(); // We use the feed date if there is no date for the item + $item->setDate($feed->getDate()); // We use the feed date if there is no date for the item } elseif ($published !== null && $updated !== null) { - $item->date = max($published, $updated); // We use the most recent date between published and updated + $item->setDate(max($published, $updated)); // We use the most recent date between published and updated } else { - $item->date = $updated ?: $published; + $item->setDate($updated ?: $published); } } @@ -191,7 +191,7 @@ class Atom extends Parser $title = XmlParser::getXPathResult($entry, 'atom:title', $this->namespaces) ?: XmlParser::getXPathResult($entry, 'title'); - $item->title = Filter::stripWhiteSpace((string) current($title)) ?: $item->url; + $item->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $item->getUrl()); } /** @@ -208,7 +208,7 @@ class Atom extends Parser ?: XmlParser::getXPathResult($xml, 'atom:author/atom:name', $this->namespaces) ?: XmlParser::getXPathResult($xml, 'author/name'); - $item->author = (string) current($author); + $item->setAuthor(XmlParser::getValue($author)); } /** @@ -219,7 +219,7 @@ class Atom extends Parser */ public function findItemContent(SimpleXMLElement $entry, Item $item) { - $item->content = $this->getContent($entry); + $item->setContent($this->getContent($entry)); } /** @@ -230,7 +230,7 @@ class Atom extends Parser */ public function findItemUrl(SimpleXMLElement $entry, Item $item) { - $item->url = $this->getUrl($entry, 'alternate', true); + $item->setUrl($this->getUrl($entry, 'alternate', true)); } /** @@ -246,11 +246,11 @@ class Atom extends Parser ?: XmlParser::getXPathResult($entry, 'id'); if (!empty($id)) { - $item->id = $this->generateId((string) current($id)); + $item->setId($this->generateId(XmlParser::getValue($id))); } else { - $item->id = $this->generateId( + $item->setId($this->generateId( $item->getTitle(), $item->getUrl(), $item->getContent() - ); + )); } } @@ -266,8 +266,8 @@ class Atom extends Parser $enclosure = $this->findLink($entry, 'enclosure'); if ($enclosure) { - $item->enclosure_url = Url::resolve((string) $enclosure['href'], $feed->getSiteUrl()); - $item->enclosure_type = (string) $enclosure['type']; + $item->setEnclosureUrl(Url::resolve((string) $enclosure['href'], $feed->getSiteUrl())); + $item->setEnclosureType((string) $enclosure['type']); } } @@ -281,8 +281,7 @@ class Atom extends Parser public function findItemLanguage(SimpleXMLElement $entry, Item $item, Feed $feed) { $language = XmlParser::getXPathResult($entry, './/@xml:lang'); - - $item->language = (string) current($language) ?: $feed->language; + $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); } /** @@ -303,7 +302,6 @@ class Atom extends Parser if ($fallback) { $link = $this->findLink($xml, ''); - return $link ? (string) $link['href'] : ''; } @@ -329,7 +327,7 @@ class Atom extends Parser } } - return; + return null; } /** diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Feed.php b/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Feed.php index bf2bacf..7095728 100644 --- a/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Feed.php +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Feed.php @@ -42,14 +42,14 @@ class Feed * * @var string */ - public $feed_url = ''; + public $feedUrl = ''; /** * Site url. * * @var string */ - public $site_url = ''; + public $siteUrl = ''; /** * Feed date. @@ -86,7 +86,7 @@ class Feed { $output = ''; - foreach (array('id', 'title', 'feed_url', 'site_url', 'language', 'description', 'logo') as $property) { + foreach (array('id', 'title', 'feedUrl', 'siteUrl', 'language', 'description', 'logo') as $property) { $output .= 'Feed::'.$property.' = '.$this->$property.PHP_EOL; } @@ -139,7 +139,7 @@ class Feed */ public function getFeedUrl() { - return $this->feed_url; + return $this->feedUrl; } /** @@ -147,7 +147,7 @@ class Feed */ public function getSiteUrl() { - return $this->site_url; + return $this->siteUrl; } /** @@ -191,4 +191,124 @@ class Feed { return Parser::isLanguageRTL($this->language); } + + /** + * Set feed items. + * + * @param Item[] $items + * @return Feed + */ + public function setItems(array $items) + { + $this->items = $items; + return $this; + } + + /** + * Set feed id. + * + * @param string $id + * @return Feed + */ + public function setId($id) + { + $this->id = $id; + return $this; + } + + /** + * Set feed title. + * + * @param string $title + * @return Feed + */ + public function setTitle($title) + { + $this->title = $title; + return $this; + } + + /** + * Set feed description. + * + * @param string $description + * @return Feed + */ + public function setDescription($description) + { + $this->description = $description; + return $this; + } + + /** + * Set feed url. + * + * @param string $feedUrl + * @return Feed + */ + public function setFeedUrl($feedUrl) + { + $this->feedUrl = $feedUrl; + return $this; + } + + /** + * Set feed website url. + * + * @param string $siteUrl + * @return Feed + */ + public function setSiteUrl($siteUrl) + { + $this->siteUrl = $siteUrl; + return $this; + } + + /** + * Set feed date. + * + * @param \DateTime $date + * @return Feed + */ + public function setDate($date) + { + $this->date = $date; + return $this; + } + + /** + * Set feed language. + * + * @param string $language + * @return Feed + */ + public function setLanguage($language) + { + $this->language = $language; + return $this; + } + + /** + * Set feed logo. + * + * @param string $logo + * @return Feed + */ + public function setLogo($logo) + { + $this->logo = $logo; + return $this; + } + + /** + * Set feed icon. + * + * @param string $icon + * @return Feed + */ + public function setIcon($icon) + { + $this->icon = $icon; + return $this; + } } diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Item.php b/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Item.php index 34e557a..a2a966c 100644 --- a/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Item.php +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Item.php @@ -12,7 +12,7 @@ class Item /** * List of known RTL languages. * - * @var public + * @var string[] */ public $rtl = array( 'ar', // Arabic (ar-**) @@ -72,14 +72,14 @@ class Item * * @var string */ - public $enclosure_url = ''; + public $enclosureUrl = ''; /** * Item enclusure type. * * @var string */ - public $enclosure_type = ''; + public $enclosureType = ''; /** * Item language. @@ -140,12 +140,14 @@ class Item /** * Return item information. + * + * @return string */ public function __toString() { $output = ''; - foreach (array('id', 'title', 'url', 'language', 'author', 'enclosure_url', 'enclosure_type') as $property) { + foreach (array('id', 'title', 'url', 'language', 'author', 'enclosureUrl', 'enclosureType') as $property) { $output .= 'Item::'.$property.' = '.$this->$property.PHP_EOL; } @@ -158,6 +160,8 @@ class Item /** * Get title. + * + * @return string */ public function getTitle() { @@ -190,6 +194,8 @@ class Item /** * Get id. + * + * @return string */ public function getId() { @@ -198,6 +204,8 @@ class Item /** * Get date. + * + * @return \DateTime */ public function getDate() { @@ -206,6 +214,8 @@ class Item /** * Get content. + * + * @return string */ public function getContent() { @@ -227,22 +237,28 @@ class Item /** * Get enclosure url. + * + * @return string */ public function getEnclosureUrl() { - return $this->enclosure_url; + return $this->enclosureUrl; } /** * Get enclosure type. + * + * @return string */ public function getEnclosureType() { - return $this->enclosure_type; + return $this->enclosureType; } /** * Get language. + * + * @return string */ public function getLanguage() { @@ -251,6 +267,8 @@ class Item /** * Get author. + * + * @return string */ public function getAuthor() { @@ -266,4 +284,132 @@ class Item { return Parser::isLanguageRTL($this->language); } + + /** + * Set item id. + * + * @param string $id + * @return Item + */ + public function setId($id) + { + $this->id = $id; + return $this; + } + + /** + * Set item title. + * + * @param string $title + * @return Item + */ + public function setTitle($title) + { + $this->title = $title; + return $this; + } + + /** + * Set author. + * + * @param string $author + * @return Item + */ + public function setAuthor($author) + { + $this->author = $author; + return $this; + } + + /** + * Set item date. + * + * @param \DateTime $date + * @return Item + */ + public function setDate($date) + { + $this->date = $date; + return $this; + } + + /** + * Set enclosure url. + * + * @param string $enclosureUrl + * @return Item + */ + public function setEnclosureUrl($enclosureUrl) + { + $this->enclosureUrl = $enclosureUrl; + return $this; + } + + /** + * Set enclosure type. + * + * @param string $enclosureType + * @return Item + */ + public function setEnclosureType($enclosureType) + { + $this->enclosureType = $enclosureType; + return $this; + } + + /** + * Set item language. + * + * @param string $language + * @return Item + */ + public function setLanguage($language) + { + $this->language = $language; + return $this; + } + + /** + * Set raw XML. + * + * @param \SimpleXMLElement $xml + * @return Item + */ + public function setXml($xml) + { + $this->xml = $xml; + return $this; + } + + /** + * Get raw XML. + * + * @return \SimpleXMLElement + */ + public function getXml() + { + return $this->xml; + } + + /** + * Set XML namespaces. + * + * @param array $namespaces + * @return Item + */ + public function setNamespaces($namespaces) + { + $this->namespaces = $namespaces; + return $this; + } + + /** + * Get XML namespaces. + * + * @return array + */ + public function getNamespaces() + { + return $this->namespaces; + } } diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Parser.php b/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Parser.php index e82da3d..9e09058 100644 --- a/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Parser.php +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Parser.php @@ -180,9 +180,9 @@ abstract class Parser public function checkFeedUrl(Feed $feed) { if ($feed->getFeedUrl() === '') { - $feed->feed_url = $this->fallback_url; + $feed->feedUrl = $this->fallback_url; } else { - $feed->feed_url = Url::resolve($feed->getFeedUrl(), $this->fallback_url); + $feed->feedUrl = Url::resolve($feed->getFeedUrl(), $this->fallback_url); } } @@ -194,9 +194,9 @@ abstract class Parser public function checkSiteUrl(Feed $feed) { if ($feed->getSiteUrl() === '') { - $feed->site_url = Url::base($feed->getFeedUrl()); + $feed->siteUrl = Url::base($feed->getFeedUrl()); } else { - $feed->site_url = Url::resolve($feed->getSiteUrl(), $this->fallback_url); + $feed->siteUrl = Url::resolve($feed->getSiteUrl(), $this->fallback_url); } } diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Rss10.php b/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Rss10.php index 315c7db..210f8af 100644 --- a/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Rss10.php +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Rss10.php @@ -32,7 +32,8 @@ class Rss10 extends Parser public function getItemsTree(SimpleXMLElement $xml) { return XmlParser::getXPathResult($xml, 'rss:item', $this->namespaces) - ?: XmlParser::getXPathResult($xml, 'item'); + ?: XmlParser::getXPathResult($xml, 'item') + ?: $xml->item; } /** @@ -43,7 +44,7 @@ class Rss10 extends Parser */ public function findFeedUrl(SimpleXMLElement $xml, Feed $feed) { - $feed->feed_url = ''; + $feed->setFeedUrl(''); } /** @@ -54,10 +55,11 @@ class Rss10 extends Parser */ public function findSiteUrl(SimpleXMLElement $xml, Feed $feed) { - $site_url = XmlParser::getXPathResult($xml, 'rss:channel/rss:link', $this->namespaces) - ?: XmlParser::getXPathResult($xml, 'channel/link'); + $value = XmlParser::getXPathResult($xml, 'rss:channel/rss:link', $this->namespaces) + ?: XmlParser::getXPathResult($xml, 'channel/link') + ?: $xml->channel->link; - $feed->site_url = (string) current($site_url); + $feed->setSiteUrl(XmlParser::getValue($value)); } /** @@ -69,9 +71,10 @@ class Rss10 extends Parser public function findFeedDescription(SimpleXMLElement $xml, Feed $feed) { $description = XmlParser::getXPathResult($xml, 'rss:channel/rss:description', $this->namespaces) - ?: XmlParser::getXPathResult($xml, 'channel/description'); + ?: XmlParser::getXPathResult($xml, 'channel/description') + ?: $xml->channel->description; - $feed->description = (string) current($description); + $feed->setDescription(XmlParser::getValue($description)); } /** @@ -83,9 +86,9 @@ class Rss10 extends Parser public function findFeedLogo(SimpleXMLElement $xml, Feed $feed) { $logo = XmlParser::getXPathResult($xml, 'rss:image/rss:url', $this->namespaces) - ?: XmlParser::getXPathResult($xml, 'image/url'); + ?: XmlParser::getXPathResult($xml, 'image/url'); - $feed->logo = (string) current($logo); + $feed->setLogo(XmlParser::getValue($logo)); } /** @@ -96,7 +99,7 @@ class Rss10 extends Parser */ public function findFeedIcon(SimpleXMLElement $xml, Feed $feed) { - $feed->icon = ''; + $feed->setIcon(''); } /** @@ -108,9 +111,10 @@ class Rss10 extends Parser public function findFeedTitle(SimpleXMLElement $xml, Feed $feed) { $title = XmlParser::getXPathResult($xml, 'rss:channel/rss:title', $this->namespaces) - ?: XmlParser::getXPathResult($xml, 'channel/title'); + ?: XmlParser::getXPathResult($xml, 'channel/title') + ?: $xml->channel->title; - $feed->title = Filter::stripWhiteSpace((string) current($title)) ?: $feed->getSiteUrl(); + $feed->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $feed->getSiteUrl()); } /** @@ -124,7 +128,7 @@ class Rss10 extends Parser $language = XmlParser::getXPathResult($xml, 'rss:channel/dc:language', $this->namespaces) ?: XmlParser::getXPathResult($xml, 'channel/dc:language', $this->namespaces); - $feed->language = (string) current($language); + $feed->setLanguage(XmlParser::getValue($language)); } /** @@ -135,7 +139,7 @@ class Rss10 extends Parser */ public function findFeedId(SimpleXMLElement $xml, Feed $feed) { - $feed->id = $feed->getFeedUrl() ?: $feed->getSiteUrl(); + $feed->setId($feed->getFeedUrl() ?: $feed->getSiteUrl()); } /** @@ -149,7 +153,7 @@ class Rss10 extends Parser $date = XmlParser::getXPathResult($xml, 'rss:channel/dc:date', $this->namespaces) ?: XmlParser::getXPathResult($xml, 'channel/dc:date', $this->namespaces); - $feed->date = $this->getDateParser()->getDateTime((string) current($date)); + $feed->setDate($this->getDateParser()->getDateTime(XmlParser::getValue($date))); } /** @@ -163,7 +167,7 @@ class Rss10 extends Parser { $date = XmlParser::getXPathResult($entry, 'dc:date', $this->namespaces); - $item->date = empty($date) ? $feed->getDate() : $this->getDateParser()->getDateTime((string) current($date)); + $item->setDate(empty($date) ? $feed->getDate() : $this->getDateParser()->getDateTime(XmlParser::getValue($date))); } /** @@ -175,9 +179,10 @@ class Rss10 extends Parser public function findItemTitle(SimpleXMLElement $entry, Item $item) { $title = XmlParser::getXPathResult($entry, 'rss:title', $this->namespaces) - ?: XmlParser::getXPathResult($entry, 'title'); + ?: XmlParser::getXPathResult($entry, 'title') + ?: $entry->title; - $item->title = Filter::stripWhiteSpace((string) current($title)) ?: $item->url; + $item->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $item->getUrl()); } /** @@ -193,7 +198,7 @@ class Rss10 extends Parser ?: XmlParser::getXPathResult($xml, 'rss:channel/dc:creator', $this->namespaces) ?: XmlParser::getXPathResult($xml, 'channel/dc:creator', $this->namespaces); - $item->author = (string) current($author); + $item->setAuthor(XmlParser::getValue($author)); } /** @@ -206,12 +211,13 @@ class Rss10 extends Parser { $content = XmlParser::getXPathResult($entry, 'content:encoded', $this->namespaces); - if (trim((string) current($content)) === '') { + if (XmlParser::getValue($content) === '') { $content = XmlParser::getXPathResult($entry, 'rss:description', $this->namespaces) - ?: XmlParser::getXPathResult($entry, 'description'); + ?: XmlParser::getXPathResult($entry, 'description') + ?: $entry->description; } - $item->content = (string) current($content); + $item->setContent(XmlParser::getValue($content)); } /** @@ -223,10 +229,11 @@ class Rss10 extends Parser public function findItemUrl(SimpleXMLElement $entry, Item $item) { $link = XmlParser::getXPathResult($entry, 'feedburner:origLink', $this->namespaces) - ?: XmlParser::getXPathResult($entry, 'rss:link', $this->namespaces) - ?: XmlParser::getXPathResult($entry, 'link'); + ?: XmlParser::getXPathResult($entry, 'rss:link', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'link') + ?: $entry->link; - $item->url = trim((string) current($link)); + $item->setUrl(XmlParser::getValue($link)); } /** @@ -238,9 +245,9 @@ class Rss10 extends Parser */ public function findItemId(SimpleXMLElement $entry, Item $item, Feed $feed) { - $item->id = $this->generateId( + $item->setId($this->generateId( $item->getTitle(), $item->getUrl(), $item->getContent() - ); + )); } /** @@ -265,6 +272,6 @@ class Rss10 extends Parser { $language = XmlParser::getXPathResult($entry, 'dc:language', $this->namespaces); - $item->language = (string) current($language) ?: $feed->language; + $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); } } diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Rss20.php b/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Rss20.php index b265656..77f797d 100644 --- a/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Rss20.php +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Parser/Rss20.php @@ -43,7 +43,7 @@ class Rss20 extends Parser */ public function findFeedUrl(SimpleXMLElement $xml, Feed $feed) { - $feed->feed_url = ''; + $feed->setFeedUrl(''); } /** @@ -54,8 +54,8 @@ class Rss20 extends Parser */ public function findSiteUrl(SimpleXMLElement $xml, Feed $feed) { - $site_url = XmlParser::getXPathResult($xml, 'channel/link'); - $feed->site_url = (string) current($site_url); + $value = XmlParser::getXPathResult($xml, 'channel/link'); + $feed->setSiteUrl(XmlParser::getValue($value)); } /** @@ -66,8 +66,8 @@ class Rss20 extends Parser */ public function findFeedDescription(SimpleXMLElement $xml, Feed $feed) { - $description = XmlParser::getXPathResult($xml, 'channel/description'); - $feed->description = (string) current($description); + $value = XmlParser::getXPathResult($xml, 'channel/description'); + $feed->setDescription(XmlParser::getValue($value)); } /** @@ -78,8 +78,8 @@ class Rss20 extends Parser */ public function findFeedLogo(SimpleXMLElement $xml, Feed $feed) { - $logo = XmlParser::getXPathResult($xml, 'channel/image/url'); - $feed->logo = (string) current($logo); + $value = XmlParser::getXPathResult($xml, 'channel/image/url'); + $feed->setLogo(XmlParser::getValue($value)); } /** @@ -90,7 +90,7 @@ class Rss20 extends Parser */ public function findFeedIcon(SimpleXMLElement $xml, Feed $feed) { - $feed->icon = ''; + $feed->setIcon(''); } /** @@ -102,7 +102,7 @@ class Rss20 extends Parser public function findFeedTitle(SimpleXMLElement $xml, Feed $feed) { $title = XmlParser::getXPathResult($xml, 'channel/title'); - $feed->title = Filter::stripWhiteSpace((string) current($title)) ?: $feed->getSiteUrl(); + $feed->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($title)) ?: $feed->getSiteUrl()); } /** @@ -113,8 +113,8 @@ class Rss20 extends Parser */ public function findFeedLanguage(SimpleXMLElement $xml, Feed $feed) { - $language = XmlParser::getXPathResult($xml, 'channel/language'); - $feed->language = (string) current($language); + $value = XmlParser::getXPathResult($xml, 'channel/language'); + $feed->setLanguage(XmlParser::getValue($value)); } /** @@ -125,7 +125,7 @@ class Rss20 extends Parser */ public function findFeedId(SimpleXMLElement $xml, Feed $feed) { - $feed->id = $feed->getFeedUrl() ?: $feed->getSiteUrl(); + $feed->setId($feed->getFeedUrl() ?: $feed->getSiteUrl()); } /** @@ -139,15 +139,15 @@ class Rss20 extends Parser $publish_date = XmlParser::getXPathResult($xml, 'channel/pubDate'); $update_date = XmlParser::getXPathResult($xml, 'channel/lastBuildDate'); - $published = !empty($publish_date) ? $this->getDateParser()->getDateTime((string) current($publish_date)) : null; - $updated = !empty($update_date) ? $this->getDateParser()->getDateTime((string) current($update_date)) : null; + $published = !empty($publish_date) ? $this->getDateParser()->getDateTime(XmlParser::getValue($publish_date)) : null; + $updated = !empty($update_date) ? $this->getDateParser()->getDateTime(XmlParser::getValue($update_date)) : null; if ($published === null && $updated === null) { - $feed->date = $this->getDateParser()->getCurrentDateTime(); // We use the current date if there is no date for the feed + $feed->setDate($this->getDateParser()->getCurrentDateTime()); // We use the current date if there is no date for the feed } elseif ($published !== null && $updated !== null) { - $feed->date = max($published, $updated); // We use the most recent date between published and updated + $feed->setDate(max($published, $updated)); // We use the most recent date between published and updated } else { - $feed->date = $updated ?: $published; + $feed->setDate($updated ?: $published); } } @@ -162,7 +162,7 @@ class Rss20 extends Parser { $date = XmlParser::getXPathResult($entry, 'pubDate'); - $item->date = empty($date) ? $feed->getDate() : $this->getDateParser()->getDateTime((string) current($date)); + $item->setDate(empty($date) ? $feed->getDate() : $this->getDateParser()->getDateTime(XmlParser::getValue($date))); } /** @@ -173,8 +173,8 @@ class Rss20 extends Parser */ public function findItemTitle(SimpleXMLElement $entry, Item $item) { - $title = XmlParser::getXPathResult($entry, 'title'); - $item->title = Filter::stripWhiteSpace((string) current($title)) ?: $item->url; + $value = XmlParser::getXPathResult($entry, 'title'); + $item->setTitle(Filter::stripWhiteSpace(XmlParser::getValue($value)) ?: $item->getUrl()); } /** @@ -186,12 +186,12 @@ class Rss20 extends Parser */ public function findItemAuthor(SimpleXMLElement $xml, SimpleXMLElement $entry, Item $item) { - $author = XmlParser::getXPathResult($entry, 'dc:creator', $this->namespaces) + $value = XmlParser::getXPathResult($entry, 'dc:creator', $this->namespaces) ?: XmlParser::getXPathResult($entry, 'author') ?: XmlParser::getXPathResult($xml, 'channel/dc:creator', $this->namespaces) ?: XmlParser::getXPathResult($xml, 'channel/managingEditor'); - $item->author = (string) current($author); + $item->setAuthor(XmlParser::getValue($value)); } /** @@ -204,11 +204,11 @@ class Rss20 extends Parser { $content = XmlParser::getXPathResult($entry, 'content:encoded', $this->namespaces); - if (trim((string) current($content)) === '') { + if (XmlParser::getValue($content) === '') { $content = XmlParser::getXPathResult($entry, 'description'); } - $item->content = (string) current($content); + $item->setContent(XmlParser::getValue($content)); } /** @@ -224,13 +224,13 @@ class Rss20 extends Parser ?: XmlParser::getXPathResult($entry, 'atom:link/@href', $this->namespaces); if (!empty($link)) { - $item->url = trim((string) current($link)); + $item->setUrl(XmlParser::getValue($link)); } else { $link = XmlParser::getXPathResult($entry, 'guid'); - $link = trim((string) current($link)); + $link = XmlParser::getValue($link); if (filter_var($link, FILTER_VALIDATE_URL) !== false) { - $item->url = $link; + $item->setUrl($link); } } } @@ -244,14 +244,14 @@ class Rss20 extends Parser */ public function findItemId(SimpleXMLElement $entry, Item $item, Feed $feed) { - $id = (string) current(XmlParser::getXPathResult($entry, 'guid')); + $id = XmlParser::getValue(XmlParser::getXPathResult($entry, 'guid')); if ($id) { - $item->id = $this->generateId($id); + $item->setId($this->generateId($id)); } else { - $item->id = $this->generateId( + $item->setId($this->generateId( $item->getTitle(), $item->getUrl(), $item->getContent() - ); + )); } } @@ -265,13 +265,12 @@ class Rss20 extends Parser public function findItemEnclosure(SimpleXMLElement $entry, Item $item, Feed $feed) { if (isset($entry->enclosure)) { - $enclosure_url = XmlParser::getXPathResult($entry, 'feedburner:origEnclosureLink', $this->namespaces) - ?: XmlParser::getXPathResult($entry, 'enclosure/@url'); + $type = XmlParser::getXPathResult($entry, 'enclosure/@type'); + $url = XmlParser::getXPathResult($entry, 'feedburner:origEnclosureLink', $this->namespaces) + ?: XmlParser::getXPathResult($entry, 'enclosure/@url'); - $enclosure_type = XmlParser::getXPathResult($entry, 'enclosure/@type'); - - $item->enclosure_url = Url::resolve((string) current($enclosure_url), $feed->getSiteUrl()); - $item->enclosure_type = (string) current($enclosure_type); + $item->setEnclosureUrl(Url::resolve(XmlParser::getValue($url), $feed->getSiteUrl())); + $item->setEnclosureType(XmlParser::getValue($type)); } } @@ -285,7 +284,6 @@ class Rss20 extends Parser public function findItemLanguage(SimpleXMLElement $entry, Item $item, Feed $feed) { $language = XmlParser::getXPathResult($entry, 'dc:language', $this->namespaces); - - $item->language = (string) current($language) ?: $feed->language; + $item->setLanguage(XmlParser::getValue($language) ?: $feed->getLanguage()); } } diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Parser/XmlParser.php b/vendor/fguillot/picofeed/lib/PicoFeed/Parser/XmlParser.php index 6ed5a48..8247c99 100644 --- a/vendor/fguillot/picofeed/lib/PicoFeed/Parser/XmlParser.php +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Parser/XmlParser.php @@ -4,7 +4,6 @@ namespace PicoFeed\Parser; use DomDocument; use SimpleXmlElement; -use Exception; use ZendXml\Security; @@ -21,9 +20,7 @@ class XmlParser * Get a SimpleXmlElement instance or return false. * * @static - * * @param string $input XML content - * * @return mixed */ public static function getSimpleXml($input) @@ -35,9 +32,7 @@ class XmlParser * Get a DomDocument instance or return false. * * @static - * * @param string $input XML content - * * @return \DOMDocument */ public static function getDomDocument($input) @@ -59,6 +54,7 @@ class XmlParser /** * Small wrapper around ZendXml to turn their exceptions into picoFeed * exceptions + * * @param $input the xml to load * @param $dom pass in a dom document or use null/omit if simpleXml should * be used @@ -76,9 +72,7 @@ class XmlParser * Load HTML document by using a DomDocument instance or return false on failure. * * @static - * * @param string $input XML content - * * @return \DOMDocument */ public static function getHtmlDocument($input) @@ -112,7 +106,6 @@ class XmlParser public static function htmlToXml($html) { $dom = self::getHtmlDocument(''.$html); - return $dom->saveXML($dom->getElementsByTagName('body')->item(0)); } @@ -120,7 +113,6 @@ class XmlParser * Get XML parser errors. * * @static - * * @return string */ public static function getErrors() @@ -143,9 +135,7 @@ class XmlParser * Get the encoding from a xml tag. * * @static - * * @param string $data Input data - * * @return string */ public static function getEncodingFromXmlTag($data) @@ -172,9 +162,7 @@ class XmlParser * Get the charset from a meta tag. * * @static - * * @param string $data Input data - * * @return string */ public static function getEncodingFromMetaTag($data) @@ -193,7 +181,6 @@ class XmlParser * * @param string $query XPath query * @param array $ns Prefix to namespace URI mapping - * * @return string */ public static function replaceXPathPrefixWithNamespaceURI($query, array $ns) @@ -215,8 +202,7 @@ class XmlParser * @param \SimpleXMLElement $xml XML element * @param string $query XPath query * @param array $ns Prefix to namespace URI mapping - * - * @return \SimpleXMLElement + * @return \SimpleXMLElement[] */ public static function getXPathResult(SimpleXMLElement $xml, $query, array $ns = array()) { @@ -226,4 +212,25 @@ class XmlParser return $xml->xpath($query); } + + /** + * Get the first Xpath result or SimpleXMLElement value + * + * @static + * @access public + * @param mixed $value + * @return string + */ + public static function getValue($value) + { + $result = ''; + + if (is_array($value) && count($value) > 0) { + $result = (string) $value[0]; + } elseif (is_a($value, 'SimpleXMLElement')) { + return $result = (string) $value; + } + + return trim($result); + } } diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.sciencemag.org.php b/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.sciencemag.org.php index 3d34857..ae7a93a 100644 --- a/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.sciencemag.org.php +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Rules/www.sciencemag.org.php @@ -2,7 +2,7 @@ return array( 'grabber' => array( '%.*%' => array( - 'test_url' => 'http://www.sciencemag.org/news/2016/01/could-bright-foamy-wak$ + 'test_url' => 'http://www.sciencemag.org/news/2016/01/could-bright-foamy-wak$', 'body' => array( '//div[@class="row--hero"]', '//article[contains(@class,"primary")]', diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Export.php b/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Export.php deleted file mode 100644 index e5b6197..0000000 --- a/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Export.php +++ /dev/null @@ -1,122 +0,0 @@ -content = $content; - } - - /** - * Get the OPML document. - * - * @return string - */ - public function execute() - { - $xml = new SimpleXMLElement(''); - - $head = $xml->addChild('head'); - $head->addChild('title', 'OPML Export'); - - $body = $xml->addChild('body'); - - foreach ($this->content as $category => $values) { - if (is_string($category)) { - $this->createCategory($body, $category, $values); - } else { - $this->createEntry($body, $values); - } - } - - return $xml->asXML(); - } - - /** - * Create a feed entry. - * - * @param SimpleXMLElement $parent Parent Element - * @param array $feed Feed properties - */ - public function createEntry(SimpleXMLElement $parent, array $feed) - { - $valid = true; - - foreach ($this->required_fields as $field) { - if (!isset($feed[$field])) { - $valid = false; - break; - } - } - - if ($valid) { - $outline = $parent->addChild('outline'); - $outline->addAttribute('xmlUrl', $feed['feed_url']); - $outline->addAttribute('htmlUrl', $feed['site_url']); - $outline->addAttribute('title', $feed['title']); - $outline->addAttribute('text', $feed['title']); - $outline->addAttribute('description', isset($feed['description']) ? $feed['description'] : $feed['title']); - $outline->addAttribute('type', 'rss'); - $outline->addAttribute('version', 'RSS'); - } - } - - /** - * Create entries for a feed list. - * - * @param SimpleXMLElement $parent Parent Element - * @param array $feeds Feed list - */ - public function createEntries(SimpleXMLElement $parent, array $feeds) - { - foreach ($feeds as $feed) { - $this->createEntry($parent, $feed); - } - } - - /** - * Create a category entry. - * - * @param SimpleXMLElement $parent Parent Element - * @param string $category Category - * @param array $feeds Feed properties - */ - public function createCategory(SimpleXMLElement $parent, $category, array $feeds) - { - $outline = $parent->addChild('outline'); - $outline->addAttribute('text', $category); - $this->createEntries($outline, $feeds); - } -} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Import.php b/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Import.php deleted file mode 100644 index 5a426e6..0000000 --- a/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Import.php +++ /dev/null @@ -1,162 +0,0 @@ -content = $content; - } - - /** - * Parse the OPML file. - * - * @return array|false - */ - public function execute() - { - Logger::setMessage(get_called_class().': start importation'); - - $xml = XmlParser::getSimpleXml(trim($this->content)); - - if ($xml === false || $xml->getName() !== 'opml' || !isset($xml->body)) { - Logger::setMessage(get_called_class().': OPML tag not found or malformed XML document'); - - return false; - } - - $this->parseEntries($xml->body); - Logger::setMessage(get_called_class().': '.count($this->items).' subscriptions found'); - - return $this->items; - } - - /** - * Parse each entries of the subscription list. - * - * @param SimpleXMLElement $tree XML node - */ - public function parseEntries(SimpleXMLElement $tree) - { - if (isset($tree->outline)) { - foreach ($tree->outline as $item) { - if (isset($item->outline)) { - $this->parseEntries($item); - } elseif ((isset($item['text']) || isset($item['title'])) && isset($item['xmlUrl'])) { - $entry = new StdClass(); - $entry->category = $this->findCategory($tree); - $entry->title = $this->findTitle($item); - $entry->feed_url = $this->findFeedUrl($item); - $entry->site_url = $this->findSiteUrl($item, $entry); - $entry->type = $this->findType($item); - $entry->description = $this->findDescription($item, $entry); - $this->items[] = $entry; - } - } - } - } - - /** - * Find category. - * - * @param SimpleXmlElement $tree XML tree - * - * @return string - */ - public function findCategory(SimpleXmlElement $tree) - { - return isset($tree['title']) ? (string) $tree['title'] : (string) $tree['text']; - } - - /** - * Find title. - * - * @param SimpleXmlElement $item XML tree - * - * @return string - */ - public function findTitle(SimpleXmlElement $item) - { - return isset($item['title']) ? (string) $item['title'] : (string) $item['text']; - } - - /** - * Find feed url. - * - * @param SimpleXmlElement $item XML tree - * - * @return string - */ - public function findFeedUrl(SimpleXmlElement $item) - { - return (string) $item['xmlUrl']; - } - - /** - * Find site url. - * - * @param SimpleXmlElement $item XML tree - * @param StdClass $entry Feed entry - * - * @return string - */ - public function findSiteUrl(SimpleXmlElement $item, StdClass $entry) - { - return isset($item['htmlUrl']) ? (string) $item['htmlUrl'] : $entry->feed_url; - } - - /** - * Find type. - * - * @param SimpleXmlElement $item XML tree - * - * @return string - */ - public function findType(SimpleXmlElement $item) - { - return isset($item['version']) ? (string) $item['version'] : isset($item['type']) ? (string) $item['type'] : 'rss'; - } - - /** - * Find description. - * - * @param SimpleXmlElement $item XML tree - * @param StdClass $entry Feed entry - * - * @return string - */ - public function findDescription(SimpleXmlElement $item, StdClass $entry) - { - return isset($item['description']) ? (string) $item['description'] : $entry->title; - } -} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Subscription.php b/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Subscription.php new file mode 100644 index 0000000..12eccfd --- /dev/null +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/Subscription.php @@ -0,0 +1,175 @@ +title = $title; + return $this; + } + + /** + * Get title + * + * @access public + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * Set feed URL + * + * @access public + * @param string $feedUrl + * @return Subscription + */ + public function setFeedUrl($feedUrl) + { + $this->feedUrl = $feedUrl; + return $this; + } + + /** + * Get feed URL + * + * @access public + * @return string + */ + public function getFeedUrl() + { + return $this->feedUrl; + } + + /** + * Set site URL + * + * @access public + * @param string $siteUrl + * @return Subscription + */ + public function setSiteUrl($siteUrl) + { + $this->siteUrl = $siteUrl; + return $this; + } + + /** + * Get site URL + * + * @access public + * @return string + */ + public function getSiteUrl() + { + return $this->siteUrl; + } + + /** + * Set category + * + * @access public + * @param string $category + * @return Subscription + */ + public function setCategory($category) + { + $this->category = $category; + return $this; + } + + /** + * Get category + * + * @access public + * @return string + */ + public function getCategory() + { + return $this->category; + } + + /** + * Set description + * + * @access public + * @param string $description + * @return Subscription + */ + public function setDescription($description) + { + $this->description = $description; + return $this; + } + + /** + * Get description + * + * @access public + * @return string + */ + public function getDescription() + { + return $this->description; + } + + /** + * Set type + * + * @access public + * @param string $type + * @return Subscription + */ + public function setType($type) + { + $this->type = $type; + return $this; + } + + /** + * Get type + * + * @access public + * @return string + */ + public function getType() + { + return $this->type; + } +} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php b/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php new file mode 100644 index 0000000..b173f89 --- /dev/null +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionList.php @@ -0,0 +1,75 @@ +title = $title; + return $this; + } + + /** + * Get title + * + * @access public + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * Add subscription + * + * @access public + * @param Subscription $subscription + * @return SubscriptionList + */ + public function addSubscription(Subscription $subscription) + { + $this->subscriptions[] = $subscription; + return $this; + } +} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php b/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php new file mode 100644 index 0000000..838e4cb --- /dev/null +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListBuilder.php @@ -0,0 +1,204 @@ +subscriptionList = $subscriptionList; + } + + /** + * Get object instance + * + * @static + * @access public + * @param SubscriptionList $subscriptionList + * @return SubscriptionListBuilder + */ + public static function create(SubscriptionList $subscriptionList) + { + return new static($subscriptionList); + } + + /** + * Build OPML feed + * + * @access public + * @param string $filename + * @return string + */ + public function build($filename = '') + { + $this->document = new DomDocument('1.0', 'UTF-8'); + $this->document->formatOutput = true; + + $opmlElement = $this->document->createElement('opml'); + $opmlElement->setAttribute('version', '1.0'); + + $headElement = $this->document->createElement('head'); + + if ($this->subscriptionList->getTitle() !== '') { + $titleElement = $this->document->createElement('title'); + $titleElement->appendChild($this->document->createTextNode($this->subscriptionList->getTitle())); + $headElement->appendChild($titleElement); + } + + $opmlElement->appendChild($headElement); + $opmlElement->appendChild($this->buildBody()); + $this->document->appendChild($opmlElement); + + if ($filename !== '') { + $this->document->save($filename); + return ''; + } + + return $this->document->saveXML(); + } + + /** + * Return true if the list has categories + * + * @access public + * @return bool + */ + public function hasCategories() + { + foreach ($this->subscriptionList->subscriptions as $subscription) { + if ($subscription->getCategory() !== '') { + return true; + } + } + + return false; + } + + /** + * Build OPML body + * + * @access protected + * @return DOMElement + */ + protected function buildBody() + { + $bodyElement = $this->document->createElement('body'); + + if ($this->hasCategories()) { + $this->buildCategories($bodyElement); + return $bodyElement; + } + + foreach ($this->subscriptionList->subscriptions as $subscription) { + $bodyElement->appendChild($this->buildSubscription($subscription)); + } + + return $bodyElement; + } + + /** + * Build categories section + * + * @access protected + * @param DOMElement $bodyElement + */ + protected function buildCategories(DOMElement $bodyElement) + { + $categories = $this->groupByCategories(); + + foreach ($categories as $category => $subscriptions) { + $bodyElement->appendChild($this->buildCategory($category, $subscriptions)); + } + } + + /** + * Build category tag + * + * @access protected + * @param string $category + * @param array $subscriptions + * @return DOMElement + */ + protected function buildCategory($category, array $subscriptions) + { + $outlineElement = $this->document->createElement('outline'); + $outlineElement->setAttribute('text', $category); + + foreach ($subscriptions as $subscription) { + $outlineElement->appendChild($this->buildSubscription($subscription)); + } + + return $outlineElement; + } + + /** + * Build subscription entry + * + * @access public + * @param Subscription $subscription + * @return DOMElement + */ + protected function buildSubscription(Subscription $subscription) + { + $outlineElement = $this->document->createElement('outline'); + $outlineElement->setAttribute('type', $subscription->getType() ?: 'rss'); + $outlineElement->setAttribute('text', $subscription->getTitle() ?: $subscription->getFeedUrl()); + $outlineElement->setAttribute('xmlUrl', $subscription->getFeedUrl()); + + if ($subscription->getTitle() !== '') { + $outlineElement->setAttribute('title', $subscription->getTitle()); + } + + if ($subscription->getDescription() !== '') { + $outlineElement->setAttribute('description', $subscription->getDescription()); + } + + if ($subscription->getSiteUrl() !== '') { + $outlineElement->setAttribute('htmlUrl', $subscription->getSiteUrl()); + } + + return $outlineElement; + } + + /** + * Group subscriptions by category + * + * @access private + * @return array + */ + private function groupByCategories() + { + $categories = array(); + + foreach ($this->subscriptionList->subscriptions as $subscription) { + $categories[$subscription->getCategory()][] = $subscription; + } + + return $categories; + } +} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php b/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php new file mode 100644 index 0000000..9085588 --- /dev/null +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionListParser.php @@ -0,0 +1,100 @@ +subscriptionList = new SubscriptionList(); + $this->data = trim($data); + } + + /** + * Get object instance + * + * @static + * @access public + * @param string $data + * @return SubscriptionListParser + */ + public static function create($data) + { + return new static($data); + } + + /** + * Parse a subscription list entry + * + * @access public + * @throws MalformedXmlException + * @return SubscriptionList + */ + public function parse() + { + $xml = XmlParser::getSimpleXml($this->data); + + if (! $xml || !isset($xml->head) || !isset($xml->body)) { + throw new MalformedXmlException('Unable to parse OPML file: invalid XML'); + } + + $this->parseTitle($xml->head); + $this->parseEntries($xml->body); + + return $this->subscriptionList; + } + + /** + * Parse title + * + * @access protected + * @param SimpleXMLElement $xml + */ + protected function parseTitle(SimpleXMLElement $xml) + { + $this->subscriptionList->setTitle((string) $xml->title); + } + + /** + * Parse entries + * + * @access protected + * @param SimpleXMLElement $body + */ + private function parseEntries(SimpleXMLElement $body) + { + foreach ($body->outline as $outlineElement) { + if (isset($outlineElement->outline)) { + $this->parseEntries($outlineElement); + } else { + $this->subscriptionList->subscriptions[] = SubscriptionParser::create($body, $outlineElement)->parse(); + } + } + } +} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php b/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php new file mode 100644 index 0000000..caff07c --- /dev/null +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Serialization/SubscriptionParser.php @@ -0,0 +1,142 @@ +parentElement = $parentElement; + $this->outlineElement = $outlineElement; + $this->subscription = new Subscription(); + } + + /** + * Get object instance + * + * @static + * @access public + * @param SimpleXMLElement $parentElement + * @param SimpleXMLElement $outlineElement + * @return SubscriptionParser + */ + public static function create(SimpleXMLElement $parentElement, SimpleXMLElement $outlineElement) + { + return new static($parentElement, $outlineElement); + } + + /** + * Parse subscription entry + * + * @access public + * @return Subscription + */ + public function parse() + { + $this->subscription->setCategory($this->findCategory()); + $this->subscription->setTitle($this->findTitle()); + $this->subscription->setFeedUrl($this->findFeedUrl()); + $this->subscription->setSiteUrl($this->findSiteUrl()); + $this->subscription->setType($this->findType()); + $this->subscription->setDescription($this->findDescription()); + + return $this->subscription; + } + + /** + * Find category. + * + * @access protected + * @return string + */ + protected function findCategory() + { + return isset($this->parentElement['text']) ? (string) $this->parentElement['text'] : ''; + } + + /** + * Find title. + * + * @access protected + * @return string + */ + protected function findTitle() + { + return isset($this->outlineElement['title']) ? (string) $this->outlineElement['title'] : (string) $this->outlineElement['text']; + } + + /** + * Find feed url. + * + * @access protected + * @return string + */ + protected function findFeedUrl() + { + return (string) $this->outlineElement['xmlUrl']; + } + + /** + * Find site url. + * + * @access protected + * @return string + */ + protected function findSiteUrl() + { + return isset($this->outlineElement['htmlUrl']) ? (string) $this->outlineElement['htmlUrl'] : $this->findFeedUrl(); + } + + /** + * Find type. + * + * @access protected + * @return string + */ + protected function findType() + { + return isset($this->outlineElement['version']) ? (string) $this->outlineElement['version'] : + isset($this->outlineElement['type']) ? (string) $this->outlineElement['type'] : 'rss'; + } + + /** + * Find description. + * + * @access protected + * @return string + */ + protected function findDescription() + { + return isset($this->outlineElement['description']) ? (string) $this->outlineElement['description'] : $this->findTitle(); + } +} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Atom.php b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Atom.php deleted file mode 100644 index 759f35b..0000000 --- a/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Atom.php +++ /dev/null @@ -1,215 +0,0 @@ -checkRequiredProperties($this->required_feed_properties, $this); - - $this->dom = new DomDocument('1.0', 'UTF-8'); - $this->dom->formatOutput = true; - - // - $feed = $this->dom->createElement('feed'); - $feed->setAttributeNodeNS(new DomAttr('xmlns', 'http://www.w3.org/2005/Atom')); - - // - $generator = $this->dom->createElement('generator', 'PicoFeed'); - $generator->setAttribute('uri', 'https://github.com/fguillot/picoFeed'); - $feed->appendChild($generator); - - // - $title = $this->dom->createElement('title'); - $title->appendChild($this->dom->createTextNode($this->title)); - $feed->appendChild($title); - - // <id/> - $id = $this->dom->createElement('id'); - $id->appendChild($this->dom->createTextNode($this->site_url)); - $feed->appendChild($id); - - // <updated/> - $this->addUpdated($feed, $this->updated); - - // <link rel="alternate" type="text/html" href="http://example.org/"/> - $this->addLink($feed, $this->site_url); - - // <link rel="self" type="application/atom+xml" href="http://example.org/feed.atom"/> - $this->addLink($feed, $this->feed_url, 'self', 'application/atom+xml'); - - // <author/> - if (isset($this->author)) { - $this->addAuthor($feed, $this->author); - } - - // <entry/> - foreach ($this->items as $item) { - $this->checkRequiredProperties($this->required_item_properties, $item); - $feed->appendChild($this->createEntry($item)); - } - - $this->dom->appendChild($feed); - - if ($filename) { - $this->dom->save($filename); - } else { - return $this->dom->saveXML(); - } - } - - /** - * Create item entry. - * - * @param arrray $item Item properties - * - * @return DomElement - */ - public function createEntry(array $item) - { - $entry = $this->dom->createElement('entry'); - - // <title/> - $title = $this->dom->createElement('title'); - $title->appendChild($this->dom->createTextNode($item['title'])); - $entry->appendChild($title); - - // <id/> - $id = $this->dom->createElement('id'); - $id->appendChild($this->dom->createTextNode(isset($item['id']) ? $item['id'] : $item['url'])); - $entry->appendChild($id); - - // <updated/> - $this->addUpdated($entry, isset($item['updated']) ? $item['updated'] : ''); - - // <published/> - if (isset($item['published'])) { - $entry->appendChild($this->dom->createElement('published', date(DATE_ATOM, $item['published']))); - } - - // <link rel="alternate" type="text/html" href="http://example.org/"/> - $this->addLink($entry, $item['url']); - - // <summary/> - if (isset($item['summary'])) { - $summary = $this->dom->createElement('summary'); - $summary->appendChild($this->dom->createTextNode($item['summary'])); - $entry->appendChild($summary); - } - - // <content/> - if (isset($item['content'])) { - $content = $this->dom->createElement('content'); - $content->setAttribute('type', 'html'); - $content->appendChild($this->dom->createCDATASection($item['content'])); - $entry->appendChild($content); - } - - // <author/> - if (isset($item['author'])) { - $this->addAuthor($entry, $item['author']); - } - - return $entry; - } - - /** - * Add Link. - * - * @param DomElement $xml XML node - * @param string $url URL - * @param string $rel Link rel attribute - * @param string $type Link type attribute - */ - public function addLink(DomElement $xml, $url, $rel = 'alternate', $type = 'text/html') - { - $link = $this->dom->createElement('link'); - $link->setAttribute('rel', $rel); - $link->setAttribute('type', $type); - $link->setAttribute('href', $url); - $xml->appendChild($link); - } - - /** - * Add publication date. - * - * @param DomElement $xml XML node - * @param int $value Timestamp - */ - public function addUpdated(DomElement $xml, $value = 0) - { - $xml->appendChild($this->dom->createElement( - 'updated', - date(DATE_ATOM, $value ?: time()) - )); - } - - /** - * Add author. - * - * @param DomElement $xml XML node - * @param array $values Author name and email - */ - public function addAuthor(DomElement $xml, array $values) - { - $author = $this->dom->createElement('author'); - - if (isset($values['name'])) { - $name = $this->dom->createElement('name'); - $name->appendChild($this->dom->createTextNode($values['name'])); - $author->appendChild($name); - } - - if (isset($values['email'])) { - $email = $this->dom->createElement('email'); - $email->appendChild($this->dom->createTextNode($values['email'])); - $author->appendChild($email); - } - - if (isset($values['url'])) { - $uri = $this->dom->createElement('uri'); - $uri->appendChild($this->dom->createTextNode($values['url'])); - $author->appendChild($uri); - } - - $xml->appendChild($author); - } -} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php new file mode 100644 index 0000000..9d80d71 --- /dev/null +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomFeedBuilder.php @@ -0,0 +1,65 @@ +<?php + +namespace PicoFeed\Syndication; + +use DOMAttr; +use DOMElement; + +/** + * Atom Feed Builder + * + * @package PicoFeed\Syndication + * @author Frederic Guillot + */ +class AtomFeedBuilder extends FeedBuilder +{ + /** + * @var DOMElement + */ + protected $feedElement; + + /** + * @var AtomHelper + */ + protected $helper; + + /** + * Build feed + * + * @access public + * @param string $filename + * @return string + */ + public function build($filename = '') + { + $this->helper = new AtomHelper($this->getDocument()); + + $this->feedElement = $this->getDocument()->createElement('feed'); + $this->feedElement->setAttributeNodeNS(new DomAttr('xmlns', 'http://www.w3.org/2005/Atom')); + + $generator = $this->getDocument()->createElement('generator', 'PicoFeed'); + $generator->setAttribute('uri', 'https://github.com/fguillot/picoFeed'); + $this->feedElement->appendChild($generator); + + $this->helper + ->buildTitle($this->feedElement, $this->feedTitle) + ->buildId($this->feedElement, $this->feedUrl) + ->buildDate($this->feedElement, $this->feedDate) + ->buildLink($this->feedElement, $this->siteUrl) + ->buildLink($this->feedElement, $this->feedUrl, 'self', 'application/atom+xml') + ->buildAuthor($this->feedElement, $this->authorName, $this->authorEmail, $this->authorUrl) + ; + + foreach ($this->items as $item) { + $this->feedElement->appendChild($item->build()); + } + + $this->getDocument()->appendChild($this->feedElement); + + if ($filename !== '') { + $this->getDocument()->save($filename); + } + + return $this->getDocument()->saveXML(); + } +} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomHelper.php b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomHelper.php new file mode 100644 index 0000000..def6b0b --- /dev/null +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomHelper.php @@ -0,0 +1,139 @@ +<?php + +namespace PicoFeed\Syndication; + +use DateTime; +use DOMDocument; +use DOMElement; + +/** + * Class AtomHelper + * + * @package PicoFeed\Syndication + * @author Frederic Guillot + */ +class AtomHelper +{ + /** + * @var DOMDocument + */ + protected $document; + + /** + * Constructor + * + * @param DOMDocument $document + */ + public function __construct(DOMDocument $document) + { + $this->document = $document; + } + + /** + * Build node + * + * @access public + * @param DOMElement $element + * @param string $tag + * @param string $value + * @return AtomHelper + */ + public function buildNode(DOMElement $element, $tag, $value) + { + $node = $this->document->createElement($tag); + $node->appendChild($this->document->createTextNode($value)); + $element->appendChild($node); + return $this; + } + + /** + * Build title + * + * @access public + * @param DOMElement $element + * @param string $title + * @return AtomHelper + */ + public function buildTitle(DOMElement $element, $title) + { + return $this->buildNode($element, 'title', $title); + } + + /** + * Build id + * + * @access public + * @param DOMElement $element + * @param string $id + * @return AtomHelper + */ + public function buildId(DOMElement $element, $id) + { + return $this->buildNode($element, 'id', $id); + } + + /** + * Build date element + * + * @access public + * @param DOMElement $element + * @param DateTime $date + * @param string $type + * @return AtomHelper + */ + public function buildDate(DOMElement $element, DateTime $date, $type = 'updated') + { + return $this->buildNode($element, $type, $date->format(DateTime::ATOM)); + } + + /** + * Build link element + * + * @access public + * @param DOMElement $element + * @param string $url + * @param string $rel + * @param string $type + * @return AtomHelper + */ + public function buildLink(DOMElement $element, $url, $rel = 'alternate', $type = 'text/html') + { + $node = $this->document->createElement('link'); + $node->setAttribute('rel', $rel); + $node->setAttribute('type', $type); + $node->setAttribute('href', $url); + $element->appendChild($node); + + return $this; + } + + /** + * Build author element + * + * @access public + * @param DOMElement $element + * @param string $authorName + * @param string $authorEmail + * @param string $authorUrl + * @return AtomHelper + */ + public function buildAuthor(DOMElement $element, $authorName, $authorEmail, $authorUrl) + { + if (!empty($authorName)) { + $author = $this->document->createElement('author'); + $this->buildNode($author, 'name', $authorName); + + if (!empty($authorEmail)) { + $this->buildNode($author, 'email', $authorEmail); + } + + if (!empty($authorUrl)) { + $this->buildNode($author, 'uri', $authorUrl); + } + + $element->appendChild($author); + } + + return $this; + } +} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php new file mode 100644 index 0000000..dfdfe68 --- /dev/null +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/AtomItemBuilder.php @@ -0,0 +1,63 @@ +<?php + +namespace PicoFeed\Syndication; + +use DOMElement; + +/** + * Atom Item Builder + * + * @package PicoFeed\Syndication + * @author Frederic Guillot + */ +class AtomItemBuilder extends ItemBuilder +{ + /** + * @var DOMElement + */ + protected $itemElement; + + /** + * @var AtomHelper + */ + protected $helper; + + /** + * Build item + * + * @access public + * @return DOMElement + */ + public function build() + { + $this->itemElement = $this->feedBuilder->getDocument()->createElement('entry'); + $this->helper = new AtomHelper($this->feedBuilder->getDocument()); + + if (!empty($this->itemId)) { + $this->helper->buildId($this->itemElement, $this->itemId); + } else { + $this->helper->buildId($this->itemElement, $this->itemUrl); + } + + $this->helper + ->buildTitle($this->itemElement, $this->itemTitle) + ->buildLink($this->itemElement, $this->itemUrl) + ->buildDate($this->itemElement, $this->itemUpdatedDate, 'updated') + ->buildDate($this->itemElement, $this->itemPublishedDate, 'published') + ->buildAuthor($this->itemElement, $this->authorName, $this->authorEmail, $this->authorUrl) + ; + + if (!empty($this->itemSummary)) { + $this->helper->buildNode($this->itemElement, 'summary', $this->itemSummary); + } + + if (!empty($this->itemContent)) { + $node = $this->feedBuilder->getDocument()->createElement('content'); + $node->setAttribute('type', 'html'); + $node->appendChild($this->feedBuilder->getDocument()->createCDATASection($this->itemContent)); + $this->itemElement->appendChild($node); + } + + return $this->itemElement; + } +} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php new file mode 100644 index 0000000..e7bdbc7 --- /dev/null +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/FeedBuilder.php @@ -0,0 +1,185 @@ +<?php + +namespace PicoFeed\Syndication; + +use DateTime; +use DOMDocument; + +/** + * Class FeedBuilder + * + * @package PicoFeed\Syndication + * @author Frederic Guillot + */ +abstract class FeedBuilder +{ + /** + * @var DOMDocument + */ + protected $document; + + /** + * @var string + */ + protected $feedTitle; + + /** + * @var string + */ + protected $feedUrl; + + /** + * @var string + */ + protected $siteUrl; + + /** + * @var string + */ + protected $authorName; + + /** + * @var string + */ + protected $authorEmail; + + /** + * @var string + */ + protected $authorUrl; + + /** + * @var DateTime + */ + protected $feedDate; + + /** + * @var ItemBuilder[] + */ + protected $items; + + /** + * Constructor + * + * @access public + */ + public function __construct() + { + $this->document = new DomDocument('1.0', 'UTF-8'); + $this->document->formatOutput = true; + } + + /** + * Get new object instance + * + * @access public + * @return static + */ + public static function create() + { + return new static(); + } + + /** + * Add feed title + * + * @access public + * @param string $title + * @return $this + */ + public function withTitle($title) + { + $this->feedTitle = $title; + return $this; + } + + /** + * Add feed url + * + * @access public + * @param string $url + * @return $this + */ + public function withFeedUrl($url) + { + $this->feedUrl = $url; + return $this; + } + + /** + * Add website url + * + * @access public + * @param string $url + * @return $this + */ + public function withSiteUrl($url) + { + $this->siteUrl = $url; + return $this; + } + + /** + * Add feed date + * + * @access public + * @param DateTime $date + * @return $this + */ + public function withDate(DateTime $date) + { + $this->feedDate = $date; + return $this; + } + + /** + * Add feed author + * + * @access public + * @param string $name + * @param string $email + * @param string $url + * @return $this + */ + public function withAuthor($name, $email = '', $url ='') + { + $this->authorName = $name; + $this->authorEmail = $email; + $this->authorUrl = $url; + return $this; + } + + /** + * Add feed item + * + * @access public + * @param ItemBuilder $item + * @return $this + */ + public function withItem(ItemBuilder $item) + { + $this->items[] = $item; + return $this; + } + + /** + * Get DOM document + * + * @access public + * @return DOMDocument + */ + public function getDocument() + { + return $this->document; + } + + /** + * Build feed + * + * @abstract + * @access public + * @param string $filename + * @return string + */ + abstract public function build($filename = ''); +} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php new file mode 100644 index 0000000..86985bc --- /dev/null +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/ItemBuilder.php @@ -0,0 +1,209 @@ +<?php + +namespace PicoFeed\Syndication; + +use DateTime; +use DOMElement; + +/** + * Class ItemBuilder + * + * @package PicoFeed\Syndication + * @author Frederic Guillot + */ +abstract class ItemBuilder +{ + /** + * @var string + */ + protected $itemTitle; + + /** + * @var string + */ + protected $itemId; + + /** + * @var string + */ + protected $itemSummary; + + /** + * @var string + */ + protected $authorName; + + /** + * @var string + */ + protected $authorEmail; + + /** + * @var string + */ + protected $authorUrl; + + /** + * @var DateTime + */ + protected $itemPublishedDate; + + /** + * @var DateTime + */ + protected $itemUpdatedDate; + + /** + * @var string + */ + protected $itemContent; + + /** + * @var string + */ + protected $itemUrl; + + /** + * @var FeedBuilder + */ + protected $feedBuilder; + + /** + * Constructor + * + * @param FeedBuilder $feedBuilder + */ + public function __construct(FeedBuilder $feedBuilder) + { + $this->feedBuilder = $feedBuilder; + } + + /** + * Get new object instance + * + * @access public + * @param FeedBuilder $feedBuilder + * @return static + */ + public static function create(FeedBuilder $feedBuilder) + { + return new static($feedBuilder); + } + + /** + * Add item title + * + * @access public + * @param string $title + * @return $this + */ + public function withTitle($title) + { + $this->itemTitle = $title; + return $this; + } + + /** + * Add item id + * + * @access public + * @param string $id + * @return $this + */ + public function withId($id) + { + $this->itemId = $id; + return $this; + } + + /** + * Add item url + * + * @access public + * @param string $url + * @return $this + */ + public function withUrl($url) + { + $this->itemUrl = $url; + return $this; + } + + /** + * Add item summary + * + * @access public + * @param string $summary + * @return $this + */ + public function withSummary($summary) + { + $this->itemSummary = $summary; + return $this; + } + + /** + * Add item content + * + * @access public + * @param string $content + * @return $this + */ + public function withContent($content) + { + $this->itemContent = $content; + return $this; + } + + /** + * Add item updated date + * + * @access public + * @param DateTime $date + * @return $this + */ + public function withUpdatedDate(DateTime $date) + { + $this->itemUpdatedDate = $date; + return $this; + } + + /** + * Add item published date + * + * @access public + * @param DateTime $date + * @return $this + */ + public function withPublishedDate(DateTime $date) + { + $this->itemPublishedDate = $date; + return $this; + } + + /** + * Add item author + * + * @access public + * @param string $name + * @param string $email + * @param string $url + * @return $this + */ + public function withAuthor($name, $email = '', $url ='') + { + $this->authorName = $name; + $this->authorEmail = $email; + $this->authorUrl = $url; + return $this; + } + + /** + * Build item + * + * @abstract + * @access public + * @return DOMElement + */ + abstract public function build(); +} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20.php b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20.php deleted file mode 100644 index 3d0150d..0000000 --- a/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20.php +++ /dev/null @@ -1,206 +0,0 @@ -<?php - -namespace PicoFeed\Syndication; - -use DomDocument; -use DomAttr; -use DomElement; - -/** - * Rss 2.0 writer class. - * - * @author Frederic Guillot - */ -class Rss20 extends Writer -{ - /** - * List of required properties for each feed. - * - * @var array - */ - private $required_feed_properties = array( - 'title', - 'site_url', - 'feed_url', - ); - - /** - * List of required properties for each item. - * - * @var array - */ - private $required_item_properties = array( - 'title', - 'url', - ); - - /** - * Get the Rss 2.0 document. - * - * @param string $filename Optional filename - * - * @return string - */ - public function execute($filename = '') - { - $this->checkRequiredProperties($this->required_feed_properties, $this); - - $this->dom = new DomDocument('1.0', 'UTF-8'); - $this->dom->formatOutput = true; - - // <rss/> - $rss = $this->dom->createElement('rss'); - $rss->setAttribute('version', '2.0'); - $rss->setAttributeNodeNS(new DomAttr('xmlns:content', 'http://purl.org/rss/1.0/modules/content/')); - $rss->setAttributeNodeNS(new DomAttr('xmlns:atom', 'http://www.w3.org/2005/Atom')); - - $channel = $this->dom->createElement('channel'); - - // <generator/> - $generator = $this->dom->createElement('generator', 'PicoFeed (https://github.com/fguillot/picoFeed)'); - $channel->appendChild($generator); - - // <title/> - $title = $this->dom->createElement('title'); - $title->appendChild($this->dom->createTextNode($this->title)); - $channel->appendChild($title); - - // <description/> - $description = $this->dom->createElement('description'); - $description->appendChild($this->dom->createTextNode($this->description ?: $this->title)); - $channel->appendChild($description); - - // <pubDate/> - $this->addPubDate($channel, $this->updated); - - // <atom:link/> - $link = $this->dom->createElement('atom:link'); - $link->setAttribute('href', $this->feed_url); - $link->setAttribute('rel', 'self'); - $link->setAttribute('type', 'application/rss+xml'); - $channel->appendChild($link); - - // <link/> - $link = $this->dom->createElement('link'); - $link->appendChild($this->dom->createTextNode($this->site_url)); - $channel->appendChild($link); - - // <webMaster/> - if (isset($this->author)) { - $this->addAuthor($channel, 'webMaster', $this->author); - } - - // <item/> - foreach ($this->items as $item) { - $this->checkRequiredProperties($this->required_item_properties, $item); - $channel->appendChild($this->createEntry($item)); - } - - $rss->appendChild($channel); - $this->dom->appendChild($rss); - - if ($filename) { - $this->dom->save($filename); - } else { - return $this->dom->saveXML(); - } - } - - /** - * Create item entry. - * - * @param arrray $item Item properties - * - * @return DomElement - */ - public function createEntry(array $item) - { - $entry = $this->dom->createElement('item'); - - // <title/> - $title = $this->dom->createElement('title'); - $title->appendChild($this->dom->createTextNode($item['title'])); - $entry->appendChild($title); - - // <link/> - $link = $this->dom->createElement('link'); - $link->appendChild($this->dom->createTextNode($item['url'])); - $entry->appendChild($link); - - // <guid/> - if (isset($item['id'])) { - $guid = $this->dom->createElement('guid'); - $guid->setAttribute('isPermaLink', 'false'); - $guid->appendChild($this->dom->createTextNode($item['id'])); - $entry->appendChild($guid); - } else { - $guid = $this->dom->createElement('guid'); - $guid->setAttribute('isPermaLink', 'true'); - $guid->appendChild($this->dom->createTextNode($item['url'])); - $entry->appendChild($guid); - } - - // <pubDate/> - $this->addPubDate($entry, isset($item['updated']) ? $item['updated'] : ''); - - // <description/> - if (isset($item['summary'])) { - $description = $this->dom->createElement('description'); - $description->appendChild($this->dom->createTextNode($item['summary'])); - $entry->appendChild($description); - } - - // <content/> - if (isset($item['content'])) { - $content = $this->dom->createElement('content:encoded'); - $content->appendChild($this->dom->createCDATASection($item['content'])); - $entry->appendChild($content); - } - - // <author/> - if (isset($item['author'])) { - $this->addAuthor($entry, 'author', $item['author']); - } - - return $entry; - } - - /** - * Add publication date. - * - * @param DomElement $xml XML node - * @param int $value Timestamp - */ - public function addPubDate(DomElement $xml, $value = 0) - { - $xml->appendChild($this->dom->createElement( - 'pubDate', - date(DATE_RSS, $value ?: time()) - )); - } - - /** - * Add author. - * - * @param DomElement $xml XML node - * @param string $tag Tag name - * @param array $values Author name and email - */ - public function addAuthor(DomElement $xml, $tag, array $values) - { - $value = ''; - - if (isset($values['email'])) { - $value .= $values['email']; - } - if ($value && isset($values['name'])) { - $value .= ' ('.$values['name'].')'; - } - - if ($value) { - $author = $this->dom->createElement($tag); - $author->appendChild($this->dom->createTextNode($value)); - $xml->appendChild($author); - } - } -} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php new file mode 100644 index 0000000..d4ce160 --- /dev/null +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20FeedBuilder.php @@ -0,0 +1,76 @@ +<?php + +namespace PicoFeed\Syndication; + +use DOMAttr; +use DOMElement; + +/** + * Rss20 Feed Builder + * + * @package PicoFeed\Syndication + * @author Frederic Guillot + */ +class Rss20FeedBuilder extends FeedBuilder +{ + /** + * @var DOMElement + */ + protected $rssElement; + + /** + * @var Rss20Helper + */ + protected $helper; + + /** + * @var DOMElement + */ + protected $channelElement; + + /** + * Build feed + * + * @access public + * @param string $filename + * @return string + */ + public function build($filename = '') + { + $this->helper = new Rss20Helper($this->getDocument()); + + $this->rssElement = $this->getDocument()->createElement('rss'); + $this->rssElement->setAttribute('version', '2.0'); + $this->rssElement->setAttributeNodeNS(new DomAttr('xmlns:content', 'http://purl.org/rss/1.0/modules/content/')); + $this->rssElement->setAttributeNodeNS(new DomAttr('xmlns:atom', 'http://www.w3.org/2005/Atom')); + + $this->channelElement = $this->getDocument()->createElement('channel'); + $this->helper + ->buildNode($this->channelElement, 'generator', 'PicoFeed (https://github.com/fguillot/picoFeed)') + ->buildTitle($this->channelElement, $this->feedTitle) + ->buildNode($this->channelElement, 'description', $this->feedTitle) + ->buildDate($this->channelElement, $this->feedDate) + ->buildAuthor($this->channelElement, 'webMaster', $this->authorName, $this->authorEmail) + ->buildLink($this->channelElement, $this->siteUrl) + ; + + $link = $this->getDocument()->createElement('atom:link'); + $link->setAttribute('href', $this->feedUrl); + $link->setAttribute('rel', 'self'); + $link->setAttribute('type', 'application/rss+xml'); + $this->channelElement->appendChild($link); + + foreach ($this->items as $item) { + $this->channelElement->appendChild($item->build()); + } + + $this->rssElement->appendChild($this->channelElement); + $this->getDocument()->appendChild($this->rssElement); + + if ($filename !== '') { + $this->getDocument()->save($filename); + } + + return $this->getDocument()->saveXML(); + } +} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php new file mode 100644 index 0000000..c99688a --- /dev/null +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20Helper.php @@ -0,0 +1,115 @@ +<?php + +namespace PicoFeed\Syndication; + +use DateTime; +use DOMDocument; +use DOMElement; + +/** + * Class Rss20Helper + * + * @package PicoFeed\Syndication + * @author Frederic Guillot + */ +class Rss20Helper +{ + /** + * @var DOMDocument + */ + protected $document; + + /** + * Constructor + * + * @param DOMDocument $document + */ + public function __construct(DOMDocument $document) + { + $this->document = $document; + } + + /** + * Build node + * + * @access public + * @param DOMElement $element + * @param string $tag + * @param string $value + * @return AtomHelper + */ + public function buildNode(DOMElement $element, $tag, $value) + { + $node = $this->document->createElement($tag); + $node->appendChild($this->document->createTextNode($value)); + $element->appendChild($node); + return $this; + } + + /** + * Build title + * + * @access public + * @param DOMElement $element + * @param string $title + * @return AtomHelper + */ + public function buildTitle(DOMElement $element, $title) + { + return $this->buildNode($element, 'title', $title); + } + + /** + * Build date element + * + * @access public + * @param DOMElement $element + * @param DateTime $date + * @param string $type + * @return AtomHelper + */ + public function buildDate(DOMElement $element, DateTime $date, $type = 'pubDate') + { + return $this->buildNode($element, $type, $date->format(DateTime::RSS)); + } + + /** + * Build link element + * + * @access public + * @param DOMElement $element + * @param string $url + * @return AtomHelper + */ + public function buildLink(DOMElement $element, $url) + { + return $this->buildNode($element, 'link', $url); + } + + /** + * Build author element + * + * @access public + * @param DOMElement $element + * @param string $tag + * @param string $authorName + * @param string $authorEmail + * @return AtomHelper + */ + public function buildAuthor(DOMElement $element, $tag, $authorName, $authorEmail) + { + if (!empty($authorName)) { + $value = ''; + + if (!empty($authorEmail)) { + $value .= $authorEmail.' ('.$authorName.')'; + } else { + $value = $authorName; + } + + $this->buildNode($element, $tag, $value); + } + + return $this; + } +} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php new file mode 100644 index 0000000..125dc6a --- /dev/null +++ b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Rss20ItemBuilder.php @@ -0,0 +1,67 @@ +<?php + +namespace PicoFeed\Syndication; + +use DOMElement; + +/** + * Rss20 Item Builder + * + * @package PicoFeed\Syndication + * @author Frederic Guillot + */ +class Rss20ItemBuilder extends ItemBuilder +{ + /** + * @var DOMElement + */ + protected $itemElement; + + /** + * @var Rss20Helper + */ + protected $helper; + + /** + * Build item + * + * @access public + * @return DOMElement + */ + public function build() + { + $this->itemElement = $this->feedBuilder->getDocument()->createElement('item'); + $this->helper = new Rss20Helper($this->feedBuilder->getDocument()); + + if (!empty($this->itemId)) { + $guid = $this->feedBuilder->getDocument()->createElement('guid'); + $guid->setAttribute('isPermaLink', 'false'); + $guid->appendChild($this->feedBuilder->getDocument()->createTextNode($this->itemId)); + $this->itemElement->appendChild($guid); + } else { + $guid = $this->feedBuilder->getDocument()->createElement('guid'); + $guid->setAttribute('isPermaLink', 'true'); + $guid->appendChild($this->feedBuilder->getDocument()->createTextNode($this->itemUrl)); + $this->itemElement->appendChild($guid); + } + + $this->helper + ->buildTitle($this->itemElement, $this->itemTitle) + ->buildLink($this->itemElement, $this->itemUrl) + ->buildDate($this->itemElement, $this->itemPublishedDate) + ->buildAuthor($this->itemElement, 'author', $this->authorName, $this->authorEmail) + ; + + if (!empty($this->itemSummary)) { + $this->helper->buildNode($this->itemElement, 'description', $this->itemSummary); + } + + if (!empty($this->itemContent)) { + $node = $this->feedBuilder->getDocument()->createElement('content:encoded'); + $node->appendChild($this->feedBuilder->getDocument()->createCDATASection($this->itemContent)); + $this->itemElement->appendChild($node); + } + + return $this->itemElement; + } +} diff --git a/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Writer.php b/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Writer.php deleted file mode 100644 index 9312e7e..0000000 --- a/vendor/fguillot/picofeed/lib/PicoFeed/Syndication/Writer.php +++ /dev/null @@ -1,95 +0,0 @@ -<?php - -namespace PicoFeed\Syndication; - -use RuntimeException; - -/** - * Base writer class. - * - * @author Frederic Guillot - */ -abstract class Writer -{ - /** - * Dom object. - * - * @var \DomDocument - */ - protected $dom; - - /** - * Items. - * - * @var array - */ - public $items = array(); - - /** - * Author. - * - * @var array - */ - public $author = array(); - - /** - * Feed URL. - * - * @var string - */ - public $feed_url = ''; - - /** - * Website URL. - * - * @var string - */ - public $site_url = ''; - - /** - * Feed title. - * - * @var string - */ - public $title = ''; - - /** - * Feed description. - * - * @var string - */ - public $description = ''; - - /** - * Feed modification date (timestamp). - * - * @var int - */ - public $updated = 0; - - /** - * Generate the XML document. - * - * @abstract - * - * @param string $filename Optional filename - * - * @return string - */ - abstract public function execute($filename = ''); - - /** - * Check required properties to generate the output. - * - * @param array $properties List of properties - * @param mixed $container Object or array container - */ - public function checkRequiredProperties(array $properties, $container) - { - foreach ($properties as $property) { - if ((is_object($container) && !isset($container->$property)) || (is_array($container) && !isset($container[$property]))) { - throw new RuntimeException('Required property missing: '.$property); - } - } - } -}