Completed
Pull Request — authpdo (#1572)
by
unknown
04:27
created

Doku_Handler_Table::finalizeTable()   F

Complexity

Conditions 36
Paths 552

Size

Total Lines 180
Code Lines 101

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 180
rs 2.4507
cc 36
eloc 101
nc 552
nop 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
if(!defined('DOKU_INC')) die('meh.');
3
if (!defined('DOKU_PARSER_EOL')) define('DOKU_PARSER_EOL',"\n");   // add this to make handling test cases simpler
4
5
class Doku_Handler {
6
7
    var $Renderer = null;
8
9
    var $CallWriter = null;
10
11
    var $calls = array();
12
13
    var $status = array(
14
        'section' => false,
15
        'doublequote' => 0,
16
    );
17
18
    var $rewriteBlocks = true;
19
20
    function __construct() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
21
        $this->CallWriter = new Doku_Handler_CallWriter($this);
22
    }
23
24
    /**
25
     * @param string $handler
26
     */
27
    function _addCall($handler, $args, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
28
        $call = array($handler,$args, $pos);
29
        $this->CallWriter->writeCall($call);
30
    }
31
32
    function addPluginCall($plugin, $args, $state, $pos, $match) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
33
        $call = array('plugin',array($plugin, $args, $state, $match), $pos);
34
        $this->CallWriter->writeCall($call);
35
    }
36
37
    function _finalize(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
38
39
        $this->CallWriter->finalise();
40
41
        if ( $this->status['section'] ) {
42
            $last_call = end($this->calls);
43
            array_push($this->calls,array('section_close',array(), $last_call[2]));
44
        }
45
46
        if ( $this->rewriteBlocks ) {
47
            $B = new Doku_Handler_Block();
48
            $this->calls = $B->process($this->calls);
49
        }
50
51
        trigger_event('PARSER_HANDLER_DONE',$this);
52
53
        array_unshift($this->calls,array('document_start',array(),0));
54
        $last_call = end($this->calls);
55
        array_push($this->calls,array('document_end',array(),$last_call[2]));
56
    }
57
58
    function fetch() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
59
        $call = each($this->calls);
60
        if ( $call ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $call of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
61
            return $call['value'];
62
        }
63
        return false;
64
    }
65
66
67
    /**
68
     * Special plugin handler
69
     *
70
     * This handler is called for all modes starting with 'plugin_'.
71
     * An additional parameter with the plugin name is passed
72
     *
73
     * @author Andreas Gohr <[email protected]>
74
     */
75
    function plugin($match, $state, $pos, $pluginname){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
76
        $data = array($match);
77
        /** @var DokuWiki_Syntax_Plugin $plugin */
78
        $plugin = plugin_load('syntax',$pluginname);
79
        if($plugin != null){
80
            $data = $plugin->handle($match, $state, $pos, $this);
81
        }
82
        if ($data !== false) {
83
            $this->addPluginCall($pluginname,$data,$state,$pos,$match);
84
        }
85
        return true;
86
    }
87
88
    function base($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
89
        switch ( $state ) {
90
            case DOKU_LEXER_UNMATCHED:
91
                $this->_addCall('cdata',array($match), $pos);
92
                return true;
93
            break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
94
        }
95
    }
96
97
    function header($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
98
        // get level and title
99
        $title = trim($match);
100
        $level = 7 - strspn($title,'=');
101
        if($level < 1) $level = 1;
102
        $title = trim($title,'=');
103
        $title = trim($title);
104
105
        if ($this->status['section']) $this->_addCall('section_close',array(),$pos);
106
107
        $this->_addCall('header',array($title,$level,$pos), $pos);
108
109
        $this->_addCall('section_open',array($level),$pos);
110
        $this->status['section'] = true;
111
        return true;
112
    }
113
114
    function notoc($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
115
        $this->_addCall('notoc',array(),$pos);
116
        return true;
117
    }
118
119
    function nocache($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
120
        $this->_addCall('nocache',array(),$pos);
121
        return true;
122
    }
123
124
    function linebreak($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
125
        $this->_addCall('linebreak',array(),$pos);
126
        return true;
127
    }
128
129
    function eol($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
130
        $this->_addCall('eol',array(),$pos);
131
        return true;
132
    }
133
134
    function hr($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
135
        $this->_addCall('hr',array(),$pos);
136
        return true;
137
    }
138
139
    /**
140
     * @param string $name
141
     */
142
    function _nestingTag($match, $state, $pos, $name) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
143
        switch ( $state ) {
144
            case DOKU_LEXER_ENTER:
145
                $this->_addCall($name.'_open', array(), $pos);
146
            break;
147
            case DOKU_LEXER_EXIT:
148
                $this->_addCall($name.'_close', array(), $pos);
149
            break;
150
            case DOKU_LEXER_UNMATCHED:
151
                $this->_addCall('cdata',array($match), $pos);
152
            break;
153
        }
154
    }
155
156
    function strong($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
157
        $this->_nestingTag($match, $state, $pos, 'strong');
158
        return true;
159
    }
160
161
    function emphasis($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
162
        $this->_nestingTag($match, $state, $pos, 'emphasis');
163
        return true;
164
    }
165
166
    function underline($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
167
        $this->_nestingTag($match, $state, $pos, 'underline');
168
        return true;
169
    }
170
171
    function monospace($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
172
        $this->_nestingTag($match, $state, $pos, 'monospace');
173
        return true;
174
    }
175
176
    function subscript($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
177
        $this->_nestingTag($match, $state, $pos, 'subscript');
178
        return true;
179
    }
180
181
    function superscript($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
182
        $this->_nestingTag($match, $state, $pos, 'superscript');
183
        return true;
184
    }
185
186
    function deleted($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
187
        $this->_nestingTag($match, $state, $pos, 'deleted');
188
        return true;
189
    }
190
191
192
    function footnote($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
193
//        $this->_nestingTag($match, $state, $pos, 'footnote');
194
        if (!isset($this->_footnote)) $this->_footnote = false;
0 ignored issues
show
Bug introduced by
The property _footnote does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
195
196
        switch ( $state ) {
197
            case DOKU_LEXER_ENTER:
198
                // footnotes can not be nested - however due to limitations in lexer it can't be prevented
199
                // we will still enter a new footnote mode, we just do nothing
200
                if ($this->_footnote) {
201
                    $this->_addCall('cdata',array($match), $pos);
202
                    break;
203
                }
204
205
                $this->_footnote = true;
206
207
                $ReWriter = new Doku_Handler_Nest($this->CallWriter,'footnote_close');
208
                $this->CallWriter = & $ReWriter;
209
                $this->_addCall('footnote_open', array(), $pos);
210
            break;
211
            case DOKU_LEXER_EXIT:
212
                // check whether we have already exitted the footnote mode, can happen if the modes were nested
213
                if (!$this->_footnote) {
214
                    $this->_addCall('cdata',array($match), $pos);
215
                    break;
216
                }
217
218
                $this->_footnote = false;
219
220
                $this->_addCall('footnote_close', array(), $pos);
221
                $this->CallWriter->process();
0 ignored issues
show
Bug introduced by
The method process() does not seem to exist on object<Doku_Handler_CallWriter>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
222
                $ReWriter = & $this->CallWriter;
223
                $this->CallWriter = & $ReWriter->CallWriter;
0 ignored issues
show
Bug introduced by
The property CallWriter does not seem to exist in Doku_Handler_CallWriter.

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...
224
            break;
225
            case DOKU_LEXER_UNMATCHED:
226
                $this->_addCall('cdata', array($match), $pos);
227
            break;
228
        }
229
        return true;
230
    }
