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