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