231
232
    function listblock($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
233
        switch ( $state ) {
234
            case DOKU_LEXER_ENTER:
235
                $ReWriter = new Doku_Handler_List($this->CallWriter);
236
                $this->CallWriter = & $ReWriter;
237
                $this->_addCall('list_open', array($match), $pos);
238
            break;
239
            case DOKU_LEXER_EXIT:
240
                $this->_addCall('list_close', array(), $pos);
241
                $this->CallWriter->process();
0 ignored issues
show
Bug introduced by
The method process does only exist in Doku_Handler_Nest, but not in Doku_Handler_CallWriter.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
242
                $ReWriter = & $this->CallWriter;
243
                $this->CallWriter = & $ReWriter->CallWriter;
244
            break;
245
            case DOKU_LEXER_MATCHED:
246
                $this->_addCall('list_item', array($match), $pos);
247
            break;
248
            case DOKU_LEXER_UNMATCHED:
249
                $this->_addCall('cdata', array($match), $pos);
250
            break;
251
        }
252
        return true;
253
    }
254
255
    function unformatted($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
256
        if ( $state == DOKU_LEXER_UNMATCHED ) {
257
            $this->_addCall('unformatted',array($match), $pos);
258
        }
259
        return true;
260
    }
261
262
    function php($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
263
        global $conf;
264
        if ( $state == DOKU_LEXER_UNMATCHED ) {
265
            $this->_addCall('php',array($match), $pos);
266
        }
267
        return true;
268
    }
269
270
    function phpblock($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
271
        global $conf;
272
        if ( $state == DOKU_LEXER_UNMATCHED ) {
273
            $this->_addCall('phpblock',array($match), $pos);
274
        }
275
        return true;
276
    }
277
278
    function html($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
279
        global $conf;
280
        if ( $state == DOKU_LEXER_UNMATCHED ) {
281
            $this->_addCall('html',array($match), $pos);
282
        }
283
        return true;
284
    }
285
286
    function htmlblock($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
287
        global $conf;
288
        if ( $state == DOKU_LEXER_UNMATCHED ) {
289
            $this->_addCall('htmlblock',array($match), $pos);
290
        }
291
        return true;
292
    }
293
294
    function preformatted($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
295
        switch ( $state ) {
296
            case DOKU_LEXER_ENTER:
297
                $ReWriter = new Doku_Handler_Preformatted($this->CallWriter);
298
                $this->CallWriter = $ReWriter;
299
                $this->_addCall('preformatted_start',array(), $pos);
300
            break;
301
            case DOKU_LEXER_EXIT:
302
                $this->_addCall('preformatted_end',array(), $pos);
303
                $this->CallWriter->process();
0 ignored issues
show
Bug introduced by
The method process does only exist in Doku_Handler_List and Doku_Handler_Nest, but not in Doku_Handler_CallWriter.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
304
                $ReWriter = & $this->CallWriter;
305
                $this->CallWriter = & $ReWriter->CallWriter;
306
            break;
307
            case DOKU_LEXER_MATCHED:
308
                $this->_addCall('preformatted_newline',array(), $pos);
309
            break;
310
            case DOKU_LEXER_UNMATCHED:
311
                $this->_addCall('preformatted_content',array($match), $pos);
312
            break;
313
        }
314
315
        return true;
316
    }
317
318
    function quote($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
319
320
        switch ( $state ) {
321
322
            case DOKU_LEXER_ENTER:
323
                $ReWriter = new Doku_Handler_Quote($this->CallWriter);
324
                $this->CallWriter = & $ReWriter;
325
                $this->_addCall('quote_start',array($match), $pos);
326
            break;
327
328
            case DOKU_LEXER_EXIT:
329
                $this->_addCall('quote_end',array(), $pos);
330
                $this->CallWriter->process();
0 ignored issues
show
Bug introduced by
The method process does only exist in Doku_Handler_List and Do...ku_Handler_Preformatted, but not in Doku_Handler_CallWriter.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
331
                $ReWriter = & $this->CallWriter;
332
                $this->CallWriter = & $ReWriter->CallWriter;
333
            break;
334
335
            case DOKU_LEXER_MATCHED:
336
                $this->_addCall('quote_newline',array($match), $pos);
337
            break;
338
339
            case DOKU_LEXER_UNMATCHED:
340
                $this->_addCall('cdata',array($match), $pos);
341
            break;
342
343
        }
344
345
        return true;
346
    }
347
348
    function file($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
349
        return $this->code($match, $state, $pos, 'file');
350
    }
351
352
    function code($match, $state, $pos, $type='code') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
353
        if ( $state == DOKU_LEXER_UNMATCHED ) {
354
            $matches = explode('>',$match,2);
355
356
            $param = preg_split('/\s+/', $matches[0], 2, PREG_SPLIT_NO_EMPTY);
357
            while(count($param) < 2) array_push($param, null);
358
359
            // We shortcut html here.
360
            if ($param[0] == 'html') $param[0] = 'html4strict';
361
            if ($param[0] == '-') $param[0] = null;
362
            array_unshift($param, $matches[1]);
363
364
            $this->_addCall($type, $param, $pos);
365
        }
366
        return true;
367
    }
368
369
    function acronym($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
370
        $this->_addCall('acronym',array($match), $pos);
371
        return true;
372
    }
373
374
    function smiley($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
375
        $this->_addCall('smiley',array($match), $pos);
376
        return true;
377
    }
378
379
    function wordblock($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
380
        $this->_addCall('wordblock',array($match), $pos);
381
        return true;
382
    }
383
384
    function entity($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
385
        $this->_addCall('entity',array($match), $pos);
386
        return true;
387
    }
388
389
    function multiplyentity($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
390
        preg_match_all('/\d+/',$match,$matches);
391
        $this->_addCall('multiplyentity',array($matches[0][0],$matches[0][1]), $pos);
392
        return true;
393
    }
394
395
    function singlequoteopening($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
396
        $this->_addCall('singlequoteopening',array(), $pos);
397
        return true;
398
    }
399
400
    function singlequoteclosing($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
401
        $this->_addCall('singlequoteclosing',array(), $pos);
402
        return true;
403
    }
404
405
    function apostrophe($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
406
        $this->_addCall('apostrophe',array(), $pos);
407
        return true;
408
    }
409
410
    function doublequoteopening($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $match is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
411
        $this->_addCall('doublequoteopening',array(), $pos);
412
        $this->status['doublequote']++;
413
        return true;
414
    }
415
416
    function doublequoteclosing($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
417
        if ($this->status['doublequote'] <= 0) {
418
            $this->doublequoteopening($match, $state, $pos);
419
        } else {
420
            $this->_addCall('doublequoteclosing',array(), $pos);
421
            $this->status['doublequote'] = max(0, --$this->status['doublequote']);
422
        }
423
        return true;
424
    }
425
426
    function camelcaselink($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
427
        $this->_addCall('camelcaselink',array($match), $pos);
428
        return true;
429
    }
430
431
    /*
432
    */
