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