Failed Conditions
Pull Request — master (#3198)
by
unknown
03:03
created

Diff::show()   F

Complexity

Conditions 24
Paths 13824

Size

Total Lines 191

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 24
nc 13824
nop 0
dl 0
loc 191
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace dokuwiki\Ui;
4
5
use dokuwiki\ChangeLog\PageChangeLog;
6
use dokuwiki\ChangeLog\MediaChangeLog;
7
use dokuwiki\Extension\Event;
8
use dokuwiki\Form\Form;
9
10
/**
11
 * DokuWiki Diff Interface
12
 *
13
 * @package dokuwiki\Ui
14
 */
15
class Diff extends Ui
16
{
17
    protected $text;
18
    protected $showIntro;
19
    protected $diffType;
20
21
    /** 
22
     * Diff Ui constructor
23
     *
24
     * @param  string $text  when non-empty: compare with this text with most current version
25
     * @param  bool   $showIntro display the intro text
26
     * @param  string $diffType  type of the diff (inline or sidebyside)
27
     */
28
    public function __construct($text = '', $showIntro = true, $diffType = null)
29
    {
30
        $this->text      = $text;
31
        $this->showIntro = $showIntro;
32
        $this->diffType  = $diffType;
33
    }
34
35
    /**
36
     * Show diff
37
     * between current page version and provided $text
38
     * or between the revisions provided via GET or POST
39
     *
40
     * @author Andreas Gohr <[email protected]>
41
     *
42
     * @return void
43
     */
44
    public function show()
45
    {
46
        global $ID;
47
        global $REV;
48
        global $lang;
49
        global $INPUT;
50
        global $INFO;
51
        $pagelog = new PageChangeLog($ID);
52
53
        /*
54
         * Determine diff type
55
         */
56
        if ($this->diffType === null) {
0 ignored issues
show
Bug introduced by
The property diffType  does not seem to exist. Did you mean diffType?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
57
            $this->diffType = $INPUT->str('difftype');
58
            if (empty($this->difftype)) {
0 ignored issues
show
Bug introduced by
The property difftype does not seem to exist. Did you mean diffType?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
59
                $this->diffType = get_doku_pref('difftype', $this->diffType);
60
                if (empty($this->diffType) && $INFO['ismobile']) {
61
                    $this->diffType = 'inline';
62
                }
63
            }
64
        }
65
        if ($this->diffType != 'inline') $this->diffType = 'sidebyside';
66
67
        /*
68
         * Determine requested revision(s)
69
         */
70
        // we're trying to be clever here, revisions to compare can be either
71
        // given as rev and rev2 parameters, with rev2 being optional. Or in an
72
        // array in rev2.
73
        $rev1 = $REV;
74
75
        $rev2 = $INPUT->ref('rev2');
76
        if (is_array($rev2)) {
77
            $rev1 = (int) $rev2[0];
78
            $rev2 = (int) $rev2[1];
79
80
            if (!$rev1) {
81
                $rev1 = $rev2;
82
                unset($rev2);
83
            }
84
        } else {
85
            $rev2 = $INPUT->int('rev2');
86
        }
87
88
        /*
89
         * Determine left and right revision, its texts and the header
90
         */
91
        $r_minor = '';
92
        $l_minor = '';
93
94
        if ($this->text) { // compare text to the most current revision
95
            $l_rev = '';
96
            $l_text = rawWiki($ID, '');
97
            $l_head = '<a class="wikilink1" href="'. wl($ID) .'">'
98
                . $ID .' '. dformat((int) @filemtime(wikiFN($ID))) .'</a> '
99
                . $lang['current'];
100
101
            $r_rev = '';
102
            $r_text = cleanText($this->text);
103
            $r_head = $lang['yours'];
104
        } else {
105
            if ($rev1 && isset($rev2) && $rev2) { // two specific revisions wanted
106
                // make sure order is correct (older on the left)
107
                if ($rev1 < $rev2) {
108
                    $l_rev = $rev1;
109
                    $r_rev = $rev2;
110
                } else {
111
                    $l_rev = $rev2;
112
                    $r_rev = $rev1;
113
                }
114
            } elseif ($rev1) { // single revision given, compare to current
115
                $r_rev = '';
116
                $l_rev = $rev1;
117
            } else { // no revision was given, compare previous to current
118
                $r_rev = '';
119
                $revs = $pagelog->getRevisions(0, 1);
120
                $l_rev = $revs[0];
121
                $REV = $l_rev; // store revision back in $REV
122
            }
123
124
            // when both revisions are empty then the page was created just now
125
            if (!$l_rev && !$r_rev) {
126
                $l_text = '';
127
            } else {
128
                $l_text = rawWiki($ID, $l_rev);
129
            }
130
            $r_text = rawWiki($ID, $r_rev);
131
132
            list($l_head, $r_head, $l_minor, $r_minor) = $this->diffHead(
133
                $l_rev, $r_rev, null, false, ($this->diffType == 'inline')
134
            );
135
        }
136
137
        /*
138
         * Build navigation
139
         */
140
        $l_nav = '';
141
        $r_nav = '';
142
        if (!$this->text) {
143
            list($l_nav, $r_nav) = $this->diffNavigation($pagelog, $this->diffType, $l_rev, $r_rev);
144
        }
145
        /*
146
         * Create diff object and the formatter
147
         */
148
        $diff = new \Diff(explode("\n", $l_text), explode("\n", $r_text));
149
150
        if ($this->diffType == 'inline') {
151
            $diffformatter = new \InlineDiffFormatter();
152
        } else {
153
            $diffformatter = new \TableDiffFormatter();
154
        }
155
        /*
156
         * Display intro
157
         */
158
        if ($this->showIntro) print p_locale_xhtml('diff');
159
160
        /*
161
         * Display type and exact reference
162
         */
163
        if (!$this->text) {
164
            print '<div class="diffoptions group">';
165
166
            // create the form to select diff view type
167
            $form = new Form(['action' => wl()]);
168
            $form->setHiddenField('id', $ID);
169
            $form->setHiddenField('rev2[0]', $l_rev);
170
            $form->setHiddenField('rev2[1]', $r_rev);
171
            $form->setHiddenField('do', 'diff');
172
            $options = array(
173
                         'sidebyside' => $lang['diff_side'],
174
                         'inline' => $lang['diff_inline']
175
            );
176
            $input = $form->addDropdown('difftype', $options, $lang['diff_type'])
177
                ->val($this->diffType)->addClass('quickselect');
178
            $input->useInput(false); // inhibit prefillInput() during toHTML() process
179
            $form->addButton('do[diff]', 'Go')->attr('type','submit');
180
            print $form->toHTML();
181
182
            print '<p>';
183
            // link to exactly this view FS#2835
184
            print $this->diffViewlink($this->diffType, 'difflink', $l_rev, $r_rev ? $r_rev : $INFO['currentrev']);
185
            print '</p>';
186
187
            print '</div>'; // .diffoptions
188
        }
189
190
        /*
191
         * Display diff view table
192
         */
193
        print '<div class="table">';
194
        print '<table class="diff diff_'. $this->diffType .'">';
195
196
        //navigation and header
197
        if ($this->diffType == 'inline') {
198
            if (!$this->text) {
199
                print '<tr>'
200
                    . '<td class="diff-lineheader">-</td>'
201
                    . '<td class="diffnav">'. $l_nav .'</td>'
202
                    . '</tr>';
203
                print '<tr>'
204
                    . '<th class="diff-lineheader">-</th>'
205
                    . '<th '. $l_minor .'>'. $l_head .'</th>'
206
                    .'</tr>';
207
            }
208
            print '<tr>'
209
                . '<td class="diff-lineheader">+</td>'
210
                . '<td class="diffnav">'. $r_nav .'</td>'
211
                .'</tr>';
212
            print '<tr>'
213
                . '<th class="diff-lineheader">+</th>'
214
                . '<th '. $r_minor .'>'. $r_head .'</th>'
215
                . '</tr>';
216
        } else {
217
            if (!$this->text) {
218
                print '<tr>'
219
                    . '<td colspan="2" class="diffnav">'. $l_nav .'</td>'
220
                    . '<td colspan="2" class="diffnav">'. $r_nav .'</td>'
221
                    . '</tr>';
222
            }
223
            print '<tr>'
224
                . '<th colspan="2" '. $l_minor .'>'. $l_head .'</th>'
225
                . '<th colspan="2" '. $r_minor .'>'. $r_head .'</th>'
226
                . '</tr>';
227
        }
228
229
        //diff view
230
        print html_insert_softbreaks($diffformatter->format($diff));
231
232
        print '</table>';
233
        print '</div>'. DOKU_LF;
234
    }
235
236
237
    /**
238
     * Get header of diff HTML
239
     *
240
     * @param string $l_rev   Left revisions
241
     * @param string $r_rev   Right revision
242
     * @param string $id      Page id, if null $ID is used
243
     * @param bool   $media   If it is for media files
244
     * @param bool   $inline  Return the header on a single line
245
     * @return string[] HTML snippets for diff header
246
     */
247
    protected function diffHead($l_rev, $r_rev, $id = null, $media = false, $inline = false)
248
    {
249
        global $lang;
250
        if ($id === null) {
251
            global $ID;
252
            $id = $ID;
253
        }
254
        $head_separator = $inline ? ' ' : '<br />';
255
        $media_or_wikiFN = $media ? 'mediaFN' : 'wikiFN';
256
        $ml_or_wl = $media ? 'ml' : 'wl';
257
        $l_minor = $r_minor = '';
258
259
        if ($media) {
260
            $changelog = new MediaChangeLog($id);
261
        } else {
262
            $changelog = new PageChangeLog($id);
263
        }
264
        if (!$l_rev) {
265
            $l_head = '&mdash;';
266
        } else {
267
            $l_info   = $changelog->getRevisionInfo($l_rev);
268
            if ($l_info['user']) {
269
                $l_user = '<bdi>'.editorinfo($l_info['user']).'</bdi>';
270
                if (auth_ismanager()) $l_user .= ' <bdo dir="ltr">('.$l_info['ip'].')</bdo>';
271
            } else {
272
                $l_user = '<bdo dir="ltr">'.$l_info['ip'].'</bdo>';
273
            }
274
            $l_user  = '<span class="user">'.$l_user.'</span>';
275
            $l_sum   = ($l_info['sum']) ? '<span class="sum"><bdi>'.hsc($l_info['sum']).'</bdi></span>' : '';
276
            if ($l_info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) $l_minor = 'class="minor"';
277
278
            $l_head_title = ($media) ? dformat($l_rev) : $id.' ['.dformat($l_rev).']';
279
            $l_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id,"rev=$l_rev").'">'
280
                . $l_head_title.'</a></bdi>'.$head_separator.$l_user.' '.$l_sum;
281
        }
282
283
        if ($r_rev) {
284
            $r_info   = $changelog->getRevisionInfo($r_rev);
285
            if ($r_info['user']) {
286
                $r_user = '<bdi>'.editorinfo($r_info['user']).'</bdi>';
287
                if (auth_ismanager()) $r_user .= ' <bdo dir="ltr">('.$r_info['ip'].')</bdo>';
288
            } else {
289
                $r_user = '<bdo dir="ltr">'.$r_info['ip'].'</bdo>';
290
            }
291
            $r_user = '<span class="user">'.$r_user.'</span>';
292
            $r_sum  = ($r_info['sum']) ? '<span class="sum"><bdi>'.hsc($r_info['sum']).'</bdi></span>' : '';
293
            if ($r_info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"';
294
295
            $r_head_title = ($media) ? dformat($r_rev) : $id.' ['.dformat($r_rev).']';
296
            $r_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id,"rev=$r_rev").'">'
297
                . $r_head_title.'</a></bdi>'.$head_separator.$r_user.' '.$r_sum;
298
        } elseif ($_rev = @filemtime($media_or_wikiFN($id))) {
299
            $_info   = $changelog->getRevisionInfo($_rev);
300
            if ($_info['user']) {
301
                $_user = '<bdi>'.editorinfo($_info['user']).'</bdi>';
302
                if (auth_ismanager()) $_user .= ' <bdo dir="ltr">('.$_info['ip'].')</bdo>';
303
            } else {
304
                $_user = '<bdo dir="ltr">'.$_info['ip'].'</bdo>';
305
            }
306
            $_user = '<span class="user">'.$_user.'</span>';
307
            $_sum  = ($_info['sum']) ? '<span class="sum"><bdi>'.hsc($_info['sum']).'</span></bdi>' : '';
308
            if ($_info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"';
309
310
            $r_head_title = ($media) ? dformat($_rev) : $id.' ['.dformat($_rev).']';
311
            $r_head  = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id).'">'
312
                . $r_head_title.'</a></bdi> '.'('.$lang['current'].')'.$head_separator.$_user.' '.$_sum;
313
        }else{
314
            $r_head = '&mdash; ('.$lang['current'].')';
315
        }
316
317
        return array($l_head, $r_head, $l_minor, $r_minor);
318
    }
319
320
    /**
321
     * Create html for revision navigation
322
     *
323
     * @param PageChangeLog $pagelog changelog object of current page
324
     * @param string        $type    inline vs sidebyside
325
     * @param int           $l_rev   left revision timestamp
326
     * @param int           $r_rev   right revision timestamp
327
     * @return string[] html of left and right navigation elements
328
     */
329
    protected function diffNavigation($pagelog, $type, $l_rev, $r_rev)
330
    {
331
        global $INFO, $ID;
332
333
        // last timestamp is not in changelog, retrieve timestamp from metadata
334
        // note: when page is removed, the metadata timestamp is zero
335
        if (!$r_rev) {
336
            if (isset($INFO['meta']['last_change']['date'])) {
337
                $r_rev = $INFO['meta']['last_change']['date'];
338
            } else {
339
                $r_rev = 0;
340
            }
341
        }
342
343
        //retrieve revisions with additional info
344
        list($l_revs, $r_revs) = $pagelog->getRevisionsAround($l_rev, $r_rev);
345
        $l_revisions = array();
346
        if (!$l_rev) {
347
            //no left revision given, add dummy
348
            $l_revisions[0]= array('label' => '', 'attrs' => []);
349
        }
350
        foreach ($l_revs as $rev) {
351
            $info = $pagelog->getRevisionInfo($rev);
352
            $l_revisions[$rev] = array(
353
                'label' => dformat($info['date']) .' '. editorinfo($info['user'], true) .' '. $info['sum'],
354
                'attrs' => ['title' => $rev],
355
            );
356
            if ($r_rev ? $rev >= $r_rev : false) $l_revisions[$rev]['attrs']['disabled'] = 'disabled';
357
        }
358
        $r_revisions = array();
359
        if (!$r_rev) {
360
            //no right revision given, add dummy
361
            $r_revisions[0] = array('label' => '', 'attrs' => []);
362
        }
363
        foreach ($r_revs as $rev) {
364
            $info = $pagelog->getRevisionInfo($rev);
365
            $r_revisions[$rev] = array(
366
                'label' => dformat($info['date']) .' '. editorinfo($info['user'], true) .' '. $info['sum'],
367
                'attrs' => ['title' => $rev],
368
            );
369
            if ($rev <= $l_rev) $r_revisions[$rev]['attrs']['disabled'] = 'disabled';
370
        }
371
372
        //determine previous/next revisions
373
        $l_index = array_search($l_rev, $l_revs);
374
        $l_prev = $l_revs[$l_index + 1];
375
        $l_next = $l_revs[$l_index - 1];
376
        if ($r_rev) {
377
            $r_index = array_search($r_rev, $r_revs);
378
            $r_prev = $r_revs[$r_index + 1];
379
            $r_next = $r_revs[$r_index - 1];
380
        } else {
381
            //removed page
382
            if ($l_next) {
383
                $r_prev = $r_revs[0];
384
            } else {
385
                $r_prev = null;
386
            }
387
            $r_next = null;
388
        }
389
390
        /*
391
         * Left side:
392
         */
393
        $l_nav = '';
394
        //move back
395
        if ($l_prev) {
396
            $l_nav .= $this->diffViewlink($type, 'diffbothprevrev', $l_prev, $r_prev);
397
            $l_nav .= $this->diffViewlink($type, 'diffprevrev', $l_prev, $r_rev);
398
        }
399
        //dropdown
400
        $form = new Form(['action' => wl()]);
401
        $form->setHiddenField('id', $ID);
402
        $form->setHiddenField('difftype', $type);
403
        $form->setHiddenField('rev2[1]', $r_rev);
404
        $form->setHiddenField('do', 'diff');
405
        $input = $form->addDropdown('rev2[0]', $l_revisions)->val($l_rev)->addClass('quickselect');
406
        $input->useInput(false); // inhibit prefillInput() during toHTML() process
407
        $form->addButton('do[diff]', 'Go')->attr('type','submit');
408
        $l_nav .= $form->toHTML();
409
        //move forward
410
        if ($l_next && ($l_next < $r_rev || !$r_rev)) {
411
            $l_nav .= $this->diffViewlink($type, 'diffnextrev', $l_next, $r_rev);
412
        }
413
414
        /*
415
         * Right side:
416
         */
417
        $r_nav = '';
418
        //move back
419
        if ($l_rev < $r_prev) {
420
            $r_nav .= $this->diffViewlink($type, 'diffprevrev', $l_rev, $r_prev);
421
        }
422
        //dropdown
423
        $form = new Form(['action' => wl()]);
424
        $form->setHiddenField('id', $ID);
425
        $form->setHiddenField('rev2[0]', $l_rev);
426
        $form->setHiddenField('difftype', $type);
427
        $form->setHiddenField('do', 'diff');
428
        $input = $form->addDropdown('rev2[1]', $r_revisions)->val($r_rev)->addClass('quickselect');
429
        $input->useInput(false); // inhibit prefillInput() during toHTML() process
430
        $form->addButton('do[diff]', 'Go')->attr('type','submit');
431
        $r_nav .= $form->toHTML();
432
        //move forward
433
        if ($r_next) {
434
            if ($pagelog->isCurrentRevision($r_next)) {
435
                //last revision is diff with current page
436
                $r_nav .= $this->diffViewlink($type, 'difflastrev', $l_rev);
437
            } else {
438
                $r_nav .= $this->diffViewlink($type, 'diffnextrev', $l_rev, $r_next);
439
            }
440
        } else {
441
            $r_nav .= $this->diffViewlink($type, 'diffbothnextrev', $l_next, $r_next);
442
        }
443
        return array($l_nav, $r_nav);
444
    }
445
446
    /**
447
     * Create html link to a diff view defined by two revisions
448
     *
449
     * @param string $difftype display type
450
     * @param string $linktype
451
     * @param int $lrev oldest revision
452
     * @param int $rrev newest revision or null for diff with current revision
453
     * @return string html of link to a diff view
454
     */
455
    protected function diffViewlink($difftype, $linktype, $lrev, $rrev = null)
456
    {
457
        global $ID, $lang;
458
        if ($rrev === null) {
459
            $urlparam = array(
460
                'do' => 'diff',
461
                'rev' => $lrev,
462
                'difftype' => $difftype,
463
            );
464
        } else {
465
            $urlparam = array(
466
                'do' => 'diff',
467
                'rev2[0]' => $lrev,
468
                'rev2[1]' => $rrev,
469
                'difftype' => $difftype,
470
            );
471
        }
472
        return  '<a class="'. $linktype .'" href="'. wl($ID, $urlparam) .'" title="'. $lang[$linktype] .'">'
473
              . '<span>'. $lang[$linktype] .'</span>'
474
              . '</a>'. DOKU_LF;
475
    }
476
477
}
478