433
    function internallink($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
434
        // Strip the opening and closing markup
435
        $link = preg_replace(array('/^\[\[/','/\]\]$/u'),'',$match);
436
437
        // Split title from URL
438
        $link = explode('|',$link,2);
439
        if ( !isset($link[1]) ) {
440
            $link[1] = null;
441
        } else if ( preg_match('/^\{\{[^\}]+\}\}$/',$link[1]) ) {
442
            // If the title is an image, convert it to an array containing the image details
443
            $link[1] = Doku_Handler_Parse_Media($link[1]);
444
        }
445
        $link[0] = trim($link[0]);
446
447
        //decide which kind of link it is
448
449
        if ( preg_match('/^[a-zA-Z0-9\.]+>{1}.*$/u',$link[0]) ) {
450
            // Interwiki
451
            $interwiki = explode('>',$link[0],2);
452
            $this->_addCall(
453
                'interwikilink',
454
                array($link[0],$link[1],strtolower($interwiki[0]),$interwiki[1]),
455
                $pos
456
                );
457
        }elseif ( preg_match('/^\\\\\\\\[^\\\\]+?\\\\/u',$link[0]) ) {
458
            // Windows Share
459
            $this->_addCall(
460
                'windowssharelink',
461
                array($link[0],$link[1]),
462
                $pos
463
                );
464
        }elseif ( preg_match('#^([a-z0-9\-\.+]+?)://#i',$link[0]) ) {
465
            // external link (accepts all protocols)
466
            $this->_addCall(
467
                    'externallink',
468
                    array($link[0],$link[1]),
469
                    $pos
470
                    );
471
        }elseif ( preg_match('<'.PREG_PATTERN_VALID_EMAIL.'>',$link[0]) ) {
472
            // E-Mail (pattern above is defined in inc/mail.php)
473
            $this->_addCall(
474
                'emaillink',
475
                array($link[0],$link[1]),
476
                $pos
477
                );
478
        }elseif ( preg_match('!^#.+!',$link[0]) ){
479
            // local link
480
            $this->_addCall(
481
                'locallink',
482
                array(substr($link[0],1),$link[1]),
483
                $pos
484
                );
485
        }else{
486
            // internal link
487
            $this->_addCall(
488
                'internallink',
489
                array($link[0],$link[1]),
490
                $pos
491
                );
492
        }
493
494
        return true;
495
    }
496
497
    function filelink($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
498
        $this->_addCall('filelink',array($match, null), $pos);
499
        return true;
500
    }
501
502
    function windowssharelink($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
503
        $this->_addCall('windowssharelink',array($match, null), $pos);
504
        return true;
505
    }
506
507
    function media($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
508
        $p = Doku_Handler_Parse_Media($match);
509
510
        $this->_addCall(
511
              $p['type'],
512
              array($p['src'], $p['title'], $p['align'], $p['width'],
513
                     $p['height'], $p['cache'], $p['linking']),
514
              $pos
515
             );
516
        return true;
517
    }
518
519
    function rss($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
520
        $link = preg_replace(array('/^\{\{rss>/','/\}\}$/'),'',$match);
521
522
        // get params
523
        list($link,$params) = explode(' ',$link,2);
524
525
        $p = array();
526
        if(preg_match('/\b(\d+)\b/',$params,$match)){
527
            $p['max'] = $match[1];
528
        }else{
529
            $p['max'] = 8;
530
        }
531
        $p['reverse'] = (preg_match('/rev/',$params));
532
        $p['author']  = (preg_match('/\b(by|author)/',$params));
533
        $p['date']    = (preg_match('/\b(date)/',$params));
534
        $p['details'] = (preg_match('/\b(desc|detail)/',$params));
535
        $p['nosort']  = (preg_match('/\b(nosort)\b/',$params));
536
537
        if (preg_match('/\b(\d+)([dhm])\b/',$params,$match)) {
538
            $period = array('d' => 86400, 'h' => 3600, 'm' => 60);
539
            $p['refresh'] = max(600,$match[1]*$period[$match[2]]);  // n * period in seconds, minimum 10 minutes
540
        } else {
541
            $p['refresh'] = 14400;   // default to 4 hours
542
        }
543
544
        $this->_addCall('rss',array($link,$p),$pos);
545
        return true;
546
    }
547
548
    function externallink($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
549
        $url   = $match;
550
        $title = null;
551
552
        // add protocol on simple short URLs
553
        if(substr($url,0,3) == 'ftp' && (substr($url,0,6) != 'ftp://')){
554
            $title = $url;
555
            $url   = 'ftp://'.$url;
556
        }
557
        if(substr($url,0,3) == 'www' && (substr($url,0,7) != 'http://')){
558
            $title = $url;
559
            $url = 'http://'.$url;
560
        }
561
562
        $this->_addCall('externallink',array($url, $title), $pos);
563
        return true;
564
    }
565
566
    function emaillink($match, $state, $pos) {
0 ignored issues
show
Unused Code introduced by
The parameter $state is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
567
        $email = preg_replace(array('/^</','/>$/'),'',$match);
568
        $this->_addCall('emaillink',array($email, null), $pos);
569
        return true;
570
    }
571
572
    function table($match, $state, $pos) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
573
        switch ( $state ) {
574
575
            case DOKU_LEXER_ENTER:
576
577
                $ReWriter = new Doku_Handler_Table($this->CallWriter);
578
                $this->CallWriter = & $ReWriter;
579
580
                $this->_addCall('table_start', array($pos + 1), $pos);
581
                if ( trim($match) == '^' ) {
582
                    $this->_addCall('tableheader', array(), $pos);
583
                } else {
584
                    $this->_addCall('tablecell', array(), $pos);
585
                }
586
            break;
587
588
            case DOKU_LEXER_EXIT:
589
                $this->_addCall('table_end', array($pos), $pos);
590
                $this->CallWriter->process();
0 ignored issues
show
Bug introduced by
The method process does only exist in Doku_Handler_List and Do... and Doku_Handler_Quote, but not in Doku_Handler_CallWriter.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
591
                $ReWriter = & $this->CallWriter;
592
                $this->CallWriter = & $ReWriter->CallWriter;
593
            break;
594
595
            case DOKU_LEXER_UNMATCHED:
596
                if ( trim($match) != '' ) {
597
                    $this->_addCall('cdata',array($match), $pos);
598
                }
599
            break;
600
601
            case DOKU_LEXER_MATCHED:
602
                if ( $match == ' ' ){
603
                    $this->_addCall('cdata', array($match), $pos);
604
                } else if ( preg_match('/:::/',$match) ) {
605
                    $this->_addCall('rowspan', array($match), $pos);
606
                } else if ( preg_match('/\t+/',$match) ) {
607
                    $this->_addCall('table_align', array($match), $pos);
608
                } else if ( preg_match('/ {2,}/',$match) ) {
609
                    $this->_addCall('table_align', array($match), $pos);
610
                } else if ( $match == "\n|" ) {
611
                    $this->_addCall('table_row', array(), $pos);
612
                    $this->_addCall('tablecell', array(), $pos);
613
                } else if ( $match == "\n^" ) {
614
                    $this->_addCall('table_row', array(), $pos);
615
                    $this->_addCall('tableheader', array(), $pos);
616
                } else if ( $match == '|' ) {
617
                    $this->_addCall('tablecell', array(), $pos);
618
                } else if ( $match == '^' ) {
619
                    $this->_addCall('tableheader', array(), $pos);
620
                }
621
            break;
622
        }
623
        return true;
624
    }
