From d63edf541f77a736715039ec6689b01193993c7b Mon Sep 17 00:00:00 2001 From: "J. King" Date: Fri, 29 Mar 2019 09:02:39 -0400 Subject: [PATCH] Insert folders into OPML before subscriptions --- lib/ImportExport/OPML.php | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/ImportExport/OPML.php b/lib/ImportExport/OPML.php index e3053a0..032d753 100644 --- a/lib/ImportExport/OPML.php +++ b/lib/ImportExport/OPML.php @@ -10,9 +10,10 @@ use JKingWeb\Arsse\Arsse; class OPML { public function export(string $user, bool $flat = false): string { + $tags = []; $folders = []; $parents = [0 => null]; - $tags = []; + // create a base document $document = new \DOMDocument("1.0", "utf-8"); $document->formatOutput = true; $document->appendChild($document->createElement("opml")); @@ -20,10 +21,13 @@ class OPML { $document->documentElement->appendChild($document->createElement("head")); // create the "root folder" node (the body node, in OPML terms) $folders[0] = $document->createElement("body"); + // begin a transaction for read isolation $transaction = Arsse::$db->begin(); + // gather up the list of tags for each subscription foreach (Arsse::$db->tagSummarize($user) as $r) { $sub = $r['subscription']; $tag = $r['name']; + // strip out any commas in the tag name; sadly this is lossy as OPML has no escape mechanism $tag = str_replace(",", "", $tag); if (!isset($tags[$sub])) { $tags[$sub] = []; @@ -31,28 +35,36 @@ class OPML { $tags[$sub][] = $tag; } if (!$flat) { + // unless the output is requested flat, gather up the list of folders, using their database IDs as array indices foreach (Arsse::$db->folderList($user) as $r) { + // note the index of its parent folder for later tree construction $parents[$r['id']] = $r['parent'] ?? 0; + // create a DOM node for each folder; we don't insert it yet $el = $document->createElement("outline"); $el->setAttribute("text", $r['name']); $folders[$r['id']] = $el; } + // insert each folder into its parent node; for the root folder the parent is the document root node + foreach ($folders as $id => $el) { + $parent = $parents[$id] ?? $document->documentElement; + $parent->appendChild($el); + } } + // create a DOM node for each subscription and insert them directly into their folder DOM node foreach (Arsse::$db->subscriptionList($user) as $r) { $el = $document->createElement(("outline")); $el->setAttribute("text", $r['title']); $el->setAttribute("type", "rss"); $el->setAttribute("xmlUrl", $r['url']); + // include the category attribute only if there are tags if (sizeof($tags[$r['id']])) { $el->setAttribute("category", implode(",", $tags[$r['id']])); } + // if flat output was requested subscriptions are inserted into the root folder ($folders[$r['folder'] ?? 0] ?? $folders[0])->appendChild($el); } + // release the transaction $transaction->rollback(); - foreach ($folders as $id => $el) { - $parent = $parents[$id] ?? $document->documentElement; - $parent->appendChild($el); - } // return the serialization return $document->saveXML(); }