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

Recent.php$0 ➔ editDate()   A

Complexity

Conditions 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace dokuwiki\Ui;
4
5
use dokuwiki\ChangeLog\MediaChangeLog;
6
use dokuwiki\Extension\Event;
7
use dokuwiki\Form\Form;
8
9
/**
10
 * DokuWiki Recent Interface
11
 *
12
 * @package dokuwiki\Ui
13
 */
14
class Recent extends Ui
15
{
16
    protected $first;
17
    protected $show_changes;
18
19
    /** 
20
     * Recent Ui constructor
21
     *
22
     * @param int $first  skip the first n changelog lines
23
     * @param string $show_changes  type of changes to show; pages, mediafiles, or both
24
     */
25
    public function __construct($first = 0, $show_changes = 'both')
26
    {
27
        $this->first        = $first;
28
        $this->show_changes = $show_changes;
29
    }
30
31
    /**
32
     * Display recent changes
33
     *
34
     * @author Andreas Gohr <[email protected]>
35
     * @author Matthias Grimm <[email protected]>
36
     * @author Ben Coburn <[email protected]>
37
     * @author Kate Arzamastseva <[email protected]>
38
     * @author Satoshi Sahara <[email protected]>
39
     *
40
     * @triggers HTML_RECENTFORM_OUTPUT
41
     * @return void
42
     */
43
    public function show()
44
    {
45
        global $lang;
46
        global $ID;
47
48
        // get recent items, and set correct pagenation parameters (first, hasNext)
49
        $first = $this->first;
50
        $hasNext = null;
51
        $recents = $this->getRecents($first, $hasNext);
0 ignored issues
show
Documentation introduced by
$hasNext is of type null, but the function expects a boolean.

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...
52
53
        // print intro
54
        print p_locale_xhtml('recent');
55
56
        if (getNS($ID) != '') {
57
            print '<div class="level1"><p>'
58
                . sprintf($lang['recent_global'], getNS($ID), wl('', 'do=recent'))
59
                .'</p></div>';
60
        }
61
62
        // create the form
63
        $form = new Form(['id'=>'dw__recent', 'method'=>'GET', 'action'=> wl($ID), 'class'=>'changes']);
64
        $form->addTagOpen('div')->addClass('no');
65
        $form->setHiddenField('sectok', null);
66
        $form->setHiddenField('do', 'recent');
67
        $form->setHiddenField('id', $ID);
68
69
        // show dropdown selector, whether include not only recent pages but also recent media files?
70
        if ($conf['mediarevisions']) {
0 ignored issues
show
Bug introduced by
The variable $conf does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
71
            $this->addRecentItemSelector($form);
72
        }
73
74
        // start listing of recent items
75
        $form->addTagOpen('ul');
76
        foreach ($recents as $recent) {
77
            $objRevInfo = $this->getObjRevInfo($recent);
78
            $class = ($recent['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? 'minor': '';
79
            $form->addTagOpen('li')->addClass($class);
80
            $form->addTagOpen('div')->addClass('li');
81
            $html = implode(' ', [
82
                $objRevInfo->itemIcon(),          // filetype icon
83
                $objRevInfo->editDate(),          // edit date and time
84
                $objRevInfo->difflink(),          // link to diffview icon
85
                $objRevInfo->revisionlink(),      // linkto revisions icon
86
                $objRevInfo->itemName(),          // name of page or media
87
                $objRevInfo->editSummary(),       // edit summary
88
                $objRevInfo->editor(),            // editor info
89
                html_sizechange($recent['sizechange']), // size change indicator
90
            ]);
91
            $form->addHTML($html);
92
            $form->addTagClose('div');
93
            $form->addTagClose('li');
94
        }
95
        $form->addTagClose('ul');
96
97
        $form->addTagClose('div'); // close div class=no
98
99
        // provide navigation for pagenated recent list (of pages and/or media files)
100
        $form->addHTML($this->htmlNavigation($first, $hasNext));
101
102
        // emit HTML_CRECENTFORM_OUTPUT event
103
        Event::createAndTrigger('HTML_RECENTFORM_OUTPUT', $form, null, false);
104
        print $form->toHTML();
105
    }
106
107
    /**
108
     * Get recent items, and set correct pagenation parameters (first, hasNext)
109
     *
110
     * @param int  $first
111
     * @param bool $hasNext
112
     * @return array  recent items to be shown in a pagenated list
113
     *
114
     * @see also dokuwiki\Changelog::getRevisionInfo()
115
     */
116
    protected function getRecents(&$first, &$hasNext)
117
    {
118
        global $ID, $conf;
119
120
        $flags = 0;
121
        if ($this->show_changes == 'mediafiles' && $conf['mediarevisions']) {
122
            $flags = RECENTS_MEDIA_CHANGES;
123
        } elseif ($this->show_changes == 'pages') {
124
            $flags = 0;
125
        } elseif ($conf['mediarevisions']) {
126
            $flags = RECENTS_MEDIA_PAGES_MIXED;
127
        }
128
129
        /* we need to get one additionally log entry to be able to
130
         * decide if this is the last page or is there another one.
131
         * This is the cheapest solution to get this information.
132
         */
133
        $recents = getRecents($first, $conf['recent'] + 1, getNS($ID), $flags);
0 ignored issues
show
Security Bug introduced by
It seems like getNS($ID) targeting getNS() can also be of type false; however, getRecents() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
134
        if (count($recents) == 0 && $first != 0) {
135
            $first = 0;
136
            $recents = getRecents($first, $conf['recent'] + 1, getNS($ID), $flags);
0 ignored issues
show
Security Bug introduced by
It seems like getNS($ID) targeting getNS() can also be of type false; however, getRecents() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
137
        }
138
139
        $hasNext = false;
140
        if (count($recents) > $conf['recent']) {
141
            $hasNext = true;
142
            array_pop($recents); // remove extra log entry
143
        }
144
        return $recents;
145
    }
146
147
    /**
148
     * Navigation buttons for Pagenation (prev/next)
149
     *
150
     * @param int  $first
151
     * @param bool $hasNext
152
     * @return array  html
153
     */
154
    protected function htmlNavigation($first, $hasNext)
155
    {
156
        global $conf, $lang;
157
158
        $last = $first + $conf['recent'];
159
        $html = '<div class="pagenav">';
160
        if ($first > 0) {
161
            $first = max($first - $conf['recent'], 0);
162
            $html.= '<div class="pagenav-prev">';
163
            $html.= '<button type="submit" name="first['.$first.']" accesskey="n"'
164
                  . ' title="'.$lang['btn_newer'].' [N]" class="button show">'
165
                  . $lang['btn_newer']
166
                  . '</button>';
167
            $html.= '</div>';
168
        }
169
        if ($hasNext) {
170
            $html.= '<div class="pagenav-next">';
171
            $html.= '<button type="submit" name="first['.$last.']" accesskey="p"'
172
                  . ' title="'.$lang['btn_older'].' [P]" class="button show">'
173
                  . $lang['btn_older']
174
                  . '</button>';
175
            $html.= '</div>';
176
        }
177
        $html.= '</div>';
178
        return $html;
179
    }
180
181
    /**
182
     * Add dropdown selector of item types to the form instance
183
     *
184
     * @param Form $form
185
     * @return void
186
     */
187
    protected function addRecentItemSelector(Form $form)
188
    {
189
        global $lang;
190
191
        $form->addTagOpen('div')->addClass('changeType');
192
        $options = array(
193
                    'pages'      => $lang['pages_changes'],
194
                    'mediafiles' => $lang['media_changes'],
195
                    'both'       => $lang['both_changes'],
196
        );
197
        $form->addDropdown('show_changes', $options, $lang['changes_type'])
198
                ->val($this->show_changes)->addClass('quickselect');
199
        $form->addButton('do[recent]', $lang['btn_apply'])->attr('type','submit');
200
        $form->addTagClose('div');
201
    }
202
203
    /**
204
     * Returns instance of objRevInfo
205
     * @param array $info  Revision info structure of page or media
206
     * @return objRevInfo object (anonymous class)
207
     */
208
    protected function getObjRevInfo(array $info)
209
    {
210
        return new class ($info) // anonymous class (objRevInfo)
211
        {
212
            protected $info;
213
214
            public function __construct(array $info)
215
            {
216
                $this->info = $info;
217
            }
218
219
            // fileicon of the page or media file
220
            public function itemIcon()
221
            {
222
                $id = $this->info['id'];
223
                if (isset($this->info['media'])) {
224
                    $html = media_printicon($id);
225
                } else {
226
                    $html = '<img class="icon" src="'.DOKU_BASE.'lib/images/fileicons/file.png" alt="'.$id.'" />';
227
                }
228
                return $html;
229
            }
230
231
            // edit date and time of the page or media file
232
            public function editDate()
233
            {
234
                $date = $this->info['date'];
235
                $html = '<span class="date">'. dformat($date) .'</span>';
236
                return $html;
237
            }
238
239
            // icon difflink
240
            public function difflink()
241
            {
242
                global $lang;
243
                $id = $this->info['id'];
244
                $diff = false;
245
246
                if (isset($this->info['media'])) {
247
                    $revs = (new MediaChangeLog($id))->getRevisions(0, 1);
248
                    $diff = (count($revs) && file_exists(mediaFN($id)));
249
                    if ($diff) {
250
                        $href = media_managerURL(
251
                            ['tab_details'=>'history', 'mediado'=>'diff', 'image'=> $id, 'ns'=> getNS($id)], '&'
252
                        );
253
                    }
254
                } else {
255
                    $href = wl($id, "do=diff", false, '&');
256
                }
257
258
                if (isset($this->info['media']) && !$diff) {
259
                    $html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />';
260
                } else {
261
                    $html = '<a href="'.$href.'" class="diff_link">'
0 ignored issues
show
Bug introduced by
The variable $href 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...
262
                          . '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"'
263
                          . ' title="'.$lang['diff'].'" alt="'.$lang['diff'].'" />'
264
                          . '</a>';
265
                }
266
                return $html;
267
            }
268
269
            // icon revision link
270
            public function revisionlink()
271
            {
272
                global $lang;
273
                $id = $this->info['id'];
274
                if (isset($this->info['media'])) {
275
                    $href = media_managerURL(['tab_details'=>'history', 'image'=> $id, 'ns'=> getNS($id)], '&');
276
                } else {
277
                    $href = wl($id, "do=revisions", false, '&');
278
                }
279
                $html = '<a href="'.$href.'" class="revisions_link">'
280
                      . '<img src="'.DOKU_BASE.'lib/images/history.png" width="12" height="14"'
281
                      . ' title="'.$lang['btn_revs'].'" alt="'.$lang['btn_revs'].'" />'
282
                      . '</a>';
283
                return $html;
284
            }
285
286
            // name of the page or media file
287
            public function itemName()
288
            {
289
                $id = $this->info['id'];
290
                if (isset($this->info['media'])) {
291
                    $href = media_managerURL(['tab_details'=>'view', 'image'=> $id, 'ns'=> getNS($id)], '&');
292
                    $class = file_exists(mediaFN($id)) ? 'wikilink1' : 'wikilink2';
293
                    $html = '<a href="'.$href.'" class="'.$class.'">'.$id.'</a>';
294
                } else {
295
                    $html = html_wikilink(':'.$id, (useHeading('navigation') ? null : $id));
296
                }
297
                return $html;
298
            }
299
300
            // edit summary
301
            public function editSummary()
302
            {
303
                $html = '<span class="sum">';
304
                $html.= ' – '. hsc($this->info['sum']);
305
                $html.= '</span>';
306
                return $html;
307
            }
308
309
            // editor of the page or media file
310
            public function editor()
311
            {
312
                $html = '<span class="user">';
313
                if ($this->info['user']) {
314
                    $html.= '<bdi>'. editorinfo($this->info['user']) .'</bdi>';
315
                    if (auth_ismanager()) $html.= ' <bdo dir="ltr">('. $this->info['ip'] .')</bdo>';
316
                } else {
317
                    $html.= '<bdo dir="ltr">'. $this->info['ip'] .'</bdo>';
318
                }
319
                $html.= '</span>';
320
                return $html;
321
            }
322
        }; // end of anonymous class (objRevInfo)
323
    }
324
325
}
326