625
}
626
627
//------------------------------------------------------------------------
628
function Doku_Handler_Parse_Media($match) {
629
630
    // Strip the opening and closing markup
631
    $link = preg_replace(array('/^\{\{/','/\}\}$/u'),'',$match);
632
633
    // Split title from URL
634
    $link = explode('|',$link,2);
635
636
    // Check alignment
637
    $ralign = (bool)preg_match('/^ /',$link[0]);
638
    $lalign = (bool)preg_match('/ $/',$link[0]);
639
640
    // Logic = what's that ;)...
641
    if ( $lalign & $ralign ) {
642
        $align = 'center';
643
    } else if ( $ralign ) {
644
        $align = 'right';
645
    } else if ( $lalign ) {
646
        $align = 'left';
647
    } else {
648
        $align = null;
649
    }
650
651
    // The title...
652
    if ( !isset($link[1]) ) {
653
        $link[1] = null;
654
    }
655
656
    //remove aligning spaces
657
    $link[0] = trim($link[0]);
658
659
    //split into src and parameters (using the very last questionmark)
660
    $pos = strrpos($link[0], '?');
661
    if($pos !== false){
662
        $src   = substr($link[0],0,$pos);
663
        $param = substr($link[0],$pos+1);
664
    }else{
665
        $src   = $link[0];
666
        $param = '';
667
    }
668
669
    //parse width and height
670
    if(preg_match('#(\d+)(x(\d+))?#i',$param,$size)){
671
        !empty($size[1]) ? $w = $size[1] : $w = null;
672
        !empty($size[3]) ? $h = $size[3] : $h = null;
673
    } else {
674
        $w = null;
675
        $h = null;
676
    }
677
678
    //get linking command
679
    if(preg_match('/nolink/i',$param)){
680
        $linking = 'nolink';
681
    }else if(preg_match('/direct/i',$param)){
682
        $linking = 'direct';
683
    }else if(preg_match('/linkonly/i',$param)){
684
        $linking = 'linkonly';
685
    }else{
686
        $linking = 'details';
687
    }
688
689
    //get caching command
690
    if (preg_match('/(nocache|recache)/i',$param,$cachemode)){
691
        $cache = $cachemode[1];
692
    }else{
693
        $cache = 'cache';
694
    }
695
696
    // Check whether this is a local or remote image
697
    if ( media_isexternal($src) ) {
698
        $call = 'externalmedia';
699
    } else {
700
        $call = 'internalmedia';
701
    }
702
703
    $params = array(
704
        'type'=>$call,
705
        'src'=>$src,
706
        'title'=>$link[1],
707
        'align'=>$align,
708
        'width'=>$w,
709
        'height'=>$h,
710
        'cache'=>$cache,
711
        'linking'=>$linking,
712
    );
713
714
    return $params;
715
}
716
717
//------------------------------------------------------------------------
718
interface Doku_Handler_CallWriter_Interface {
719
    public function writeCall($call);
720
    public function writeCalls($calls);
721
    public function finalise();
722
}
723
724
class Doku_Handler_CallWriter implements Doku_Handler_CallWriter_Interface {
725
726
    var $Handler;
727
728
    /**
729
     * @param Doku_Handler $Handler
730
     */
731
    function __construct(Doku_Handler $Handler) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
732
        $this->Handler = $Handler;
733
    }
734
735
    function writeCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
736
        $this->Handler->calls[] = $call;
0 ignored issues
show
Bug introduced by
The property calls cannot be accessed from this context as it is declared private in class Doku_Handler.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
737
    }
738
739
    function writeCalls($calls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
740
        $this->Handler->calls = array_merge($this->Handler->calls, $calls);
0 ignored issues
show
Bug introduced by
The property calls cannot be accessed from this context as it is declared private in class Doku_Handler.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
741
    }
742
743
    // function is required, but since this call writer is first/highest in
744
    // the chain it is not required to do anything
745
    function finalise() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
746
        unset($this->Handler);
747
    }
748
}
749
750
//------------------------------------------------------------------------
751
/**
752
 * Generic call writer class to handle nesting of rendering instructions
753
 * within a render instruction. Also see nest() method of renderer base class
754
 *
755
 * @author    Chris Smith <[email protected]>
756
 */
757
class Doku_Handler_Nest implements Doku_Handler_CallWriter_Interface {
758
759
    var $CallWriter;
760
    var $calls = array();
761
762
    var $closingInstruction;
763
764
    /**
765
     * constructor
766
     *
767
     * @param  Doku_Handler_CallWriter $CallWriter     the renderers current call writer
768
     * @param  string     $close          closing instruction name, this is required to properly terminate the
769
     *                                    syntax mode if the document ends without a closing pattern
770
     */
771
    function __construct(Doku_Handler_CallWriter_Interface $CallWriter, $close="nest_close") {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
772
        $this->CallWriter = $CallWriter;
773
774
        $this->closingInstruction = $close;
775
    }
776
777
    function writeCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
778
        $this->calls[] = $call;
779
    }
780
781
    function writeCalls($calls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
782
        $this->calls = array_merge($this->calls, $calls);
783
    }
784
785
    function finalise() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
786
        $last_call = end($this->calls);
787
        $this->writeCall(array($this->closingInstruction,array(), $last_call[2]));
788
789
        $this->process();
790
        $this->CallWriter->finalise();
791
        unset($this->CallWriter);
792
    }
793
794
    function process() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
795
        // merge consecutive cdata
796
        $unmerged_calls = $this->calls;
797
        $this->calls = array();
798
799
        foreach ($unmerged_calls as $call) $this->addCall($call);
800
801
        $first_call = reset($this->calls);
802
        $this->CallWriter->writeCall(array("nest", array($this->calls), $first_call[2]));
803
    }
804
805
    function addCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
806
        $key = count($this->calls);
807
        if ($key and ($call[0] == 'cdata') and ($this->calls[$key-1][0] == 'cdata')) {
808
            $this->calls[$key-1][1][0] .= $call[1][0];
809
        } else if ($call[0] == 'eol') {
810
            // do nothing (eol shouldn't be allowed, to counter preformatted fix in #1652 & #1699)
811
        } else {
812
            $this->calls[] = $call;
813
        }
814
    }
815
}
816
817
class Doku_Handler_List implements Doku_Handler_CallWriter_Interface {
818
819
    var $CallWriter;
820
821
    var $calls = array();
822
    var $listCalls = array();
823
    var $listStack = array();
824
825
    const NODE = 1;
826
827
    function __construct(Doku_Handler_CallWriter_Interface $CallWriter) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
828
        $this->CallWriter = $CallWriter;
829
    }
830
831
    function writeCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
832
        $this->calls[] = $call;
833
    }
834
835
    // Probably not needed but just in case...
836
    function writeCalls($calls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
837
        $this->calls = array_merge($this->calls, $calls);
838
#        $this->CallWriter->writeCalls($this->calls);
839
    }
840
841
    function finalise() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
842
        $last_call = end($this->calls);
843
        $this->writeCall(array('list_close',array(), $last_call[2]));
844
845
        $this->process();
846
        $this->CallWriter->finalise();
847
        unset($this->CallWriter);
848
    }
849
850
    //------------------------------------------------------------------------
851
    function process() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
852
853
        foreach ( $this->calls as $call ) {
854
            switch ($call[0]) {
855
                case 'list_item':
856
                    $this->listOpen($call);
857
                break;
858
                case 'list_open':
859
                    $this->listStart($call);
860
                break;
861
                case 'list_close':
862
                    $this->listEnd($call);
863
                break;
864
                default:
865
                    $this->listContent($call);
866
                break;
867
            }
868
        }
869
870
        $this->CallWriter->writeCalls($this->listCalls);
871
    }
872
873
    //------------------------------------------------------------------------
874
    function listStart($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
875
        $depth = $this->interpretSyntax($call[1][0], $listType);
876
877
        $this->initialDepth = $depth;
0 ignored issues
show
Bug introduced by
The property initialDepth does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
878
        //                   array(list type, current depth, index of current listitem_open)
879
        $this->listStack[] = array($listType, $depth, 1);
880
881
        $this->listCalls[] = array('list'.$listType.'_open',array(),$call[2]);
882
        $this->listCalls[] = array('listitem_open',array(1),$call[2]);
883
        $this->listCalls[] = array('listcontent_open',array(),$call[2]);
884
    }
885
886
    //------------------------------------------------------------------------
