From 1742fb65c53a2a6cd6a310d225add25ee20c14b6 Mon Sep 17 00:00:00 2001 From: wn_ Date: Tue, 10 Dec 2024 18:58:17 +0000 Subject: [PATCH 1/8] Use the spread operator instead of 'array_merge' in more places. PHP 8.1 introduced support for merging string-key arrays (last array with a wins). --- classes/DiskCache.php | 7 +++++-- classes/PluginHost.php | 24 ++++++++++-------------- include/controls.php | 6 +++--- include/controls_compat.php | 30 +++++++++++++----------------- 4 files changed, 31 insertions(+), 36 deletions(-) diff --git a/classes/DiskCache.php b/classes/DiskCache.php index 249079b36..c52759a75 100644 --- a/classes/DiskCache.php +++ b/classes/DiskCache.php @@ -301,8 +301,11 @@ class DiskCache implements Cache_Adapter { if ($this->exists($local_filename) && !$force) return true; - $data = UrlHelper::fetch(array_merge(["url" => $url, - "max_size" => Config::get(Config::MAX_CACHE_FILE_SIZE)], $options)); + $data = UrlHelper::fetch([ + 'url' => $url, + 'max_size' => Config::get(Config::MAX_CACHE_FILE_SIZE), + ...$options, + ]); if ($data) return $this->put($local_filename, $data) > 0; diff --git a/classes/PluginHost.php b/classes/PluginHost.php index cc81bc9c0..9a8fa32c2 100644 --- a/classes/PluginHost.php +++ b/classes/PluginHost.php @@ -851,14 +851,12 @@ class PluginHost { */ function get_method_url(Plugin $sender, string $method, array $params = []): string { return Config::get_self_url() . "/backend.php?" . - http_build_query( - array_merge( - [ - "op" => "pluginhandler", - "plugin" => strtolower(get_class($sender)), - "method" => $method - ], - $params)); + http_build_query([ + 'op' => 'pluginhandler', + 'plugin' => strtolower(get_class($sender)), + 'method' => $method, + ...$params, + ]); } // shortcut syntax (disabled for now) @@ -880,12 +878,10 @@ class PluginHost { function get_public_method_url(Plugin $sender, string $method, array $params = []): ?string { if ($sender->is_public_method($method)) { return Config::get_self_url() . "/public.php?" . - http_build_query( - array_merge( - [ - "op" => strtolower(get_class($sender) . self::PUBLIC_METHOD_DELIMITER . $method), - ], - $params)); + http_build_query([ + 'op' => strtolower(get_class($sender) . self::PUBLIC_METHOD_DELIMITER . $method), + ...$params, + ]); } user_error("get_public_method_url: requested method '$method' of '" . get_class($sender) . "' is private."); return null; diff --git a/include/controls.php b/include/controls.php index 5c6174e3d..8932dd048 100755 --- a/include/controls.php +++ b/include/controls.php @@ -56,21 +56,21 @@ * @param array $attributes */ function number_spinner_tag(string $name, string $value, array $attributes = [], string $id = ""): string { - return input_tag($name, $value, "text", array_merge(["dojoType" => "dijit.form.NumberSpinner"], $attributes), $id); + return input_tag($name, $value, 'text', ['dojoType' => 'dijit.form.NumberSpinner', ...$attributes], $id); } /** * @param array $attributes */ function submit_tag(string $value, array $attributes = []): string { - return button_tag($value, "submit", array_merge(["class" => "alt-primary"], $attributes)); + return button_tag($value, 'submit', ['class' => 'alt-primary', ...$attributes]); } /** * @param array $attributes */ function cancel_dialog_tag(string $value, array $attributes = []): string { - return button_tag($value, "", array_merge(["onclick" => "App.dialogOf(this).hide()"], $attributes)); + return button_tag($value, '', ['onclick' => 'App.dialogOf(this).hide()', ...$attributes]); } /** diff --git a/include/controls_compat.php b/include/controls_compat.php index 5a2a9f2ba..d22f7fc3c 100644 --- a/include/controls_compat.php +++ b/include/controls_compat.php @@ -5,15 +5,13 @@ */ function stylesheet_tag(string $filename, array $attributes = []): string { - $attributes_str = \Controls\attributes_to_string( - array_merge( - [ - "href" => "$filename?" . filemtime($filename), - "rel" => "stylesheet", - "type" => "text/css", - "data-orig-href" => $filename - ], - $attributes)); + $attributes_str = \Controls\attributes_to_string([ + 'href' => "$filename?" . filemtime($filename), + 'rel' => 'stylesheet', + 'type' => 'text/css', + 'data-orig-href' => $filename, + ...$attributes, + ]); return "\n"; } @@ -22,14 +20,12 @@ function stylesheet_tag(string $filename, array $attributes = []): string { * @param array $attributes */ function javascript_tag(string $filename, array $attributes = []): string { - $attributes_str = \Controls\attributes_to_string( - array_merge( - [ - "src" => "$filename?" . filemtime($filename), - "type" => "text/javascript", - "charset" => "utf-8" - ], - $attributes)); + $attributes_str = \Controls\attributes_to_string([ + 'src' => "$filename?" . filemtime($filename), + 'type' => 'text/javascript', + 'charset' => 'utf-8', + ...$attributes, + ]); return "\n"; } From 333bab90a7d4d159d001e3f0579b10cced763249 Mon Sep 17 00:00:00 2001 From: wn_ Date: Tue, 10 Dec 2024 19:25:26 +0000 Subject: [PATCH 2/8] Remove use of 'ReturnTypeWillChange'. 'ReturnTypeWillChange' was a workaround needed until we reached PHP 8.0, which introduced union types and allowed alignment with 'SessionHandlerInterface'. --- classes/Sessions.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/classes/Sessions.php b/classes/Sessions.php index c54815b0f..330790eeb 100644 --- a/classes/Sessions.php +++ b/classes/Sessions.php @@ -53,7 +53,6 @@ class Sessions implements \SessionHandlerInterface { return true; } - #[\ReturnTypeWillChange] public function read(string $id): false|string { $sth = Db::pdo()->prepare('SELECT data FROM ttrss_sessions WHERE id=?'); $sth->execute([$id]); @@ -93,7 +92,6 @@ class Sessions implements \SessionHandlerInterface { /** * @return int|false the number of deleted sessions on success, or false on failure */ - #[\ReturnTypeWillChange] public function gc(int $max_lifetime): false|int { $result = Db::pdo()->query('DELETE FROM ttrss_sessions WHERE expire < ' . time()); return $result === false ? false : $result->rowCount(); From a1bd6cea1bbb3041ee8e2ba44a80cd2ea0b8209f Mon Sep 17 00:00:00 2001 From: wn_ Date: Tue, 10 Dec 2024 20:31:16 +0000 Subject: [PATCH 3/8] Use native typing in more places and clean up 'FeedEnclosure' a bit. --- classes/API.php | 3 +- classes/Config.php | 10 +++--- classes/Db.php | 9 ++---- classes/DiskCache.php | 5 ++- classes/FeedEnclosure.php | 26 +++++---------- classes/FeedItem_Atom.php | 10 +++--- classes/FeedItem_Common.php | 61 ++++++++++++++--------------------- classes/FeedItem_RSS.php | 16 ++++----- classes/FeedParser.php | 22 +++++-------- classes/Logger.php | 6 ++-- classes/Pref_Filters.php | 2 +- classes/Prefs.php | 8 ++--- tests/integration/ApiTest.php | 8 ++--- 13 files changed, 71 insertions(+), 115 deletions(-) diff --git a/classes/API.php b/classes/API.php index 31a3bec97..241663b3d 100644 --- a/classes/API.php +++ b/classes/API.php @@ -14,8 +14,7 @@ class API extends Handler { const E_OPERATION_FAILED = "E_OPERATION_FAILED"; const E_NOT_FOUND = "E_NOT_FOUND"; - /** @var int|null */ - private $seq; + private ?int $seq = null; /** * @param array $reply diff --git a/classes/Config.php b/classes/Config.php index 9d671215a..356f81391 100644 --- a/classes/Config.php +++ b/classes/Config.php @@ -252,17 +252,15 @@ class Config { Config::HTTP_429_THROTTLE_INTERVAL => [ 3600, Config::T_INT ] ]; - /** @var Config|null */ - private static $instance; + private static ?Config $instance = null; /** @var array> */ - private $params = []; + private array $params = []; /** @var array */ - private $version = []; + private array $version = []; - /** @var Db_Migrations|null $migrations */ - private $migrations; + private Db_Migrations $migrations; public static function get_instance() : Config { if (self::$instance == null) diff --git a/classes/Db.php b/classes/Db.php index 4331b662e..2d8511258 100644 --- a/classes/Db.php +++ b/classes/Db.php @@ -1,11 +1,8 @@ $instances */ - private static $instances = []; + private static array $instances = []; /** * https://stackoverflow.com/a/53662733 diff --git a/classes/FeedEnclosure.php b/classes/FeedEnclosure.php index b5f5cc411..6ef9bca5e 100644 --- a/classes/FeedEnclosure.php +++ b/classes/FeedEnclosure.php @@ -1,21 +1,11 @@ xpath->evaluate("string(ancestor-or-self::*[@xml:base][1]/@xml:base)", $link); if ($link->getAttribute("rel") == "enclosure") { - $enc = new FeedEnclosure(); - - $enc->type = clean($link->getAttribute("type")); - $enc->length = clean($link->getAttribute("length")); - $enc->link = clean($link->getAttribute("href")); + $enc = new FeedEnclosure( + type: clean($link->getAttribute('type')), + length: clean($link->getAttribute('length')), + link: clean($link->getAttribute('href')), + ); if (!empty($base)) { $enc->link = UrlHelper::rewrite_relative($base, $enc->link); diff --git a/classes/FeedItem_Common.php b/classes/FeedItem_Common.php index 1471dc3e3..5b30ab20c 100644 --- a/classes/FeedItem_Common.php +++ b/classes/FeedItem_Common.php @@ -1,19 +1,10 @@ elem = $elem; - $this->xpath = $xpath; - $this->doc = $doc; - + function __construct( + protected readonly DOMElement $elem, + protected readonly DOMDocument $doc, + protected readonly DOMXPath $xpath, + ) { try { $source = $elem->getElementsByTagName("source")->item(0); @@ -97,13 +88,13 @@ abstract class FeedItem_Common extends FeedItem { $enclosures = $this->xpath->query("media:content", $this->elem); foreach ($enclosures as $enclosure) { - $enc = new FeedEnclosure(); - - $enc->type = clean($enclosure->getAttribute("type")); - $enc->link = clean($enclosure->getAttribute("url")); - $enc->length = clean($enclosure->getAttribute("length")); - $enc->height = clean($enclosure->getAttribute("height")); - $enc->width = clean($enclosure->getAttribute("width")); + $enc = new FeedEnclosure( + type: clean($enclosure->getAttribute('type')), + link: clean($enclosure->getAttribute('url')), + length: clean($enclosure->getAttribute('length')), + height: clean($enclosure->getAttribute('height')), + width: clean($enclosure->getAttribute('width')), + ); $medium = clean($enclosure->getAttribute("medium")); if (!$enc->type && $medium) { @@ -119,17 +110,17 @@ abstract class FeedItem_Common extends FeedItem { $enclosures = $this->xpath->query("media:group", $this->elem); foreach ($enclosures as $enclosure) { - $enc = new FeedEnclosure(); - /** @var DOMElement|null */ $content = $this->xpath->query("media:content", $enclosure)->item(0); if ($content) { - $enc->type = clean($content->getAttribute("type")); - $enc->link = clean($content->getAttribute("url")); - $enc->length = clean($content->getAttribute("length")); - $enc->height = clean($content->getAttribute("height")); - $enc->width = clean($content->getAttribute("width")); + $enc = new FeedEnclosure( + type: clean($content->getAttribute('type')), + link: clean($content->getAttribute('url')), + length: clean($content->getAttribute('length')), + height: clean($content->getAttribute('height')), + width: clean($content->getAttribute('width')), + ); $medium = clean($content->getAttribute("medium")); if (!$enc->type && $medium) { @@ -151,14 +142,12 @@ abstract class FeedItem_Common extends FeedItem { $enclosures = $this->xpath->query("media:thumbnail", $this->elem); foreach ($enclosures as $enclosure) { - $enc = new FeedEnclosure(); - - $enc->type = "image/generic"; - $enc->link = clean($enclosure->getAttribute("url")); - $enc->height = clean($enclosure->getAttribute("height")); - $enc->width = clean($enclosure->getAttribute("width")); - - array_push($encs, $enc); + $encs[] = new FeedEnclosure( + type: 'image/generic', + link: clean($enclosure->getAttribute('url')), + height: clean($enclosure->getAttribute('height')), + width: clean($enclosure->getAttribute('width')), + ); } return $encs; diff --git a/classes/FeedItem_RSS.php b/classes/FeedItem_RSS.php index ab1764577..2970e43bd 100644 --- a/classes/FeedItem_RSS.php +++ b/classes/FeedItem_RSS.php @@ -141,15 +141,13 @@ class FeedItem_RSS extends FeedItem_Common { $encs = array(); foreach ($enclosures as $enclosure) { - $enc = new FeedEnclosure(); - - $enc->type = clean($enclosure->getAttribute("type")); - $enc->link = clean($enclosure->getAttribute("url")); - $enc->length = clean($enclosure->getAttribute("length")); - $enc->height = clean($enclosure->getAttribute("height")); - $enc->width = clean($enclosure->getAttribute("width")); - - array_push($encs, $enc); + $encs[] = new FeedEnclosure( + type: clean($enclosure->getAttribute('type')), + link: clean($enclosure->getAttribute('url')), + length: clean($enclosure->getAttribute('length')), + height: clean($enclosure->getAttribute('height')), + width: clean($enclosure->getAttribute('width')), + ); } array_push($encs, ...parent::get_enclosures()); diff --git a/classes/FeedParser.php b/classes/FeedParser.php index c288ffc91..fd26226ae 100644 --- a/classes/FeedParser.php +++ b/classes/FeedParser.php @@ -1,29 +1,23 @@ */ - private $libxml_errors = []; + private array $libxml_errors = []; /** @var array */ - private $items = []; + private array $items = []; - /** @var string|null */ - private $link; + private ?string $link = null; - /** @var string|null */ - private $title; + private ?string $title = null; /** @var FeedParser::FEED_*|null */ - private $type; + private ?int $type = null; - /** @var DOMXPath|null */ - private $xpath; + private ?DOMXPath $xpath = null; const FEED_UNKNOWN = -1; const FEED_RDF = 0; diff --git a/classes/Logger.php b/classes/Logger.php index 049b63d5e..05a117a0b 100644 --- a/classes/Logger.php +++ b/classes/Logger.php @@ -1,10 +1,8 @@ > $action_descriptions */ - private $action_descriptions = []; + private array $action_descriptions = []; function before(string $method) : bool { diff --git a/classes/Prefs.php b/classes/Prefs.php index f7e6e39c0..08f402d40 100644 --- a/classes/Prefs.php +++ b/classes/Prefs.php @@ -144,14 +144,12 @@ class Prefs { Prefs::_PREFS_MIGRATED ]; - /** @var Prefs|null */ - private static $instance; + private static ?Prefs $instance = null; /** @var array */ - private $cache = []; + private array $cache = []; - /** @var PDO */ - private $pdo; + private ?PDO $pdo = null; public static function get_instance() : Prefs { if (self::$instance == null) diff --git a/tests/integration/ApiTest.php b/tests/integration/ApiTest.php index 4b47ec4b0..65c3828f6 100644 --- a/tests/integration/ApiTest.php +++ b/tests/integration/ApiTest.php @@ -3,12 +3,8 @@ use PHPUnit\Framework\TestCase; /** @group integration */ final class ApiTest extends TestCase { - - /** @var string */ - private $api_url; - - /** @var string */ - private $sid; + private string $api_url; + private string $sid; function __construct() { $this->api_url = getenv('API_URL'); From 57dd754e07ecc7a4cf551568f0b2c4448c246b84 Mon Sep 17 00:00:00 2001 From: wn_ Date: Tue, 10 Dec 2024 20:42:38 +0000 Subject: [PATCH 4/8] Use a native DNF type for 'PluginHost->get_feed_handler()'. --- classes/PluginHost.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/classes/PluginHost.php b/classes/PluginHost.php index 9a8fa32c2..e40cf86ad 100644 --- a/classes/PluginHost.php +++ b/classes/PluginHost.php @@ -784,10 +784,8 @@ class PluginHost { /** * convert feed_id (e.g. -129) to pfeed_id first - * - * @return (Plugin&IVirtualFeed)|null */ - function get_feed_handler(int $pfeed_id): ?Plugin { + function get_feed_handler(int $pfeed_id): (Plugin&IVirtualFeed)|null { foreach ($this->feeds as $cat) { foreach ($cat as $feed) { if ($feed['id'] == $pfeed_id) { From 18b17cbc839026ecb99c2b044e401c2032626df7 Mon Sep 17 00:00:00 2001 From: wn_ Date: Sun, 15 Dec 2024 13:39:54 +0000 Subject: [PATCH 5/8] Revert some stuff based upon feedback --- classes/FeedEnclosure.php | 14 +++++----- classes/FeedItem_Atom.php | 9 +++---- classes/FeedItem_Common.php | 53 ++++++++++++++++++++----------------- classes/FeedItem_RSS.php | 15 ++++++----- classes/PluginHost.php | 3 ++- 5 files changed, 48 insertions(+), 46 deletions(-) diff --git a/classes/FeedEnclosure.php b/classes/FeedEnclosure.php index 6ef9bca5e..1e53de2e8 100644 --- a/classes/FeedEnclosure.php +++ b/classes/FeedEnclosure.php @@ -1,11 +1,9 @@ xpath->evaluate("string(ancestor-or-self::*[@xml:base][1]/@xml:base)", $link); if ($link->getAttribute("rel") == "enclosure") { - $enc = new FeedEnclosure( - type: clean($link->getAttribute('type')), - length: clean($link->getAttribute('length')), - link: clean($link->getAttribute('href')), - ); + $enc = new FeedEnclosure(); + $enc->type = clean($link->getAttribute('type')); + $enc->length = clean($link->getAttribute('length')); + $enc->link = clean($link->getAttribute('href')); if (!empty($base)) { $enc->link = UrlHelper::rewrite_relative($base, $enc->link); diff --git a/classes/FeedItem_Common.php b/classes/FeedItem_Common.php index 5b30ab20c..5ec958699 100644 --- a/classes/FeedItem_Common.php +++ b/classes/FeedItem_Common.php @@ -1,10 +1,14 @@ elem = $elem; + $this->doc = $doc; + $this->xpath = $xpath; + try { $source = $elem->getElementsByTagName("source")->item(0); @@ -88,13 +92,12 @@ abstract class FeedItem_Common extends FeedItem { $enclosures = $this->xpath->query("media:content", $this->elem); foreach ($enclosures as $enclosure) { - $enc = new FeedEnclosure( - type: clean($enclosure->getAttribute('type')), - link: clean($enclosure->getAttribute('url')), - length: clean($enclosure->getAttribute('length')), - height: clean($enclosure->getAttribute('height')), - width: clean($enclosure->getAttribute('width')), - ); + $enc = new FeedEnclosure(); + $enc->type = clean($enclosure->getAttribute('type')); + $enc->link = clean($enclosure->getAttribute('url')); + $enc->length = clean($enclosure->getAttribute('length')); + $enc->height = clean($enclosure->getAttribute('height')); + $enc->width = clean($enclosure->getAttribute('width')); $medium = clean($enclosure->getAttribute("medium")); if (!$enc->type && $medium) { @@ -114,13 +117,12 @@ abstract class FeedItem_Common extends FeedItem { $content = $this->xpath->query("media:content", $enclosure)->item(0); if ($content) { - $enc = new FeedEnclosure( - type: clean($content->getAttribute('type')), - link: clean($content->getAttribute('url')), - length: clean($content->getAttribute('length')), - height: clean($content->getAttribute('height')), - width: clean($content->getAttribute('width')), - ); + $enc = new FeedEnclosure(); + $enc->type = clean($content->getAttribute('type')); + $enc->link = clean($content->getAttribute('url')); + $enc->length = clean($content->getAttribute('length')); + $enc->height = clean($content->getAttribute('height')); + $enc->width = clean($content->getAttribute('width')); $medium = clean($content->getAttribute("medium")); if (!$enc->type && $medium) { @@ -142,12 +144,13 @@ abstract class FeedItem_Common extends FeedItem { $enclosures = $this->xpath->query("media:thumbnail", $this->elem); foreach ($enclosures as $enclosure) { - $encs[] = new FeedEnclosure( - type: 'image/generic', - link: clean($enclosure->getAttribute('url')), - height: clean($enclosure->getAttribute('height')), - width: clean($enclosure->getAttribute('width')), - ); + $enc = new FeedEnclosure(); + $enc->type = 'image/generic'; + $enc->link = clean($enclosure->getAttribute('url')); + $enc->height = clean($enclosure->getAttribute('height')); + $enc->width = clean($enclosure->getAttribute('width')); + + array_push($encs, $enc); } return $encs; diff --git a/classes/FeedItem_RSS.php b/classes/FeedItem_RSS.php index 2970e43bd..6e1435310 100644 --- a/classes/FeedItem_RSS.php +++ b/classes/FeedItem_RSS.php @@ -141,13 +141,14 @@ class FeedItem_RSS extends FeedItem_Common { $encs = array(); foreach ($enclosures as $enclosure) { - $encs[] = new FeedEnclosure( - type: clean($enclosure->getAttribute('type')), - link: clean($enclosure->getAttribute('url')), - length: clean($enclosure->getAttribute('length')), - height: clean($enclosure->getAttribute('height')), - width: clean($enclosure->getAttribute('width')), - ); + $enc = new FeedEnclosure(); + $enc->type = clean($enclosure->getAttribute('type')); + $enc->link = clean($enclosure->getAttribute('url')); + $enc->length = clean($enclosure->getAttribute('length')); + $enc->height = clean($enclosure->getAttribute('height')); + $enc->width = clean($enclosure->getAttribute('width')); + + array_push($encs, $enc); } array_push($encs, ...parent::get_enclosures()); diff --git a/classes/PluginHost.php b/classes/PluginHost.php index e40cf86ad..97d0c45c7 100644 --- a/classes/PluginHost.php +++ b/classes/PluginHost.php @@ -784,8 +784,9 @@ class PluginHost { /** * convert feed_id (e.g. -129) to pfeed_id first + * @return (Plugin&IVirtualFeed)|null */ - function get_feed_handler(int $pfeed_id): (Plugin&IVirtualFeed)|null { + function get_feed_handler(int $pfeed_id): ?Plugin { foreach ($this->feeds as $cat) { foreach ($cat as $feed) { if ($feed['id'] == $pfeed_id) { From 62a6191f04e37cc9b40fcf3e713563ed51722e95 Mon Sep 17 00:00:00 2001 From: wn_ Date: Sun, 15 Dec 2024 13:43:49 +0000 Subject: [PATCH 6/8] Deal with FeedEnclosure property accessed before initialization. --- classes/FeedEnclosure.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/classes/FeedEnclosure.php b/classes/FeedEnclosure.php index 1e53de2e8..10dd2ae33 100644 --- a/classes/FeedEnclosure.php +++ b/classes/FeedEnclosure.php @@ -1,9 +1,9 @@ Date: Sun, 15 Dec 2024 16:09:40 +0000 Subject: [PATCH 7/8] Clean up some virtual feed stuff in PluginHost. Among other things, this makes 'PluginHost->add_feed()' return false if the feed was not added. --- classes/PluginHost.php | 57 ++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/classes/PluginHost.php b/classes/PluginHost.php index 97d0c45c7..bccf2ecc8 100644 --- a/classes/PluginHost.php +++ b/classes/PluginHost.php @@ -23,8 +23,8 @@ class PluginHost { /** @var array> plugin name -> (potential profile array) -> key -> value */ private array $storage = []; - /** @var array> */ - private array $feeds = []; + /** @var array */ + private array $special_feeds = []; /** @var array API method name, Plugin sender */ private array $api_methods = []; @@ -759,44 +759,51 @@ class PluginHost { } } - // Plugin feed functions are *EXPERIMENTAL*! + /** + * Add a special (plugin-provided) feed + * + * @param int $cat_id only -1 (Feeds::CATEGORY_SPECIAL) is supported + * @return false|positive-int false if $cat_id was not -1 (Feeds::CATEGORY_SPECIAL), + * otherwise a positive integer ID that might change between executions + */ + function add_feed(int $cat_id, string $title, string $icon, Plugin $sender): false|int { + if ($cat_id !== Feeds::CATEGORY_SPECIAL) + return false; - // cat_id: only -1 (Feeds::CATEGORY_SPECIAL) is supported (Special) - function add_feed(int $cat_id, string $title, string $icon, Plugin $sender): int { + $id = count($this->special_feeds); - if (empty($this->feeds[$cat_id])) - $this->feeds[$cat_id] = []; - - $id = count($this->feeds[$cat_id]); - - array_push($this->feeds[$cat_id], - ['id' => $id, 'title' => $title, 'sender' => $sender, 'icon' => $icon]); + $this->special_feeds[] = [ + 'id' => $id, + 'title' => $title, + 'sender' => $sender, + 'icon' => $icon, + ]; return $id; } /** + * Get special (plugin-provided) feeds + * + * @param int $cat_id only -1 (Feeds::CATEGORY_SPECIAL) is supported * @return array */ function get_feeds(int $cat_id) { - return $this->feeds[$cat_id] ?? []; + return $cat_id === Feeds::CATEGORY_SPECIAL ? $this->special_feeds : []; } /** - * convert feed_id (e.g. -129) to pfeed_id first - * @return (Plugin&IVirtualFeed)|null + * Get the Plugin handling a specific virtual feed. + * + * Convert feed_id (e.g. -129) to pfeed_id first. + * + * @return (Plugin&IVirtualFeed)|null a Plugin that implements IVirtualFeed, otherwise null */ function get_feed_handler(int $pfeed_id): ?Plugin { - foreach ($this->feeds as $cat) { - foreach ($cat as $feed) { - if ($feed['id'] == $pfeed_id) { - if (implements_interface($feed['sender'], 'IVirtualFeed')) { - /** @var Plugin&IVirtualFeed $feed['sender'] */ - return $feed['sender']; - } else { - return null; - } - } + foreach ($this->special_feeds as $feed) { + if ($feed['id'] == $pfeed_id) { + /** @var Plugin&IVirtualFeed $feed['sender'] */ + return implements_interface($feed['sender'], 'IVirtualFeed') ? $feed['sender'] : null; } } return null; From 6f8f1b30d508dc3d2c3a067ca7fe2d161963ef5f Mon Sep 17 00:00:00 2001 From: wn_ Date: Sun, 15 Dec 2024 16:41:45 +0000 Subject: [PATCH 8/8] minor PHPDoc cleanup in PluginHost --- classes/PluginHost.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/classes/PluginHost.php b/classes/PluginHost.php index bccf2ecc8..5f1d97f53 100644 --- a/classes/PluginHost.php +++ b/classes/PluginHost.php @@ -763,8 +763,8 @@ class PluginHost { * Add a special (plugin-provided) feed * * @param int $cat_id only -1 (Feeds::CATEGORY_SPECIAL) is supported - * @return false|positive-int false if $cat_id was not -1 (Feeds::CATEGORY_SPECIAL), - * otherwise a positive integer ID that might change between executions + * @return false|int false if the feed wasn't added (e.g. $cat_id wasn't Feeds::CATEGORY_SPECIAL), + * otherwise an integer "feed ID" that might change between executions */ function add_feed(int $cat_id, string $title, string $icon, Plugin $sender): false|int { if ($cat_id !== Feeds::CATEGORY_SPECIAL)