1fe9d054bSAndreas Gohr<?php 2fe9d054bSAndreas Gohr 3fe9d054bSAndreas Gohrnamespace dokuwiki\Feed; 4fe9d054bSAndreas Gohr 5fe9d054bSAndreas Gohruse dokuwiki\Extension\Event; 6fe9d054bSAndreas Gohr 7fe9d054bSAndreas Gohrclass FeedCreator 8fe9d054bSAndreas Gohr{ 9fe9d054bSAndreas Gohr /** @var \UniversalFeedCreator */ 10fe9d054bSAndreas Gohr protected $feed; 11fe9d054bSAndreas Gohr 12fe9d054bSAndreas Gohr /** @var FeedCreatorOptions */ 13fe9d054bSAndreas Gohr protected $options; 14fe9d054bSAndreas Gohr 15fe9d054bSAndreas Gohr /** 16fe9d054bSAndreas Gohr * @param FeedCreatorOptions $options 17fe9d054bSAndreas Gohr */ 18fe9d054bSAndreas Gohr public function __construct(FeedCreatorOptions $options) 19fe9d054bSAndreas Gohr { 20fe9d054bSAndreas Gohr $this->options = $options; 21fe9d054bSAndreas Gohr 22fe9d054bSAndreas Gohr $this->feed = new \UniversalFeedCreator(); 23fe9d054bSAndreas Gohr $this->feed->title = $this->options->get('title'); 241136941dSAndreas Gohr $this->feed->description = $this->options->get('subtitle'); 25fe9d054bSAndreas Gohr $this->feed->link = DOKU_URL; 26fe9d054bSAndreas Gohr $this->feed->syndicationURL = DOKU_URL . 'feed.php'; 27fe9d054bSAndreas Gohr $this->feed->cssStyleSheet = DOKU_URL . 'lib/exe/css.php?s=feed'; 28fe9d054bSAndreas Gohr 29fe9d054bSAndreas Gohr $this->initLogo(); 30fe9d054bSAndreas Gohr } 31fe9d054bSAndreas Gohr 32fe9d054bSAndreas Gohr /** 33fe9d054bSAndreas Gohr * Build the feed 34fe9d054bSAndreas Gohr * 35fe9d054bSAndreas Gohr * @return string The raw XML for the feed 36fe9d054bSAndreas Gohr */ 37fe9d054bSAndreas Gohr public function build() 38fe9d054bSAndreas Gohr { 39*093fe67eSAndreas Gohr $items = match ($this->options->get('feed_mode')) { 40*093fe67eSAndreas Gohr 'list' => $this->fetchItemsFromNamespace(), 41*093fe67eSAndreas Gohr 'search' => $this->fetchItemsFromSearch(), 42*093fe67eSAndreas Gohr 'recent' => $this->fetchItemsFromRecentChanges(), 43*093fe67eSAndreas Gohr default => $this->fetchItemsFromPlugin(), 44*093fe67eSAndreas Gohr }; 45fe9d054bSAndreas Gohr 4664e1c19bSNickeau $eventData = [ 4764e1c19bSNickeau 'rss' => $this->feed, 4864e1c19bSNickeau 'data' => &$items, 4964e1c19bSNickeau 'opt' => &$this->options->options, 5064e1c19bSNickeau ]; 5164e1c19bSNickeau $event = new Event('FEED_DATA_PROCESS', $eventData); 5264e1c19bSNickeau if ($event->advise_before(false)) { 53fe9d054bSAndreas Gohr foreach ($items as $item) { 54fe9d054bSAndreas Gohr $this->createAndAddItem($item); 55fe9d054bSAndreas Gohr } 5664e1c19bSNickeau } 5764e1c19bSNickeau $event->advise_after(); 58fe9d054bSAndreas Gohr 597e23bd08SAndreas Gohr return $this->feed->createFeed($this->options->getType()); 60fe9d054bSAndreas Gohr } 61fe9d054bSAndreas Gohr 62fe9d054bSAndreas Gohr /** 63fe9d054bSAndreas Gohr * Process the raw data, create feed item and add it to the feed 64fe9d054bSAndreas Gohr * 65fe9d054bSAndreas Gohr * @param array|string $data raw item data 66fe9d054bSAndreas Gohr * @return \FeedItem 67fe9d054bSAndreas Gohr * @triggers FEED_ITEM_ADD 68fe9d054bSAndreas Gohr */ 69fe9d054bSAndreas Gohr protected function createAndAddItem($data) 70fe9d054bSAndreas Gohr { 71fe9d054bSAndreas Gohr if (is_string($data)) { 72fe9d054bSAndreas Gohr $data = ['id' => $data]; 73fe9d054bSAndreas Gohr } 74fe9d054bSAndreas Gohr 75fe9d054bSAndreas Gohr if (($data['mode'] ?? '') == 'media' || isset($data['media'])) { 76fe9d054bSAndreas Gohr $data['id'] = $data['media'] ?? $data['id']; 77fe9d054bSAndreas Gohr $proc = new FeedMediaProcessor($data); 78fe9d054bSAndreas Gohr } else { 79fe9d054bSAndreas Gohr $proc = new FeedPageProcessor($data); 80fe9d054bSAndreas Gohr } 81fe9d054bSAndreas Gohr 82fe9d054bSAndreas Gohr $item = new \FeedItem(); 83fe9d054bSAndreas Gohr $item->title = $proc->getTitle(); 84fe9d054bSAndreas Gohr if ($this->options->get('show_summary') && $proc->getSummary()) { 85fe9d054bSAndreas Gohr $item->title .= ' - ' . $proc->getSummary(); 86fe9d054bSAndreas Gohr } 874554d54dSAndreas Gohr $item->date = $proc->getRev(); 88fe9d054bSAndreas Gohr [$item->authorEmail, $item->author] = $proc->getAuthor(); 89fe9d054bSAndreas Gohr $item->link = $proc->getURL($this->options->get('link_to')); 90fe9d054bSAndreas Gohr $item->description = $proc->getBody($this->options->get('item_content')); 91fe9d054bSAndreas Gohr 92fe9d054bSAndreas Gohr $evdata = [ 93fe9d054bSAndreas Gohr 'item' => $item, 94fe9d054bSAndreas Gohr 'opt' => &$this->options->options, 95fe9d054bSAndreas Gohr 'ditem' => &$data, 96fe9d054bSAndreas Gohr 'rss' => $this->feed, 97fe9d054bSAndreas Gohr ]; 98fe9d054bSAndreas Gohr 99fe9d054bSAndreas Gohr $evt = new Event('FEED_ITEM_ADD', $evdata); 100fe9d054bSAndreas Gohr if ($evt->advise_before()) { 101fe9d054bSAndreas Gohr $this->feed->addItem($item); 102fe9d054bSAndreas Gohr } 103fe9d054bSAndreas Gohr $evt->advise_after(); 104fe9d054bSAndreas Gohr 105fe9d054bSAndreas Gohr return $item; 106fe9d054bSAndreas Gohr } 107fe9d054bSAndreas Gohr 108fe9d054bSAndreas Gohr /** 109fe9d054bSAndreas Gohr * Read all pages from a namespace 110fe9d054bSAndreas Gohr * 111fe9d054bSAndreas Gohr * @todo this currently does not honor the rss_media setting and only ever lists pages 112fe9d054bSAndreas Gohr * @return array 113fe9d054bSAndreas Gohr */ 114fe9d054bSAndreas Gohr protected function fetchItemsFromNamespace() 115fe9d054bSAndreas Gohr { 116fe9d054bSAndreas Gohr global $conf; 117fe9d054bSAndreas Gohr 118fe9d054bSAndreas Gohr $ns = ':' . cleanID($this->options->get('namespace')); 119fe9d054bSAndreas Gohr $ns = utf8_encodeFN(str_replace(':', '/', $ns)); 12072c714a3Ssplitbrain 121fe9d054bSAndreas Gohr $data = []; 122fe9d054bSAndreas Gohr $search_opts = [ 123fe9d054bSAndreas Gohr 'depth' => 1, 124fe9d054bSAndreas Gohr 'pagesonly' => true, 125fe9d054bSAndreas Gohr 'listfiles' => true 126fe9d054bSAndreas Gohr ]; 127fe9d054bSAndreas Gohr search( 128fe9d054bSAndreas Gohr $data, 129fe9d054bSAndreas Gohr $conf['datadir'], 130fe9d054bSAndreas Gohr 'search_universal', 131fe9d054bSAndreas Gohr $search_opts, 132fe9d054bSAndreas Gohr $ns, 133fe9d054bSAndreas Gohr $lvl = 1, 134fe9d054bSAndreas Gohr $this->options->get('sort') 135fe9d054bSAndreas Gohr ); 136fe9d054bSAndreas Gohr 137fe9d054bSAndreas Gohr return $data; 138fe9d054bSAndreas Gohr } 139fe9d054bSAndreas Gohr 140fe9d054bSAndreas Gohr /** 141fe9d054bSAndreas Gohr * Add the result of a full text search to the feed object 142fe9d054bSAndreas Gohr * 143fe9d054bSAndreas Gohr * @return array 144fe9d054bSAndreas Gohr */ 145fe9d054bSAndreas Gohr protected function fetchItemsFromSearch() 146fe9d054bSAndreas Gohr { 147fe9d054bSAndreas Gohr if (!actionOK('search')) throw new \RuntimeException('search is disabled'); 148fe9d054bSAndreas Gohr if (!$this->options->get('search_query')) return []; 149fe9d054bSAndreas Gohr 150fe9d054bSAndreas Gohr $data = ft_pageSearch($this->options->get('search_query'), $poswords); 151fe9d054bSAndreas Gohr return array_keys($data); 152fe9d054bSAndreas Gohr } 153fe9d054bSAndreas Gohr 154fe9d054bSAndreas Gohr /** 155fe9d054bSAndreas Gohr * Add recent changed pages to the feed object 156fe9d054bSAndreas Gohr * 157fe9d054bSAndreas Gohr * @return array 158fe9d054bSAndreas Gohr */ 159fe9d054bSAndreas Gohr protected function fetchItemsFromRecentChanges() 160fe9d054bSAndreas Gohr { 161fe9d054bSAndreas Gohr global $conf; 162fe9d054bSAndreas Gohr $flags = 0; 163fe9d054bSAndreas Gohr if (!$this->options->get('show_deleted')) $flags += RECENTS_SKIP_DELETED; 164fe9d054bSAndreas Gohr if (!$this->options->get('show_minor')) $flags += RECENTS_SKIP_MINORS; 165fe9d054bSAndreas Gohr if ($this->options->get('only_new')) $flags += RECENTS_ONLY_CREATION; 166fe9d054bSAndreas Gohr if ($this->options->get('content_type') == 'media' && $conf['mediarevisions']) { 167fe9d054bSAndreas Gohr $flags += RECENTS_MEDIA_CHANGES; 168fe9d054bSAndreas Gohr } 169fe9d054bSAndreas Gohr if ($this->options->get('content_type') == 'both' && $conf['mediarevisions']) { 170fe9d054bSAndreas Gohr $flags += RECENTS_MEDIA_PAGES_MIXED; 171fe9d054bSAndreas Gohr } 172fe9d054bSAndreas Gohr 173fe9d054bSAndreas Gohr return getRecents(0, $this->options->get('items'), $this->options->get('namespace'), $flags); 174fe9d054bSAndreas Gohr } 175fe9d054bSAndreas Gohr 176fe9d054bSAndreas Gohr /** 177fe9d054bSAndreas Gohr * Add items from a plugin to the feed object 178fe9d054bSAndreas Gohr * 179fe9d054bSAndreas Gohr * @triggers FEED_MODE_UNKNOWN 180fe9d054bSAndreas Gohr * @return array 181fe9d054bSAndreas Gohr */ 182fe9d054bSAndreas Gohr protected function fetchItemsFromPlugin() 183fe9d054bSAndreas Gohr { 184fe9d054bSAndreas Gohr $eventData = [ 185fe9d054bSAndreas Gohr 'opt' => $this->options->options, 186fe9d054bSAndreas Gohr 'data' => [], 187fe9d054bSAndreas Gohr ]; 188fe9d054bSAndreas Gohr $event = new Event('FEED_MODE_UNKNOWN', $eventData); 189fe9d054bSAndreas Gohr if ($event->advise_before(true)) { 190fe9d054bSAndreas Gohr throw new \RuntimeException('unknown feed mode'); 191fe9d054bSAndreas Gohr } 192fe9d054bSAndreas Gohr $event->advise_after(); 193fe9d054bSAndreas Gohr 194fe9d054bSAndreas Gohr return $eventData['data']; 195fe9d054bSAndreas Gohr } 196fe9d054bSAndreas Gohr 197fe9d054bSAndreas Gohr /** 198fe9d054bSAndreas Gohr * Add a logo to the feed 199fe9d054bSAndreas Gohr * 200fe9d054bSAndreas Gohr * Looks at different possible candidates for a logo and adds the first one 201fe9d054bSAndreas Gohr * 202fe9d054bSAndreas Gohr * @return void 203fe9d054bSAndreas Gohr */ 204fe9d054bSAndreas Gohr protected function initLogo() 205fe9d054bSAndreas Gohr { 206fe9d054bSAndreas Gohr global $conf; 207fe9d054bSAndreas Gohr 208fe9d054bSAndreas Gohr $this->feed->image = new \FeedImage(); 209fe9d054bSAndreas Gohr $this->feed->image->title = $conf['title']; 210fe9d054bSAndreas Gohr $this->feed->image->link = DOKU_URL; 211fe9d054bSAndreas Gohr $this->feed->image->url = tpl_getMediaFile([ 212fe9d054bSAndreas Gohr ':wiki:logo.svg', 213fe9d054bSAndreas Gohr ':logo.svg', 214fe9d054bSAndreas Gohr ':wiki:logo.png', 215fe9d054bSAndreas Gohr ':logo.png', 216fe9d054bSAndreas Gohr ':wiki:logo.jpg', 217fe9d054bSAndreas Gohr ':logo.jpg', 218fe9d054bSAndreas Gohr ':wiki:favicon.ico', 219fe9d054bSAndreas Gohr ':favicon.ico', 220cf9a4884SAndreas Gohr ':wiki:dokuwiki.svg', 221cf9a4884SAndreas Gohr ':wiki:dokuwiki-128.png', 222fe9d054bSAndreas Gohr 'images/favicon.ico' 223fe9d054bSAndreas Gohr ], true); 224fe9d054bSAndreas Gohr } 225fe9d054bSAndreas Gohr} 226