887
    function listEnd($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
888
        $closeContent = true;
889
890
        while ( $list = array_pop($this->listStack) ) {
891
            if ( $closeContent ) {
892
                $this->listCalls[] = array('listcontent_close',array(),$call[2]);
893
                $closeContent = false;
894
            }
895
            $this->listCalls[] = array('listitem_close',array(),$call[2]);
896
            $this->listCalls[] = array('list'.$list[0].'_close', array(), $call[2]);
897
        }
898
    }
899
900
    //------------------------------------------------------------------------
901
    function listOpen($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
902
        $depth = $this->interpretSyntax($call[1][0], $listType);
903
        $end = end($this->listStack);
904
        $key = key($this->listStack);
905
906
        // Not allowed to be shallower than initialDepth
907
        if ( $depth < $this->initialDepth ) {
908
            $depth = $this->initialDepth;
909
        }
910
911
        //------------------------------------------------------------------------
912
        if ( $depth == $end[1] ) {
913
914
            // Just another item in the list...
915
            if ( $listType == $end[0] ) {
916
                $this->listCalls[] = array('listcontent_close',array(),$call[2]);
917
                $this->listCalls[] = array('listitem_close',array(),$call[2]);
918
                $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]);
919
                $this->listCalls[] = array('listcontent_open',array(),$call[2]);
920
921
                // new list item, update list stack's index into current listitem_open
922
                $this->listStack[$key][2] = count($this->listCalls) - 2;
923
924
            // Switched list type...
925
            } else {
926
927
                $this->listCalls[] = array('listcontent_close',array(),$call[2]);
928
                $this->listCalls[] = array('listitem_close',array(),$call[2]);
929
                $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]);
930
                $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
931
                $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
932
                $this->listCalls[] = array('listcontent_open',array(),$call[2]);
933
934
                array_pop($this->listStack);
935
                $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
936
            }
937
938
        //------------------------------------------------------------------------
939
        // Getting deeper...
940
        } else if ( $depth > $end[1] ) {
941
942
            $this->listCalls[] = array('listcontent_close',array(),$call[2]);
943
            $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
944
            $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
945
            $this->listCalls[] = array('listcontent_open',array(),$call[2]);
946
947
            // set the node/leaf state of this item's parent listitem_open to NODE
948
            $this->listCalls[$this->listStack[$key][2]][1][1] = self::NODE;
949
950
            $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
951
952
        //------------------------------------------------------------------------
953
        // Getting shallower ( $depth < $end[1] )
954
        } else {
955
            $this->listCalls[] = array('listcontent_close',array(),$call[2]);
956
            $this->listCalls[] = array('listitem_close',array(),$call[2]);
957
            $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]);
958
959
            // Throw away the end - done
960
            array_pop($this->listStack);
961
962
            while (1) {
963
                $end = end($this->listStack);
964
                $key = key($this->listStack);
965
966
                if ( $end[1] <= $depth ) {
967
968
                    // Normalize depths
969
                    $depth = $end[1];
970
971
                    $this->listCalls[] = array('listitem_close',array(),$call[2]);
972
973
                    if ( $end[0] == $listType ) {
974
                        $this->listCalls[] = array('listitem_open',array($depth-1),$call[2]);
975
                        $this->listCalls[] = array('listcontent_open',array(),$call[2]);
976
977
                        // new list item, update list stack's index into current listitem_open
978
                        $this->listStack[$key][2] = count($this->listCalls) - 2;
979
980
                    } else {
981
                        // Switching list type...
982
                        $this->listCalls[] = array('list'.$end[0].'_close', array(), $call[2]);
983
                        $this->listCalls[] = array('list'.$listType.'_open', array(), $call[2]);
984
                        $this->listCalls[] = array('listitem_open', array($depth-1), $call[2]);
985
                        $this->listCalls[] = array('listcontent_open',array(),$call[2]);
986
987
                        array_pop($this->listStack);
988
                        $this->listStack[] = array($listType, $depth, count($this->listCalls) - 2);
989
                    }
990
991
                    break;
992
993
                // Haven't dropped down far enough yet.... ( $end[1] > $depth )
994
                } else {
995
996
                    $this->listCalls[] = array('listitem_close',array(),$call[2]);
997
                    $this->listCalls[] = array('list'.$end[0].'_close',array(),$call[2]);
998
999
                    array_pop($this->listStack);
1000
1001
                }
1002
1003
            }
1004
1005
        }
1006
    }
1007
1008
    //------------------------------------------------------------------------
1009
    function listContent($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1010
        $this->listCalls[] = $call;
1011
    }
1012
1013
    //------------------------------------------------------------------------
1014
    function interpretSyntax($match, & $type) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1015
        if ( substr($match,-1) == '*' ) {
1016
            $type = 'u';
1017
        } else {
1018
            $type = 'o';
1019
        }
1020
        // Is the +1 needed? It used to be count(explode(...))
1021
        // but I don't think the number is seen outside this handler
1022
        return substr_count(str_replace("\t",'  ',$match), '  ') + 1;
1023
    }
1024
}
1025
1026
//------------------------------------------------------------------------
1027
class Doku_Handler_Preformatted implements Doku_Handler_CallWriter_Interface {
1028
1029
    var $CallWriter;
1030
1031
    var $calls = array();
1032
    var $pos;
1033
    var $text ='';
1034
1035
1036
1037
    function __construct(Doku_Handler_CallWriter_Interface $CallWriter) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1038
        $this->CallWriter = $CallWriter;
1039
    }
1040
1041
    function writeCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1042
        $this->calls[] = $call;
1043
    }
1044
1045
    // Probably not needed but just in case...
1046
    function writeCalls($calls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1047
        $this->calls = array_merge($this->calls, $calls);
1048
#        $this->CallWriter->writeCalls($this->calls);
1049
    }
1050
1051
    function finalise() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1052
        $last_call = end($this->calls);
1053
        $this->writeCall(array('preformatted_end',array(), $last_call[2]));
1054
1055
        $this->process();
1056
        $this->CallWriter->finalise();
1057
        unset($this->CallWriter);
1058
    }
1059
1060
    function process() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1061
        foreach ( $this->calls as $call ) {
1062
            switch ($call[0]) {
1063
                case 'preformatted_start':
1064
                    $this->pos = $call[2];
1065
                break;
1066
                case 'preformatted_newline':
1067
                    $this->text .= "\n";
1068
                break;
1069
                case 'preformatted_content':
1070
                    $this->text .= $call[1][0];
1071
                break;
1072
                case 'preformatted_end':
1073
                    if (trim($this->text)) {
1074
                        $this->CallWriter->writeCall(array('preformatted',array($this->text),$this->pos));
1075
                    }
1076
                    // see FS#1699 & FS#1652, add 'eol' instructions to ensure proper triggering of following p_open
1077
                    $this->CallWriter->writeCall(array('eol',array(),$this->pos));
1078
                    $this->CallWriter->writeCall(array('eol',array(),$this->pos));
1079
                break;
1080
            }
1081
        }
1082
    }
1083
1084
}
1085
1086
//------------------------------------------------------------------------
1087
class Doku_Handler_Quote implements Doku_Handler_CallWriter_Interface {
1088
1089
    var $CallWriter;
1090
1091
    var $calls = array();
1092
1093
    var $quoteCalls = array();
1094
1095
    function __construct(Doku_Handler_CallWriter_Interface $CallWriter) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1096
        $this->CallWriter = $CallWriter;
1097
    }
1098
1099
    function writeCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1100
        $this->calls[] = $call;
1101
    }
1102
1103
    // Probably not needed but just in case...
1104
    function writeCalls($calls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1105
        $this->calls = array_merge($this->calls, $calls);
1106
    }
1107
1108
    function finalise() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1109
        $last_call = end($this->calls);
