xref: /dokuwiki/inc/Ui/Diff.php (revision e49fa56bf2db001a4fefcb366d1e886f4cfe66f6)
1<?php
2
3namespace dokuwiki\Ui;
4
5use dokuwiki\ChangeLog\ChangeLog;
6
7/**
8 * DokuWiki Diff Interface
9 * parent class of PageDiff and MediaDiff
10 *
11 * @package dokuwiki\Ui
12 */
13abstract class Diff extends Ui
14{
15    /* @var string */
16    protected $id;   // page id or media id
17    protected $item; // page or media
18
19    /* @var int|string */
20    protected $oldRev;  // timestamp of older revision, '' means current one
21    protected $newRev;  // timestamp of newer revision, '' means current one
22
23    /* @var array */
24    protected $preference = [];
25
26    /* @var ChangeLog */
27    protected $changelog; // PageChangeLog or MediaChangeLog object
28
29    /**
30     * Diff Ui constructor
31     *
32     * @param string $id  page id or media id
33     */
34    public function __construct($id)
35    {
36        $this->id = $id;
37        $this->setChangeLog();
38    }
39
40    /**
41     * set class property changelog
42     */
43    abstract protected function setChangeLog();
44
45    /**
46     * item filename resolver
47     *
48     * @param string $id  page id or media id
49     * @param int|string $rev revision timestamp, or empty string for current one
50     * @return string full path
51     */
52    abstract protected function itemFN($id, $rev = '');
53
54    /**
55     * Set a pair of revisions to be compared
56     *
57     * @param int $oldRev
58     * @param int $newRev
59     * @return $this
60     */
61    public function compare($oldRev, $newRev)
62    {
63        $this->oldRev = $oldRev;
64        $this->newRev = $newRev;
65        return $this;
66    }
67
68    /**
69     * Gets or Sets preference of the Ui\Diff object
70     *
71     * @param string|array $prefs  a key name or key-value pair(s)
72     * @param mixed $value         value used when the first args is string
73     * @return array|$this
74     */
75    public function preference($prefs = null, $value = null)
76    {
77        // set
78        if (is_string($prefs) && isset($value)) {
79            $this->preference[$prefs] = $value;
80            return $this;
81        } elseif (is_array($prefs)) {
82            foreach ($prefs as $name => $value) {
83                $this->preference[$name] = $value;
84            }
85            return $this;
86        }
87        // get
88        return $this->preference;
89    }
90
91    /**
92     * Retrieve requested revision(s) and difftype from Ui\Revisions
93     *
94     * @return void
95     */
96    protected function preProcess()
97    {
98        global $INPUT;
99
100        // difflink icon click, eg. ?rev=123456789&do=diff
101        if ($INPUT->has('rev')) {
102            $this->oldRev = $INPUT->int('rev');
103            $this->newRev = ''; // current revision
104        }
105
106        // submit button with two checked boxes
107        $rev2 = $INPUT->arr('rev2', []);
108        if (count($rev2) > 1) {
109            if ($rev2[0] == 'current') {
110                [$this->oldRev, $this->newRev] = [$rev2[1], ''];
111            } elseif ($rev2[1] == 'current') {
112                [$this->oldRev, $this->newRev] = [$rev2[0], ''];
113            } elseif ($rev2[0] < $rev2[1]) {
114                [$this->oldRev, $this->newRev] = [$rev2[0], $rev2[1]];
115            } else {
116                [$this->oldRev, $this->newRev] = [$rev2[1], $rev2[0]];
117            }
118        }
119
120        // diff view type
121        if ($INPUT->has('difftype')) {
122            // retrieve requested $difftype
123            $this->preference['difftype'] = $INPUT->str('difftype');
124        } else {
125            // read preference from DokuWiki cookie. PageDiff only
126            $mode = get_doku_pref('difftype', $mode = null);
127            if (isset($mode)) $this->preference['difftype'] = $mode;
128        }
129    }
130
131    /**
132     * get extended revision info
133     *
134     * @param int|string $rev  revision identifier, '' means current one, null means
135     * @return array  revision info structure of a page or media file
136     */
137    protected function getExtendedRevisionInfo($rev)
138    {
139        $changelog =& $this->changelog;
140
141        if ($rev) {
142            $info = $changelog->getRevisionInfo($rev);
143            //if external deletion, rev 9999999999 was used.
144            $info = is_array($info) ? $info : ($changelog->getExternalEditRevInfo() ?: []);
145        } elseif ($rev === null) { //if do=diff at just created page
146            $info = [
147                'none' => true
148            ];
149        } elseif (file_exists($filename = $this->itemFN($this->id))) {
150            $rev = filemtime(fullpath($filename));
151            $info = $changelog->getRevisionInfo($rev);
152            // if external edit, file exist but has no changelog line
153            $info = is_array($info) ? $info : ($changelog->getExternalEditRevInfo() ?: []);
154            $info = $info + [
155                'current' => true
156            ];
157        } else { // once exists, but now removed
158            $lastRev = $changelog->getRevisions(-1, 1); // from changelog
159            $lastRev = (int) (empty($lastRev) ? 0 : $lastRev[0]);
160            $info = $changelog->getRevisionInfo($lastRev);
161            if (!(is_array($info) && $info['type'] == DOKU_CHANGE_TYPE_DELETE)) {
162                $info = $changelog->getExternalEditRevInfo();
163                $info = is_array($info) && $info['type'] == DOKU_CHANGE_TYPE_DELETE ? $info : [];
164            }
165            $info = $info + [
166                'current' => true
167            ];
168        }
169        return ['item' => $this->item] + $info;
170    }
171
172
173
174    /**
175     * Build header of diff HTML
176     *
177     * @param string $l_rev   Left revisions
178     * @param string $r_rev   Right revision
179     * @return string[] HTML snippets for diff header
180     * @deprecated 2020-12-31
181     */
182    public function buildDiffHead($l_rev, $r_rev)
183    {
184        dbg_deprecated('not used see '. \dokuwiki\Ui\PageDiff::class .'::show()');
185    }
186
187}
188