xref: /dokuwiki/inc/Feed/FeedPageProcessor.php (revision fe9d054b302adfcd4618e9e33079c36cccb90d10)
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