1110
        $this->writeCall(array('quote_end',array(), $last_call[2]));
1111
1112
        $this->process();
1113
        $this->CallWriter->finalise();
1114
        unset($this->CallWriter);
1115
    }
1116
1117
    function process() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1118
1119
        $quoteDepth = 1;
1120
1121
        foreach ( $this->calls as $call ) {
1122
            switch ($call[0]) {
1123
1124
                case 'quote_start':
1125
1126
                    $this->quoteCalls[] = array('quote_open',array(),$call[2]);
1127
1128
                case 'quote_newline':
1129
1130
                    $quoteLength = $this->getDepth($call[1][0]);
1131
1132
                    if ( $quoteLength > $quoteDepth ) {
1133
                        $quoteDiff = $quoteLength - $quoteDepth;
1134
                        for ( $i = 1; $i <= $quoteDiff; $i++ ) {
1135
                            $this->quoteCalls[] = array('quote_open',array(),$call[2]);
1136
                        }
1137
                    } else if ( $quoteLength < $quoteDepth ) {
1138
                        $quoteDiff = $quoteDepth - $quoteLength;
1139
                        for ( $i = 1; $i <= $quoteDiff; $i++ ) {
1140
                            $this->quoteCalls[] = array('quote_close',array(),$call[2]);
1141
                        }
1142
                    } else {
1143
                        if ($call[0] != 'quote_start') $this->quoteCalls[] = array('linebreak',array(),$call[2]);
1144
                    }
1145
1146
                    $quoteDepth = $quoteLength;
1147
1148
                break;
1149
1150
                case 'quote_end':
1151
1152
                    if ( $quoteDepth > 1 ) {
1153
                        $quoteDiff = $quoteDepth - 1;
1154
                        for ( $i = 1; $i <= $quoteDiff; $i++ ) {
1155
                            $this->quoteCalls[] = array('quote_close',array(),$call[2]);
1156
                        }
1157
                    }
1158
1159
                    $this->quoteCalls[] = array('quote_close',array(),$call[2]);
1160
1161
                    $this->CallWriter->writeCalls($this->quoteCalls);
1162
                break;
1163
1164
                default:
1165
                    $this->quoteCalls[] = $call;
1166
                break;
1167
            }
1168
        }
1169
    }
1170
1171
    function getDepth($marker) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1172
        preg_match('/>{1,}/', $marker, $matches);
1173
        $quoteLength = strlen($matches[0]);
1174
        return $quoteLength;
1175
    }
1176
}
1177
1178
//------------------------------------------------------------------------
1179
class Doku_Handler_Table implements Doku_Handler_CallWriter_Interface {
1180
1181
    var $CallWriter;
1182
1183
    var $calls = array();
1184
    var $tableCalls = array();
1185
    var $maxCols = 0;
1186
    var $maxRows = 1;
1187
    var $currentCols = 0;
1188
    var $firstCell = false;
1189
    var $lastCellType = 'tablecell';
1190
    var $inTableHead = true;
1191
    var $currentRow = array('tableheader' => 0, 'tablecell' => 0);
1192
    var $countTableHeadRows = 0;
1193
1194
    function __construct(Doku_Handler_CallWriter_Interface $CallWriter) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1195
        $this->CallWriter = $CallWriter;
1196
    }
1197
1198
    function writeCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1199
        $this->calls[] = $call;
1200
    }
1201
1202
    // Probably not needed but just in case...
1203
    function writeCalls($calls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1204
        $this->calls = array_merge($this->calls, $calls);
1205
    }
1206
1207
    function finalise() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1208
        $last_call = end($this->calls);
1209
        $this->writeCall(array('table_end',array(), $last_call[2]));
1210
1211
        $this->process();
1212
        $this->CallWriter->finalise();
1213
        unset($this->CallWriter);
1214
    }
1215
1216
    //------------------------------------------------------------------------
1217
    function process() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1218
        foreach ( $this->calls as $call ) {
1219
            switch ( $call[0] ) {
1220
                case 'table_start':
1221
                    $this->tableStart($call);
1222
                break;
1223
                case 'table_row':
1224
                    $this->tableRowClose($call);
1225
                    $this->tableRowOpen(array('tablerow_open',$call[1],$call[2]));
1226
                break;
1227
                case 'tableheader':
1228
                case 'tablecell':
1229
                    $this->tableCell($call);
1230
                break;
1231
                case 'table_end':
1232
                    $this->tableRowClose($call);
1233
                    $this->tableEnd($call);
1234
                break;
1235
                default:
1236
                    $this->tableDefault($call);
1237
                break;
1238
            }
1239
        }
1240
        $this->CallWriter->writeCalls($this->tableCalls);
1241
    }
1242
1243
    function tableStart($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1244
        $this->tableCalls[] = array('table_open',$call[1],$call[2]);
1245
        $this->tableCalls[] = array('tablerow_open',array(),$call[2]);
1246
        $this->firstCell = true;
1247
    }
1248
1249
    function tableEnd($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1250
        $this->tableCalls[] = array('table_close',$call[1],$call[2]);
1251
        $this->finalizeTable();
1252
    }
1253
1254
    function tableRowOpen($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1255
        $this->tableCalls[] = $call;
1256
        $this->currentCols = 0;
1257
        $this->firstCell = true;
1258
        $this->lastCellType = 'tablecell';
1259
        $this->maxRows++;
1260
        if ($this->inTableHead) {
1261
            $this->currentRow = array('tablecell' => 0, 'tableheader' => 0);
1262
        }
1263
    }
1264
1265
    function tableRowClose($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1266
        if ($this->inTableHead && ($this->inTableHead = $this->isTableHeadRow())) {
1267
            $this->countTableHeadRows++;
1268
        }
1269
        // Strip off final cell opening and anything after it
1270
        while ( $discard = array_pop($this->tableCalls ) ) {
1271
1272
            if ( $discard[0] == 'tablecell_open' || $discard[0] == 'tableheader_open') {
1273
                break;
1274
            }
1275
            if (!empty($this->currentRow[$discard[0]])) {
1276
                $this->currentRow[$discard[0]]--;
1277
            }
1278
        }
1279
        $this->tableCalls[] = array('tablerow_close', array(), $call[2]);
1280
1281
        if ( $this->currentCols > $this->maxCols ) {
1282
            $this->maxCols = $this->currentCols;
1283
        }
1284
    }
1285
1286
    function isTableHeadRow() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1287
        $td = $this->currentRow['tablecell'];
1288
        $th = $this->currentRow['tableheader'];
1289
1290
        if (!$th || $td > 2) return false;
1291
        if (2*$td > $th) return false;
1292
1293
        return true;
1294
    }
1295
1296
    function tableCell($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1297
        if ($this->inTableHead) {
1298
            $this->currentRow[$call[0]]++;
1299
        }
1300
        if ( !$this->firstCell ) {
1301
1302
            // Increase the span
1303
            $lastCall = end($this->tableCalls);
1304
1305
            // A cell call which follows an open cell means an empty cell so span
1306
            if ( $lastCall[0] == 'tablecell_open' || $lastCall[0] == 'tableheader_open' ) {
1307
                 $this->tableCalls[] = array('colspan',array(),$call[2]);
1308
1309
            }
1310
1311
            $this->tableCalls[] = array($this->lastCellType.'_close',array(),$call[2]);
1312
            $this->tableCalls[] = array($call[0].'_open',array(1,null,1),$call[2]);
1313
            $this->lastCellType = $call[0];
1314
1315
        } else {
1316
1317
            $this->tableCalls[] = array($call[0].'_open',array(1,null,1),$call[2]);
1318
            $this->lastCellType = $call[0];
1319
            $this->firstCell = false;
1320
1321
        }
1322
1323
        $this->currentCols++;
1324
    }
