From adcfd9d02a2fc8e287f6464697d4fa4cc345ea4c Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Mon, 29 Jul 2024 17:10:59 -0400 Subject: [PATCH] Use bind() for result steps --- src/composer.lock | 12 +++--- src/lib/Feed.php | 79 ++++++++++++++++++--------------------- src/lib/ParsedFeed.php | 67 ++++++++++++++++----------------- src/public/feed/index.php | 4 +- 4 files changed, 78 insertions(+), 84 deletions(-) diff --git a/src/composer.lock b/src/composer.lock index a9093bc..938ceeb 100644 --- a/src/composer.lock +++ b/src/composer.lock @@ -8,11 +8,11 @@ "packages": [ { "name": "bit-badger/inspired-by-fsharp", - "version": "v1.0.0-beta1", + "version": "v1.0.0-beta2", "source": { "type": "git", "url": "https://git.bitbadger.solutions/bit-badger/inspired-by-fsharp", - "reference": "efb3a4461edcb23e0dd82068adeb0591240870b0" + "reference": "fad428a4e40b606987499b17bb2d5b7d4b04502d" }, "require": { "php": "^8.2" @@ -49,15 +49,15 @@ "rss": "https://git.bitbadger.solutions/bit-badger/inspired-by-fsharp.rss", "source": "https://git.bitbadger.solutions/bit-badger/inspired-by-fsharp" }, - "time": "2024-07-28T21:35:11+00:00" + "time": "2024-07-29T17:58:33+00:00" }, { "name": "bit-badger/pdo-document", - "version": "v1.0.0-beta8", + "version": "v1.0.0-beta9", "source": { "type": "git", "url": "https://git.bitbadger.solutions/bit-badger/pdo-document", - "reference": "039283224a173bd3e8a9bc5de0caf349ba7b58e6" + "reference": "9e0e663811d9dbbdb94a2c04ce8b874e91a7c85b" }, "require": { "bit-badger/inspired-by-fsharp": "^1", @@ -103,7 +103,7 @@ "rss": "https://git.bitbadger.solutions/bit-badger/pdo-document.rss", "source": "https://git.bitbadger.solutions/bit-badger/pdo-document" }, - "time": "2024-07-29T00:08:44+00:00" + "time": "2024-07-29T20:57:51+00:00" }, { "name": "netresearch/jsonmapper", diff --git a/src/lib/Feed.php b/src/lib/Feed.php index fa56528..682c0fc 100644 --- a/src/lib/Feed.php +++ b/src/lib/Feed.php @@ -175,34 +175,31 @@ class Feed * @param int $feedId The ID of the feed to be refreshed * @param string $url The URL of the feed to be refreshed * @return Result True if successful, an error message if not - * @throws DocumentException If any is encountered */ public static function refreshFeed(int $feedId, string $url): Result { - $tryRetrieve = ParsedFeed::retrieve($url); - if ($tryRetrieve->isError()) return $tryRetrieve; - $feed = $tryRetrieve->getOK(); + return ParsedFeed::retrieve($url) + ->bind(function (ParsedFeed $feed) use ($feedId, $url) { + try { + $feedDoc = Find::byId(Table::Feed, $feedId, self::class); + if ($feedDoc->isNone()) return Result::Error('Could not derive date last checked for feed'); + $lastChecked = date_create_immutable($feedDoc->get()->checked_on ?? WWW_EPOCH); - try { - $feedDoc = Find::byId(Table::Feed, $feedId, self::class); - if ($feedDoc->isNone()) return Result::Error('Could not derive date last checked for feed'); - $lastChecked = date_create_immutable($feedDoc->get()->checked_on ?? WWW_EPOCH); - - $itemUpdate = self::updateItems($feedId, $feed, $lastChecked); - if ($itemUpdate->isError()) return $itemUpdate; - - $patch = [ - 'title' => $feed->title, - 'updated_on' => $feed->updatedOn, - 'checked_on' => Data::formatDate('now') - ]; - if ($url !== $feed->url) $patch['url'] = $feed->url; - Patch::byId(Table::Feed, $feedId, $patch); - } catch (DocumentException $ex) { - return Result::Error("$ex"); - } - - return PURGE_TYPE === self::PurgeNone ? Result::OK(true) : self::purgeItems($feedId); + return self::updateItems($feedId, $feed, $lastChecked) + ->bind(function () use ($feed, $feedId, $url) { + $patch = [ + 'title' => $feed->title, + 'updated_on' => $feed->updatedOn, + 'checked_on' => Data::formatDate('now') + ]; + if ($url !== $feed->url) $patch['url'] = $feed->url; + Patch::byId(Table::Feed, $feedId, $patch); + }) + ->bind(fn() => PURGE_TYPE === self::PurgeNone ? Result::OK(true) : self::purgeItems($feedId)); + } catch (DocumentException $ex) { + return Result::Error("$ex"); + } + }); } /** @@ -213,27 +210,25 @@ class Feed */ public static function add(string $url): Result { - $tryRetrieve = ParsedFeed::retrieve($url); - if ($tryRetrieve->isError()) return $tryRetrieve; - $feed = $tryRetrieve->getOK(); + return ParsedFeed::retrieve($url) + ->bind(function (ParsedFeed $feed) { + try { + $fields = [Field::EQ('user_id', $_SESSION[Key::UserId]), Field::EQ('url', $feed->url)]; + if (Exists::byFields(Table::Feed, $fields)) { + return Result::Error("Already subscribed to feed $feed->url"); + } - try { - $fields = [Field::EQ('user_id', $_SESSION[Key::UserId]), Field::EQ('url', $feed->url)]; - if (Exists::byFields(Table::Feed, $fields)) { - return Result::Error("Already subscribed to feed $feed->url"); - } + Document::insert(Table::Feed, self::fromParsed($feed)); - Document::insert(Table::Feed, self::fromParsed($feed)); + $doc = Find::firstByFields(Table::Feed, $fields, self::class); + if ($doc->isNone()) return Result::Error('Could not retrieve inserted feed'); - $tryDoc = Find::firstByFields(Table::Feed, $fields, self::class); - if ($tryDoc->isNone()) return Result::Error('Could not retrieve inserted feed'); - $doc = $tryDoc->get(); - - $result = self::updateItems($doc->id, $feed, date_create_immutable(WWW_EPOCH)); - return $result->isError() ? $result : Result::OK($doc->id); - } catch (DocumentException $ex) { - return Result::Error("$ex"); - } + return self::updateItems($doc->get()->id, $feed, date_create_immutable(WWW_EPOCH)) + ->bind(fn() => Result::OK($doc->get()->id)); + } catch (DocumentException $ex) { + return Result::Error("$ex"); + } + }); } /** diff --git a/src/lib/ParsedFeed.php b/src/lib/ParsedFeed.php index d538cd8..b113cb2 100644 --- a/src/lib/ParsedFeed.php +++ b/src/lib/ParsedFeed.php @@ -239,39 +239,38 @@ readonly class ParsedFeed */ public static function retrieve(string $url): Result { - $tryDoc = self::retrieveDocument($url); - if ($tryDoc->isError()) return $tryDoc; - - $doc = $tryDoc->getOK(); - if ($doc['code'] !== 200) { - return Result::Error("Prospective feed URL $url returned HTTP Code {$doc['code']}: {$doc['content']}"); - } - - $start = strtolower(strlen($doc['content']) >= 9 ? substr($doc['content'], 0, 9) : $doc['content']); - if ($start === 'isError()) return $derivedURL; - $feedURL = $derivedURL->getOK(); - if (!str_starts_with($feedURL, 'http')) { - // Relative URL; feed should be retrieved in the context of the original URL - $original = parse_url($url); - $port = key_exists('port', $original) ? ":{$original['port']}" : ''; - $feedURL = $original['scheme'] . '://' . $original['host'] . $port . $feedURL; - } - $tryDoc = self::retrieveDocument($feedURL); - if ($tryDoc->isError()) return $tryDoc; - $doc = $tryDoc->getOK(); - if ($doc['code'] !== 200) { - return Result::Error("Derived feed URL $url returned HTTP Code {$doc['code']}: {$doc['content']}"); - } - } - - $tryParse = self::parseFeed($doc['content']); - if ($tryParse->isError()) return $tryParse; - - $parsed = $tryParse->getOK(); - $extract = $parsed->getElementsByTagNameNS(self::ATOM_NS, 'feed')->length > 0 - ? self::fromAtom(...) : self::fromRSS(...); - return $extract($parsed, $doc['url']); + $doc = self::retrieveDocument($url) + ->bind(fn(array $doc) => match ($doc['code']) { + 200 => Result::OK($doc), + default => Result::Error( + "Prospective feed URL $url returned HTTP Code {$doc['code']}: {$doc['content']}"), + }) + ->bind(function (array $doc) use ($url) { + $start = strtolower(strlen($doc['content']) >= 9 ? substr($doc['content'], 0, 9) : $doc['content']); + return $start === 'bind(function (string $feedURL) use ($url) { + if (!str_starts_with($feedURL, 'http')) { + // Relative URL; feed should be retrieved in the context of the original URL + $original = parse_url($url); + $port = key_exists('port', $original) ? ":{$original['port']}" : ''; + $feedURL = $original['scheme'] . '://' . $original['host'] . $port . $feedURL; + } + return self::retrieveDocument($feedURL); + }) + ->bind(fn($doc) => match ($doc['code']) { + 200 => Result::OK($doc), + default => Result::Error( + "Derived feed URL {$doc['url']} returned HTTP Code {$doc['code']}: {$doc['content']}"), + }) + : Result::OK($doc); + }); + return $doc + ->bind(fn($doc) => self::parseFeed($doc['content'])) + ->bind(function (DOMDocument $parsed) use ($doc) { + $extract = $parsed->getElementsByTagNameNS(self::ATOM_NS, 'feed')->length > 0 + ? self::fromAtom(...) : self::fromRSS(...); + return $extract($parsed, $doc['url']); + }); } } diff --git a/src/public/feed/index.php b/src/public/feed/index.php index 5215604..051f73d 100644 --- a/src/public/feed/index.php +++ b/src/public/feed/index.php @@ -44,10 +44,10 @@ switch ($_SERVER['REQUEST_METHOD']) { ? Feed::update($toEdit->get(), $_POST['url']) : Result::Error("Feed $feedId not found"); } - if ($result->isOK()) { + $result->iter(function () { add_info('Feed saved successfully'); frc_redirect('/feeds'); - } + }); add_error($result->getError()); $feedId = 'error'; } catch (DocumentException $ex) {