Failed Conditions
Push — psr2 ( ffc2cc...de2261 )
by Andreas
05:28
created

Doku_Parser::addBaseMode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
use dokuwiki\Lexer\Lexer;
4
use dokuwiki\ParserMode\Base;
5
use dokuwiki\ParserMode\ModeInterface;
6
7
/**
8
 * Define various types of modes used by the parser - they are used to
9
 * populate the list of modes another mode accepts
10
 */
11
global $PARSER_MODES;
12
$PARSER_MODES = array(
13
    // containers are complex modes that can contain many other modes
14
    // hr breaks the principle but they shouldn't be used in tables / lists
15
    // so they are put here
16
    'container'    => array('listblock','table','quote','hr'),
17
18
    // some mode are allowed inside the base mode only
19
    'baseonly'     => array('header'),
20
21
    // modes for styling text -- footnote behaves similar to styling
22
    'formatting'   => array('strong', 'emphasis', 'underline', 'monospace',
23
                            'subscript', 'superscript', 'deleted', 'footnote'),
24
25
    // modes where the token is simply replaced - they can not contain any
26
    // other modes
27
    'substition'   => array('acronym','smiley','wordblock','entity',
28
                            'camelcaselink', 'internallink','media',
29
                            'externallink','linebreak','emaillink',
30
                            'windowssharelink','filelink','notoc',
31
                            'nocache','multiplyentity','quotes','rss'),
32
33
    // modes which have a start and end token but inside which
34
    // no other modes should be applied
35
    'protected'    => array('preformatted','code','file','php','html','htmlblock','phpblock'),
36
37
    // inside this mode no wiki markup should be applied but lineendings
38
    // and whitespace isn't preserved
39
    'disabled'     => array('unformatted'),
40
41
    // used to mark paragraph boundaries
42
    'paragraphs'   => array('eol')
43
);
44
45
/**
46
 * Sets up the Lexer with modes and points it to the Handler
47
 * For an intro to the Lexer see: wiki:parser
48
 */
49
class Doku_Parser {
50
51
    /** @var Doku_Handler */
52
    protected $handler;
53
54
    /** @var Lexer $lexer */
55
    protected $lexer;
56
57
    /** @var ModeInterface[] $modes */
58
    protected $modes = array();
59
60
    /** @var bool mode connections may only be set up once */
61
    protected $connected = false;
62
63
    /**
64
     * Doku_Parser constructor.
65
     *
66
     * @param Doku_Handler $handler
67
     */
68
    public function __construct(Doku_Handler $handler) {
69
        $this->handler = $handler;
70
    }
71
72
    /**
73
     * Adds the base mode and initialized the lexer
74
     *
75
     * @param Base $BaseMode
76
     */
77
    protected function addBaseMode($BaseMode) {
78
        $this->modes['base'] = $BaseMode;
79
        if ( !$this->lexer ) {
80
            $this->lexer = new Lexer($this->handler, 'base', true);
81
        }
82
        $this->modes['base']->Lexer = $this->lexer;
83
    }
84
85
    /**
86
     * Add a new syntax element (mode) to the parser
87
     *
88
     * PHP preserves order of associative elements
89
     * Mode sequence is important
90
     *
91
     * @param string $name
92
     * @param ModeInterface $Mode
93
     */
94
    public function addMode($name, ModeInterface $Mode) {
95
        if ( !isset($this->modes['base']) ) {
96
            $this->addBaseMode(new Base());
97
        }
98
        $Mode->Lexer = $this->lexer; // FIXME should be done by setter
0 ignored issues
show
Bug introduced by
Accessing Lexer on the interface dokuwiki\ParserMode\ModeInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
99
        $this->modes[$name] = $Mode;
100
    }
101
102
    /**
103
     * Connect all modes with each other
104
     *
105
     * This is the last step before actually parsing.
106
     */
107
    protected function connectModes() {
108
109
        if ( $this->connected ) {
110
            return;
111
        }
112
113
        foreach ( array_keys($this->modes) as $mode ) {
114
            // Base isn't connected to anything
115
            if ( $mode == 'base' ) {
116
                continue;
117
            }
118
            $this->modes[$mode]->preConnect();
119
120
            foreach ( array_keys($this->modes) as $cm ) {
121
122
                if ( $this->modes[$cm]->accepts($mode) ) {
123
                    $this->modes[$mode]->connectTo($cm);
124
                }
125
126
            }
127
128
            $this->modes[$mode]->postConnect();
129
        }
130
131
        $this->connected = true;
132
    }
133
134
    /**
135
     * Parses wiki syntax to instructions
136
     *
137
     * @param string $doc the wiki syntax text
138
     * @return array instructions
139
     */
140
    public function parse($doc) {
141
        $this->connectModes();
142
        // Normalize CRs and pad doc
143
        $doc = "\n".str_replace("\r\n","\n",$doc)."\n";
144
        $this->lexer->parse($doc);
145
        $this->handler->_finalize();
146
        return $this->handler->calls;
147
    }
148
149
}
150