1325
1326
    function tableDefault($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1327
        $this->tableCalls[] = $call;
1328
    }
1329
1330
    function finalizeTable() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1331
1332
        // Add the max cols and rows to the table opening
1333
        if ( $this->tableCalls[0][0] == 'table_open' ) {
1334
            // Adjust to num cols not num col delimeters
1335
            $this->tableCalls[0][1][] = $this->maxCols - 1;
1336
            $this->tableCalls[0][1][] = $this->maxRows;
1337
            $this->tableCalls[0][1][] = array_shift($this->tableCalls[0][1]);
1338
        } else {
1339
            trigger_error('First element in table call list is not table_open');
1340
        }
1341
1342
        $lastRow = 0;
1343
        $lastCell = 0;
1344
        $cellKey = array();
1345
        $toDelete = array();
1346
1347
        // if still in tableheader, then there can be no table header
1348
        // as all rows can't be within <THEAD>
1349
        if ($this->inTableHead) {
1350
            $this->inTableHead = false;
1351
            $this->countTableHeadRows = 0;
1352
        }
1353
1354
        // Look for the colspan elements and increment the colspan on the
1355
        // previous non-empty opening cell. Once done, delete all the cells
1356
        // that contain colspans
1357
        for ($key = 0 ; $key < count($this->tableCalls) ; ++$key) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1358
            $call = $this->tableCalls[$key];
1359
1360
            switch ($call[0]) {
1361
                case 'table_open' :
1362
                    if($this->countTableHeadRows) {
1363
                        array_splice($this->tableCalls, $key+1, 0, array(
1364
                              array('tablethead_open', array(), $call[2]))
1365
                        );
1366
                    }
1367
                    break;
1368
1369
                case 'tablerow_open':
1370
1371
                    $lastRow++;
1372
                    $lastCell = 0;
1373
                    break;
1374
1375
                case 'tablecell_open':
1376
                case 'tableheader_open':
1377
1378
                    $lastCell++;
1379
                    $cellKey[$lastRow][$lastCell] = $key;
1380
                    break;
1381
1382
                case 'table_align':
1383
1384
                    $prev = in_array($this->tableCalls[$key-1][0], array('tablecell_open', 'tableheader_open'));
1385
                    $next = in_array($this->tableCalls[$key+1][0], array('tablecell_close', 'tableheader_close'));
1386
                    // If the cell is empty, align left
1387
                    if ($prev && $next) {
1388
                        $this->tableCalls[$key-1][1][1] = 'left';
1389
1390
                    // If the previous element was a cell open, align right
1391
                    } elseif ($prev) {
1392
                        $this->tableCalls[$key-1][1][1] = 'right';
1393
1394
                    // If the next element is the close of an element, align either center or left
1395
                    } elseif ( $next) {
1396
                        if ( $this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] == 'right' ) {
1397
                            $this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] = 'center';
1398
                        } else {
1399
                            $this->tableCalls[$cellKey[$lastRow][$lastCell]][1][1] = 'left';
1400
                        }
1401
1402
                    }
1403
1404
                    // Now convert the whitespace back to cdata
1405
                    $this->tableCalls[$key][0] = 'cdata';
1406
                    break;
1407
1408
                case 'colspan':
1409
1410
                    $this->tableCalls[$key-1][1][0] = false;
1411
1412
                    for($i = $key-2; $i >= $cellKey[$lastRow][1]; $i--) {
1413
1414
                        if ( $this->tableCalls[$i][0] == 'tablecell_open' || $this->tableCalls[$i][0] == 'tableheader_open' ) {
1415
1416
                            if ( false !== $this->tableCalls[$i][1][0] ) {
1417
                                $this->tableCalls[$i][1][0]++;
1418
                                break;
1419
                            }
1420
1421
                        }
1422
                    }
1423
1424
                    $toDelete[] = $key-1;
1425
                    $toDelete[] = $key;
1426
                    $toDelete[] = $key+1;
1427
                    break;
1428
1429
                case 'rowspan':
1430
1431
                    if ( $this->tableCalls[$key-1][0] == 'cdata' ) {
1432
                        // ignore rowspan if previous call was cdata (text mixed with :::) we don't have to check next call as that wont match regex
1433
                        $this->tableCalls[$key][0] = 'cdata';
1434
1435
                    } else {
1436
1437
                        $spanning_cell = null;
1438
1439
                        // can't cross thead/tbody boundary
1440
                        if (!$this->countTableHeadRows || ($lastRow-1 != $this->countTableHeadRows)) {
1441
                            for($i = $lastRow-1; $i > 0; $i--) {
1442
1443
                                if ( $this->tableCalls[$cellKey[$i][$lastCell]][0] == 'tablecell_open' || $this->tableCalls[$cellKey[$i][$lastCell]][0] == 'tableheader_open' ) {
1444
1445
                                    if ($this->tableCalls[$cellKey[$i][$lastCell]][1][2] >= $lastRow - $i) {
1446
                                        $spanning_cell = $i;
1447
                                        break;
1448
                                    }
1449
1450
                                }
1451
                            }
1452
                        }
1453
                        if (is_null($spanning_cell)) {
1454
                            // No spanning cell found, so convert this cell to
1455
                            // an empty one to avoid broken tables
1456
                            $this->tableCalls[$key][0] = 'cdata';
1457
                            $this->tableCalls[$key][1][0] = '';
1458
                            continue;
1459
                        }
1460
                        $this->tableCalls[$cellKey[$spanning_cell][$lastCell]][1][2]++;
1461
1462
                        $this->tableCalls[$key-1][1][2] = false;
1463
1464
                        $toDelete[] = $key-1;
1465
                        $toDelete[] = $key;
1466
                        $toDelete[] = $key+1;
1467
                    }
1468
                    break;
1469
1470
                case 'tablerow_close':
1471
1472
                    // Fix broken tables by adding missing cells
1473
                    while (++$lastCell < $this->maxCols) {
1474
                        array_splice($this->tableCalls, $key, 0, array(
1475
                               array('tablecell_open', array(1, null, 1), $call[2]),
1476
                               array('cdata', array(''), $call[2]),
1477
                               array('tablecell_close', array(), $call[2])));
1478
                        $key += 3;
1479
                    }
1480
1481
                    if($this->countTableHeadRows == $lastRow) {
1482
                        array_splice($this->tableCalls, $key+1, 0, array(
1483
                              array('tablethead_close', array(), $call[2])));
1484
                    }
1485
                    break;
1486
1487
            }
1488
        }
1489
1490
        // condense cdata
1491
        $cnt = count($this->tableCalls);
1492
        for( $key = 0; $key < $cnt; $key++){
1493
            if($this->tableCalls[$key][0] == 'cdata'){
1494
                $ckey = $key;
1495
                $key++;
1496
                while($this->tableCalls[$key][0] == 'cdata'){
1497
                    $this->tableCalls[$ckey][1][0] .= $this->tableCalls[$key][1][0];
1498
                    $toDelete[] = $key;
1499
                    $key++;
1500
                }
1501
                continue;
1502
            }
1503
        }
1504
1505
        foreach ( $toDelete as $delete ) {
1506
            unset($this->tableCalls[$delete]);
1507
        }
1508
        $this->tableCalls = array_values($this->tableCalls);
1509
    }
1510
}
1511
1512
1513
/**
1514
 * Handler for paragraphs
1515
 *
1516
 * @author Harry Fuecks <[email protected]>
1517
 */
