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

Revisions   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 286
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 9

Importance

Changes 0
Metric Value
dl 0
loc 286
rs 9.0399
c 0
b 0
f 0
wmc 42
lcom 0
cbo 9

1 Method

Rating   Name   Duplication   Size   Complexity  
F show() 0 270 42

How to fix   Complexity   

Complex Class

Complex classes like Revisions often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Revisions, and based on these observations, apply Extract Interface, too.

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 Revisions Insterface
12
 *
13
 * @package dokuwiki\Ui
14
 */
15
class Revisions extends Ui
16
{
17
    /**
18
     * Display list of old revisions
19
     *
20
     * @author Andreas Gohr <[email protected]>
21
     * @author Ben Coburn <[email protected]>
22
     * @author Kate Arzamastseva <[email protected]>
23
     *
24
     * @triggers HTML_REVISIONSFORM_OUTPUT
25
     * @param int $first skip the first n changelog lines
26
     * @param bool|string $media_id id of media, or false for current page
27
     * @return void
28
     */
29
    public function show($first = 0, $media_id = false)
30
    {
31
        global $ID;
32
        global $INFO;
33
        global $conf;
34
        global $lang;
35
        $id = $ID;
36
        if ($media_id) {
37
            $id = $media_id;
38
            $changelog = new MediaChangeLog($id);
39
        } else {
40
            $changelog = new PageChangeLog($id);
41
        }
42
43
        /* we need to get one additional log entry to be able to
44
         * decide if this is the last page or is there another one.
45
         * see html_recent()
46
         */
47
48
        $revisions = $changelog->getRevisions($first, $conf['recent'] +1);
49
50
        if (count($revisions) == 0 && $first != 0) {
51
            $first = 0;
52
            $revisions = $changelog->getRevisions($first, $conf['recent'] +1);
53
        }
54
        $hasNext = false;
55
        if (count($revisions) > $conf['recent']) {
56
            $hasNext = true;
57
            array_pop($revisions); // remove extra log entry
58
        }
59
60
        // print intro
61
        if (!$media_id) {
62
            print p_locale_xhtml('revisions');
63
            $exists = $INFO['exists'];
64
            $display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id;
65
            if (!$display_name) {
66
                $display_name = $id;
67
            }
68
        } else {
69
            $exists = file_exists(mediaFN($id));
70
            $display_name = $id;
71
        }
72
73
        // create the form
74
        $form = new Form(['id' => 'page__revisions']);
75
        $form->addClass('changes');
76
        if ($media_id) {
77
            $form->attr('action', media_managerURL(array('image' => $media_id), '&'));
0 ignored issues
show
Bug introduced by
It seems like media_managerURL(array('...ge' => $media_id), '&') targeting media_managerURL() can also be of type array; however, dokuwiki\Form\Element::attr() does only seem to accept null|string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
78
        }
79
80
        // start listing
81
        $form->addTagOpen('ul');
82
83
        if ($exists && $first == 0) {
84
            $minor = false;
85
            if ($media_id) {
86
                $date = dformat(@filemtime(mediaFN($id)));
87
                $href = media_managerURL(array('image' => $id, 'tab_details' => 'view'), '&');
88
89
                $changelog->setChunkSize(1024);
90
                $revinfo = $changelog->getRevisionInfo(@filemtime(fullpath(mediaFN($id))));
91
92
                $summary = $revinfo['sum'];
93
                $editor = $revinfo['user'] ?: $revinfo['ip'];
94
                $sizechange = $revinfo['sizechange'];
95
            } else {
96
                $date = dformat($INFO['lastmod']);
97
                if (isset($INFO['meta']) && isset($INFO['meta']['last_change'])) {
98
                    if ($INFO['meta']['last_change']['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) {
99
                        $minor = true;
100
                    }
101
                    if (isset($INFO['meta']['last_change']['sizechange'])) {
102
                        $sizechange = $INFO['meta']['last_change']['sizechange'];
103
                    } else {
104
                        $sizechange = null;
105
                    }
106
                }
107
                $pagelog = new PageChangeLog($ID);
108
                $latestrev = $pagelog->getRevisions(-1, 1);
109
                $latestrev = array_pop($latestrev);
110
                $href = wl($id, "rev=$latestrev", false, '&');
111
                $summary = $INFO['sum'];
112
                $editor = $INFO['editor'];
113
            }
114
115
            $form->addTagOpen('li')->addClass($minor ? 'minor' : '');
116
            $form->addTagOpen('div')->addClass('li');
117
            $form->addCheckbox('rev2[]')->val('current');
118
119
            $form->addTagOpen('span')->addClass('data');
120
            $form->addHTML($date);
121
            $form->addTagClose('span');
122
123
            $form->addTag('img')->attrs([
124
                'src' => DOKU_BASE.'lib/images/blank.gif',
125
                'width' => 15,
126
                'height' => 11,
127
                'alt' => '',
128
            ]);
129
130
            $form->addTagOPen('a')->attr('href', $href)->addClass('wikilink1');
0 ignored issues
show
Bug introduced by
It seems like $href defined by media_managerURL(array('...tails' => 'view'), '&') on line 87 can also be of type array; however, dokuwiki\Form\Element::attr() does only seem to accept null|string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
131
            $form->addHTML($display_name);
132
            $form->addTagClose('a');
133
134
            if ($media_id) $form->addTagOpen('div');
135
136
            if ($summary) {
137
                $form->addTagOpen('span')->addClass('sum');
138
                if (!$media_id) $form->addHTML(' – ');
139
                $form->addHTML('<bdi>' . hsc($summary) . '</bdi>');
140
                $form->addTagClose('span');
141
            }
142
143
            $form->addTagOpen('span')->addClass('user');
144
            $form->addHTML(
145
                (empty($editor)) ? ('('.$lang['external_edit'].')') : '<bdi>'.editorinfo($editor).'</bdi>'
146
            );
147
            $form->addTagClose('span');
148
149
150
            html_sizechange($sizechange, $form);
0 ignored issues
show
Bug introduced by
The variable $sizechange does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Documentation introduced by
$form is of type object<dokuwiki\Form\Form>, but the function expects a object<Form>|object<Doku_Form>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
151
152
            $form->addHTML('('.$lang['current'].')');
153
154
            if ($media_id) $form->addTagClose('div');
155
156
            $form->addTagClose('div');
157
            $form->addTagClose('li');
158
        }
159
160
        foreach ($revisions as $rev) {
161
            $date = dformat($rev);
162
            $info = $changelog->getRevisionInfo($rev);
163
            if ($media_id) {
164
                $exists = file_exists(mediaFN($id, $rev));
165
            } else {
166
                $exists = page_exists($id, $rev);
167
            }
168
169
            $class = '';
170
            if ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) {
171
                $class = 'minor';
172
            }
173
174
            $form->addTagOpen('li')->addClass($class);
175
            $form->addTagOpen('div')->addClass('li');
176
177
            if ($exists){
178
                $form->addCheckbox('rev2[]')->val($rev);
179
            } else {
180
                $form->addTag('img')->attrs([
181
                    'src' => DOKU_BASE.'lib/images/blank.gif',
182
                    'width' => 15,
183
                    'height' => 11,
184
                    'alt' => '',
185
                ]);
186
            }
187
188
            $form->addTagOpen('span')->addClass('date');
189
            $form->addHTML($date);
190
            $form->addTagClose('span');
191
192
            if ($exists) {
193
                if (!$media_id) {
194
                    $href = wl($id, "rev=$rev,do=diff", false, '&');
195
                } else {
196
                    $href = media_managerURL(array('image' => $id, 'rev' => $rev, 'mediado' => 'diff'), '&');
197
                }
198
                $form->addTagOpen('a')->attr('href', $href)->addClass('diff_link');
0 ignored issues
show
Bug introduced by
It seems like $href defined by media_managerURL(array('...diado' => 'diff'), '&') on line 196 can also be of type array; however, dokuwiki\Form\Element::attr() does only seem to accept null|string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
199
                $form->addTag('img')->attrs([
200
                    'src'    => DOKU_BASE.'lib/images/diff.png',
201
                    'width'  => 15,
202
                    'height' => 11,
203
                    'title'  => $lang['diff'],
204
                    'alt'    => $lang['diff'],
205
                ]);
206
                $form->addTagClose('a');
207
208
                if (!$media_id) {
209
                    $href = wl($id, "rev=$rev", false, '&');
210
                } else {
211
                    $href = media_managerURL(array('image' => $id, 'tab_details' => 'view', 'rev' => $rev), '&');
212
                }
213
                $form->addTagOpen('a')->attr('href', $href)->addClass('wikilink1');
0 ignored issues
show
Bug introduced by
It seems like $href defined by media_managerURL(array('...', 'rev' => $rev), '&') on line 211 can also be of type array; however, dokuwiki\Form\Element::attr() does only seem to accept null|string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
214
                $form->addHTML($display_name);
215
                $form->addTagClose('a');
216
            } else {
217
                $form->addTag('img')->attrs([
218
                    'src'    => DOKU_BASE.'lib/images/blank.gif',
219
                    'width'  => 15,
220
                    'height' => 11,
221
                    'alt'    => '',
222
                ]);
223
                $form->addHTML($display_name);
224
            }
225
226
            if ($media_id) $form->addTagOpen('div');
227
228
            if ($info['sum']) {
229
                $form->addTagOpen('span')->addClass('sum');
230
                if (!$media_id) $form->addHTML(' – ');
231
                $form->addHTML('<bdi>'. hsc($info['sum']) .'</bdi>');
232
                $form->addTagClose('span');
233
            }
234
235
            $form->addTagOpen('span')->addClass('user');
236
            if ($info['user']) {
237
                $form->addHTML('<bdi>'. editorinfo($info['user']) .'</bdi>');
238
                if (auth_ismanager()) {
239
                    $form->addHTML(' <bdo dir="ltr">('. $info['ip'] .')</bdo>');
240
                }
241
            } else {
242
                $form->addHTML('<bdo dir="ltr">' .$info['ip'] .'</bdo>');
243
            }
244
            $form->addTagClose('span');
245
246
            html_sizechange($info['sizechange'], $form);
0 ignored issues
show
Documentation introduced by
$form is of type object<dokuwiki\Form\Form>, but the function expects a object<Form>|object<Doku_Form>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
247
248
            if ($media_id) $form->addTagClose('div');
249
250
            $form->addTagClose('div');
251
            $form->addTagClose('li');
252
        }
253
254
        // end of revision list
255
        $form->addTagClose('ul');
256
257
        // show button for diff view
258
        if (!$media_id) {
259
            $form->addButton('do[diff]', $lang['diff2'])->attr('type', 'submit');
260
        } else {
261
            $form->setHiddenField('mediado', 'diff');
262
            $form->addButton('', $lang['diff2'])->attr('type', 'submit');
263
        }
264
265
        $form->addTagClose('div'); // close div class=no
266
267
        // emit HTML_REVISIONSFORM_OUTPUT event, print the form
268
        Event::createAndTrigger('HTML_REVISIONSFORM_OUTPUT', $form, 'html_form_output', false);
269
270
        print DOKU_LF;
271
272
        // provide navigation for pagenated revision list (of pages and/or media files)
273
        print '<div class="pagenav">';
274
        $last = $first + $conf['recent'];
275
        if ($first > 0) {
276
            $first = $first - $conf['recent'];
277
            if ($first < 0) $first = 0;
278
            print '<div class="pagenav-prev">';
279
            if ($media_id) {
280
                print html_btn('newer',$media_id,"p",media_managerURL(array('first' => $first), '&amp;', false, true));
281
            } else {
282
                print html_btn('newer',$id,"p",array('do' => 'revisions', 'first' => $first));
283
            }
284
            print '</div>';
285
        }
286
        if ($hasNext) {
287
            print '<div class="pagenav-next">';
288
            if ($media_id) {
289
                print html_btn('older',$media_id,"n",media_managerURL(array('first' => $last), '&amp;', false, true));
290
            } else {
291
                print html_btn('older',$id,"n",array('do' => 'revisions', 'first' => $last));
292
            }
293
            print '</div>';
294
        }
295
        print '</div>';
296
297
        print DOKU_LF;
298
    }
299
300
}
301