1fe9d054bSAndreas Gohr<?php 2fe9d054bSAndreas Gohr 3fe9d054bSAndreas Gohrnamespace dokuwiki\Feed; 4fe9d054bSAndreas Gohr 5fe9d054bSAndreas Gohruse Diff; 6fe9d054bSAndreas Gohruse dokuwiki\ChangeLog\PageChangeLog; 7fe9d054bSAndreas Gohruse TableDiffFormatter; 8fe9d054bSAndreas Gohruse UnifiedDiffFormatter; 9fe9d054bSAndreas Gohr 10fe9d054bSAndreas Gohr/** 11fe9d054bSAndreas Gohr * Accept more or less arbitrary data to represent a page and provide lazy loading accessors 12fe9d054bSAndreas Gohr * to all the data we need for feed generation. 13fe9d054bSAndreas Gohr */ 14fe9d054bSAndreas Gohrclass FeedPageProcessor extends FeedItemProcessor 15fe9d054bSAndreas Gohr{ 16fe9d054bSAndreas Gohr /** @var array[] metadata */ 17fe9d054bSAndreas Gohr protected $meta; 18fe9d054bSAndreas Gohr 19fe9d054bSAndreas Gohr // region data processors 20fe9d054bSAndreas Gohr 21fe9d054bSAndreas Gohr /** @inheritdoc */ 22fe9d054bSAndreas Gohr public function getURL($linkto) 23fe9d054bSAndreas Gohr { 24*093fe67eSAndreas Gohr $opt = match ($linkto) { 25*093fe67eSAndreas Gohr 'page' => ['rev' => $this->getRev()], 26*093fe67eSAndreas Gohr 'rev' => ['rev' => $this->getRev(), 'do' => 'revisions'], 27*093fe67eSAndreas Gohr 'current' => [], 28*093fe67eSAndreas Gohr default => ['rev' => $this->getRev(), 'do' => 'diff'], 29*093fe67eSAndreas Gohr }; 30fe9d054bSAndreas Gohr 31fe9d054bSAndreas Gohr return wl($this->getId(), $opt, true, '&'); 32fe9d054bSAndreas Gohr } 33fe9d054bSAndreas Gohr 34fe9d054bSAndreas Gohr /** @inheritdoc */ 35fe9d054bSAndreas Gohr public function getBody($content) 36fe9d054bSAndreas Gohr { 37fe9d054bSAndreas Gohr global $lang; 38fe9d054bSAndreas Gohr 39fe9d054bSAndreas Gohr switch ($content) { 40fe9d054bSAndreas Gohr case 'diff': 41fe9d054bSAndreas Gohr $diff = $this->getDiff(); 42fe9d054bSAndreas Gohr // note: diff output must be escaped, UnifiedDiffFormatter provides plain text 43fe9d054bSAndreas Gohr $udf = new UnifiedDiffFormatter(); 44fe9d054bSAndreas Gohr return "<pre>\n" . hsc($udf->format($diff)) . "\n</pre>"; 45fe9d054bSAndreas Gohr 46fe9d054bSAndreas Gohr case 'htmldiff': 47fe9d054bSAndreas Gohr $diff = $this->getDiff(); 48fe9d054bSAndreas Gohr // note: no need to escape diff output, TableDiffFormatter provides 'safe' html 49fe9d054bSAndreas Gohr $tdf = new TableDiffFormatter(); 50fe9d054bSAndreas Gohr $content = '<table>'; 51fe9d054bSAndreas Gohr $content .= '<tr><th colspan="2" width="50%">' . dformat($this->getPrev()) . '</th>'; 52fe9d054bSAndreas Gohr $content .= '<th colspan="2" width="50%">' . $lang['current'] . '</th></tr>'; 53fe9d054bSAndreas Gohr $content .= $tdf->format($diff); 54fe9d054bSAndreas Gohr $content .= '</table>'; 55fe9d054bSAndreas Gohr return $content; 56fe9d054bSAndreas Gohr 57fe9d054bSAndreas Gohr case 'html': 58fe9d054bSAndreas Gohr if ($this->isExisting()) { 59fe9d054bSAndreas Gohr $html = p_wiki_xhtml($this->getId(), '', false); 60fe9d054bSAndreas Gohr } else { 61fe9d054bSAndreas Gohr $html = p_wiki_xhtml($this->getId(), $this->getRev(), false); 62fe9d054bSAndreas Gohr } 63fe9d054bSAndreas Gohr return $this->cleanHTML($html); 64fe9d054bSAndreas Gohr 65fe9d054bSAndreas Gohr case 'abstract': 66fe9d054bSAndreas Gohr default: 67fe9d054bSAndreas Gohr return $this->getAbstract(); 68fe9d054bSAndreas Gohr } 69fe9d054bSAndreas Gohr } 70fe9d054bSAndreas Gohr 71fe9d054bSAndreas Gohr /** @inheritdoc */ 72fe9d054bSAndreas Gohr public function getCategory() 73fe9d054bSAndreas Gohr { 74fe9d054bSAndreas Gohr $meta = $this->getMetaData(); 75fe9d054bSAndreas Gohr return (array)($meta['subject'] ?? (string)getNS($this->getId())); 76fe9d054bSAndreas Gohr } 77fe9d054bSAndreas Gohr 78fe9d054bSAndreas Gohr // endregion 79fe9d054bSAndreas Gohr 80fe9d054bSAndreas Gohr // region data accessors 81fe9d054bSAndreas Gohr 82fe9d054bSAndreas Gohr /** 83fe9d054bSAndreas Gohr * Get the page abstract 84fe9d054bSAndreas Gohr * 85fe9d054bSAndreas Gohr * @return string 86fe9d054bSAndreas Gohr */ 87fe9d054bSAndreas Gohr public function getAbstract() 88fe9d054bSAndreas Gohr { 89fe9d054bSAndreas Gohr if (!isset($this->data['abstract'])) { 90fe9d054bSAndreas Gohr $meta = $this->getMetaData(); 91fe9d054bSAndreas Gohr if (isset($meta['description']['abstract'])) { 92fe9d054bSAndreas Gohr $this->data['abstract'] = (string)$meta['description']['abstract']; 93fe9d054bSAndreas Gohr } else { 94fe9d054bSAndreas Gohr $this->data['abstract'] = ''; 95fe9d054bSAndreas Gohr } 96fe9d054bSAndreas Gohr } 97fe9d054bSAndreas Gohr return $this->data['abstract']; 98fe9d054bSAndreas Gohr } 99fe9d054bSAndreas Gohr 100fe9d054bSAndreas Gohr /** @inheritdoc */ 101fe9d054bSAndreas Gohr public function getRev() 102fe9d054bSAndreas Gohr { 103fe9d054bSAndreas Gohr $rev = parent::getRev(); 104fe9d054bSAndreas Gohr if ($rev) return $rev; 105fe9d054bSAndreas Gohr 106fe9d054bSAndreas Gohr if (page_exists($this->id)) { 107fe9d054bSAndreas Gohr $this->data['rev'] = filemtime(wikiFN($this->id)); 108fe9d054bSAndreas Gohr $this->data['exists'] = true; 109fe9d054bSAndreas Gohr } else { 110fe9d054bSAndreas Gohr $this->loadRevisions(); 111fe9d054bSAndreas Gohr } 112fe9d054bSAndreas Gohr return $this->data['rev']; 113fe9d054bSAndreas Gohr } 114fe9d054bSAndreas Gohr 115fe9d054bSAndreas Gohr /** 116fe9d054bSAndreas Gohr * Get the previous revision timestamp of this page 117fe9d054bSAndreas Gohr * 118fe9d054bSAndreas Gohr * @return int|null The previous revision or null if there is none 119fe9d054bSAndreas Gohr */ 120fe9d054bSAndreas Gohr public function getPrev() 121fe9d054bSAndreas Gohr { 122fe9d054bSAndreas Gohr if ($this->data['prev'] ?? 0) return $this->data['prev']; 123fe9d054bSAndreas Gohr $this->loadRevisions(); 124fe9d054bSAndreas Gohr return $this->data['prev']; 125fe9d054bSAndreas Gohr } 126fe9d054bSAndreas Gohr 127fe9d054bSAndreas Gohr /** 128fe9d054bSAndreas Gohr * Does this page exist? 129fe9d054bSAndreas Gohr * 130fe9d054bSAndreas Gohr * @return bool 131fe9d054bSAndreas Gohr */ 132fe9d054bSAndreas Gohr public function isExisting() 133fe9d054bSAndreas Gohr { 134fe9d054bSAndreas Gohr if (!isset($this->data['exists'])) { 135fe9d054bSAndreas Gohr $this->data['exists'] = page_exists($this->id); 136fe9d054bSAndreas Gohr } 137fe9d054bSAndreas Gohr return $this->data['exists']; 138fe9d054bSAndreas Gohr } 139fe9d054bSAndreas Gohr 140fe9d054bSAndreas Gohr /** 141fe9d054bSAndreas Gohr * Get the title of this page 142fe9d054bSAndreas Gohr * 143fe9d054bSAndreas Gohr * @return string 144fe9d054bSAndreas Gohr */ 145fe9d054bSAndreas Gohr public function getTitle() 146fe9d054bSAndreas Gohr { 147fe9d054bSAndreas Gohr global $conf; 148fe9d054bSAndreas Gohr if (!isset($this->data['title'])) { 149fe9d054bSAndreas Gohr if ($conf['useheading']) { 150fe9d054bSAndreas Gohr $this->data['title'] = p_get_first_heading($this->id); 151fe9d054bSAndreas Gohr } else { 152fe9d054bSAndreas Gohr $this->data['title'] = noNS($this->id); 153fe9d054bSAndreas Gohr } 154fe9d054bSAndreas Gohr } 155fe9d054bSAndreas Gohr return $this->data['title']; 156fe9d054bSAndreas Gohr } 157fe9d054bSAndreas Gohr 158fe9d054bSAndreas Gohr // endregion 159fe9d054bSAndreas Gohr 160fe9d054bSAndreas Gohr /** 161fe9d054bSAndreas Gohr * Get the metadata of this page 162fe9d054bSAndreas Gohr * 163fe9d054bSAndreas Gohr * @return array[] 164fe9d054bSAndreas Gohr */ 165fe9d054bSAndreas Gohr protected function getMetaData() 166fe9d054bSAndreas Gohr { 167fe9d054bSAndreas Gohr if (!isset($this->meta)) { 168fe9d054bSAndreas Gohr $this->meta = (array)p_get_metadata($this->id); 169fe9d054bSAndreas Gohr } 170fe9d054bSAndreas Gohr return $this->meta; 171fe9d054bSAndreas Gohr } 172fe9d054bSAndreas Gohr 173fe9d054bSAndreas Gohr /** 174fe9d054bSAndreas Gohr * Load the current and previous revision from the changelog 175fe9d054bSAndreas Gohr * @return void 176fe9d054bSAndreas Gohr */ 177fe9d054bSAndreas Gohr protected function loadRevisions() 178fe9d054bSAndreas Gohr { 179fe9d054bSAndreas Gohr $changelog = new PageChangeLog($this->id); 180389c05a6SAndreas Gohr $revs = $changelog->getRevisions(-1, 2); 181fe9d054bSAndreas Gohr if (!isset($this->data['rev'])) { 182fe9d054bSAndreas Gohr // prefer an already set date, only set if missing 183fe9d054bSAndreas Gohr // it should usally not happen that neither is available 184fe9d054bSAndreas Gohr $this->data['rev'] = $revs[0] ?? 0; 185fe9d054bSAndreas Gohr } 186fe9d054bSAndreas Gohr // a previous revision might not exist 187fe9d054bSAndreas Gohr $this->data['prev'] = $revs[1] ?? null; 188fe9d054bSAndreas Gohr } 189fe9d054bSAndreas Gohr 190fe9d054bSAndreas Gohr /** 191fe9d054bSAndreas Gohr * Get a diff between this and the previous revision 192fe9d054bSAndreas Gohr * 193fe9d054bSAndreas Gohr * @return Diff 194fe9d054bSAndreas Gohr */ 195fe9d054bSAndreas Gohr protected function getDiff() 196fe9d054bSAndreas Gohr { 197fe9d054bSAndreas Gohr $prev = $this->getPrev(); 198fe9d054bSAndreas Gohr 199fe9d054bSAndreas Gohr if ($prev) { 200fe9d054bSAndreas Gohr return new Diff( 201fe9d054bSAndreas Gohr explode("\n", rawWiki($this->getId(), $prev)), 202fe9d054bSAndreas Gohr explode("\n", rawWiki($this->getId(), '')) 203fe9d054bSAndreas Gohr ); 204fe9d054bSAndreas Gohr } 205fe9d054bSAndreas Gohr return new Diff([''], explode("\n", rawWiki($this->getId(), ''))); 206fe9d054bSAndreas Gohr } 207fe9d054bSAndreas Gohr} 208