1518
class Doku_Handler_Block {
1519
    var $calls = array();
1520
    var $skipEol = false;
1521
    var $inParagraph = false;
1522
1523
    // Blocks these should not be inside paragraphs
1524
    var $blockOpen = array(
1525
            'header',
1526
            'listu_open','listo_open','listitem_open','listcontent_open',
1527
            'table_open','tablerow_open','tablecell_open','tableheader_open','tablethead_open',
1528
            'quote_open',
1529
            'code','file','hr','preformatted','rss',
1530
            'htmlblock','phpblock',
1531
            'footnote_open',
1532
        );
1533
1534
    var $blockClose = array(
1535
            'header',
1536
            'listu_close','listo_close','listitem_close','listcontent_close',
1537
            'table_close','tablerow_close','tablecell_close','tableheader_close','tablethead_close',
1538
            'quote_close',
1539
            'code','file','hr','preformatted','rss',
1540
            'htmlblock','phpblock',
1541
            'footnote_close',
1542
        );
1543
1544
    // Stacks can contain paragraphs
1545
    var $stackOpen = array(
1546
        'section_open',
1547
        );
1548
1549
    var $stackClose = array(
1550
        'section_close',
1551
        );
1552
1553
1554
    /**
1555
     * Constructor. Adds loaded syntax plugins to the block and stack
1556
     * arrays
1557
     *
1558
     * @author Andreas Gohr <[email protected]>
1559
     */
1560
    function __construct(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1561
        global $DOKU_PLUGINS;
1562
        //check if syntax plugins were loaded
1563
        if(empty($DOKU_PLUGINS['syntax'])) return;
1564
        foreach($DOKU_PLUGINS['syntax'] as $n => $p){
1565
            $ptype = $p->getPType();
1566
            if($ptype == 'block'){
1567
                $this->blockOpen[]  = 'plugin_'.$n;
1568
                $this->blockClose[] = 'plugin_'.$n;
1569
            }elseif($ptype == 'stack'){
1570
                $this->stackOpen[]  = 'plugin_'.$n;
1571
                $this->stackClose[] = 'plugin_'.$n;
1572
            }
1573
        }
1574
    }
1575
1576
    function openParagraph($pos){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1577
        if ($this->inParagraph) return;
1578
        $this->calls[] = array('p_open',array(), $pos);
1579
        $this->inParagraph = true;
1580
        $this->skipEol = true;
1581
    }
1582
1583
    /**
1584
     * Close a paragraph if needed
1585
     *
1586
     * This function makes sure there are no empty paragraphs on the stack
1587
     *
1588
     * @author Andreas Gohr <[email protected]>
1589
     */
1590
    function closeParagraph($pos){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1591
        if (!$this->inParagraph) return;
1592
        // look back if there was any content - we don't want empty paragraphs
1593
        $content = '';
1594
        $ccount = count($this->calls);
1595
        for($i=$ccount-1; $i>=0; $i--){
1596
            if($this->calls[$i][0] == 'p_open'){
1597
                break;
1598
            }elseif($this->calls[$i][0] == 'cdata'){
1599
                $content .= $this->calls[$i][1][0];
1600
            }else{
1601
                $content = 'found markup';
1602
                break;
1603
            }
1604
        }
1605
1606
        if(trim($content)==''){
1607
            //remove the whole paragraph
1608
            //array_splice($this->calls,$i); // <- this is much slower than the loop below
1609
            for($x=$ccount; $x>$i; $x--) array_pop($this->calls);
1610
        }else{
1611
            // remove ending linebreaks in the paragraph
1612
            $i=count($this->calls)-1;
1613
            if ($this->calls[$i][0] == 'cdata') $this->calls[$i][1][0] = rtrim($this->calls[$i][1][0],DOKU_PARSER_EOL);
1614
            $this->calls[] = array('p_close',array(), $pos);
1615
        }
1616
1617
        $this->inParagraph = false;
1618
        $this->skipEol = true;
1619
    }
1620
1621
    function addCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1622
        $key = count($this->calls);
1623
        if ($key and ($call[0] == 'cdata') and ($this->calls[$key-1][0] == 'cdata')) {
1624
            $this->calls[$key-1][1][0] .= $call[1][0];
1625
        } else {
1626
            $this->calls[] = $call;
1627
        }
1628
    }
1629
1630
    // simple version of addCall, without checking cdata
1631
    function storeCall($call) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1632
        $this->calls[] = $call;
1633
    }
1634
1635
    /**
1636
     * Processes the whole instruction stack to open and close paragraphs
1637
     *
1638
     * @author Harry Fuecks <[email protected]>
1639
     * @author Andreas Gohr <[email protected]>
1640
     */
1641
    function process($calls) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
1642
        // open first paragraph
1643
        $this->openParagraph(0);
1644
        foreach ( $calls as $key => $call ) {
1645
            $cname = $call[0];
1646
            if ($cname == 'plugin') {
1647
                $cname='plugin_'.$call[1][0];
1648
                $plugin = true;
1649
                $plugin_open = (($call[1][2] == DOKU_LEXER_ENTER) || ($call[1][2] == DOKU_LEXER_SPECIAL));
1650
                $plugin_close = (($call[1][2] == DOKU_LEXER_EXIT) || ($call[1][2] == DOKU_LEXER_SPECIAL));
1651
            } else {
1652
                $plugin = false;
1653
            }
1654
            /* stack */
1655
            if ( in_array($cname,$this->stackClose ) && (!$plugin || $plugin_close)) {
0 ignored issues
show
Bug introduced by
The variable $plugin_close 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...
1656
                $this->closeParagraph($call[2]);
1657
                $this->storeCall($call);
1658
                $this->openParagraph($call[2]);
1659
                continue;
1660
            }
1661
            if ( in_array($cname,$this->stackOpen ) && (!$plugin || $plugin_open) ) {
0 ignored issues
show
Bug introduced by
The variable $plugin_open 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...
1662
                $this->closeParagraph($call[2]);
1663
                $this->storeCall($call);
1664
                $this->openParagraph($call[2]);
1665
                continue;
1666
            }
1667
            /* block */
1668
            // If it's a substition it opens and closes at the same call.
1669
            // To make sure next paragraph is correctly started, let close go first.
1670
            if ( in_array($cname, $this->blockClose) && (!$plugin || $plugin_close)) {
1671
                $this->closeParagraph($call[2]);
1672
                $this->storeCall($call);
1673
                $this->openParagraph($call[2]);
1674
                continue;
1675
            }
1676
            if ( in_array($cname, $this->blockOpen) && (!$plugin || $plugin_open)) {
1677
                $this->closeParagraph($call[2]);
1678
                $this->storeCall($call);
1679
                continue;
1680
            }
1681
            /* eol */
1682
            if ( $cname == 'eol' ) {
1683
                // Check this isn't an eol instruction to skip...
1684
                if ( !$this->skipEol ) {
1685
                    // Next is EOL => double eol => mark as paragraph
1686
                    if ( isset($calls[$key+1]) && $calls[$key+1][0] == 'eol' ) {
1687
                        $this->closeParagraph($call[2]);
1688
                        $this->openParagraph($call[2]);
1689
                    } else {
1690
                        //if this is just a single eol make a space from it
1691
                        $this->addCall(array('cdata',array(DOKU_PARSER_EOL), $call[2]));
1692
                    }
1693
                }
1694
                continue;
1695
            }
1696
            /* normal */
1697
            $this->addCall($call);
1698
            $this->skipEol = false;
1699
        }
1700
        // close last paragraph
1701
        $call = end($this->calls);
1702
        $this->closeParagraph($call[2]);
1703
        return $this->calls;
1704
    }
1705
}
1706
1707
//Setup VIM: ex: et ts=4 :
1708