Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * Library of functions and constants for module wiki
19
 *
20
 * It contains the great majority of functions defined by Moodle
21
 * that are mandatory to develop a module.
22
 *
23
 * @package mod_wiki
24
 * @copyright 2009 Marc Alier, Jordi Piguillem marc.alier@upc.edu
25
 * @copyright 2009 Universitat Politecnica de Catalunya http://www.upc.edu
26
 *
27
 * @author Jordi Piguillem
28
 * @author Marc Alier
29
 * @author David Jimenez
30
 * @author Josep Arus
31
 * @author Kenneth Riba
32
 *
33
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34
 */
35
 
36
defined('MOODLE_INTERNAL') || die();
37
 
38
/**
39
 * Generic parser implementation
40
 *
41
 * @author Josep Arús
42
 *
43
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
44
 * @package mod_wiki
45
 */
46
class wiki_parser_proxy {
47
    /**
48
     * @var array $parsers Array of parser instances
49
     */
50
    private static $parsers = [];
51
 
52
    /**
53
     * Parse a string using a specific parser
54
     *
55
     * @param string $string The string to parse
56
     * @param string $type The parser type
57
     * @param array $options The parser options
58
     * @return mixed The parsed string or false if the parser type is not found
59
     */
60
    public static function parse(&$string, $type, $options = []) {
61
        $type = strtolower($type);
62
        self::$parsers[$type] = null; // Reset the current parser because it may have other options.
63
        if (self::create_parser_instance($type)) {
64
            return self::$parsers[$type]->parse($string, $options);
65
        } else {
66
            return false;
67
        }
68
    }
69
 
70
    public static function get_token($name, $type) {
71
        if (self::create_parser_instance($type)) {
72
            return self::$parsers[$type]->get_token($name);
73
        } else {
74
            return false;
75
        }
76
    }
77
 
78
    public static function get_section(&$string, $type, $section, $allcontent = false) {
79
        if (self::create_parser_instance($type)) {
80
            $content = self::$parsers[$type]->get_section($section, $string, true);
81
 
82
            if ($allcontent) {
83
                return $content;
84
            } else {
85
                return is_array($content) ? $content[1] : null;
86
            }
87
        } else {
88
            return false;
89
        }
90
    }
91
 
92
    private static function create_parser_instance($type) {
93
        global $CFG;
94
        $type = clean_param($type, PARAM_ALPHA);
95
        if (empty(self::$parsers[$type])) {
96
            $path = "$CFG->dirroot/mod/wiki/parser/markups/$type.php";
97
            if (!file_exists($path)) {
98
                throw new moodle_exception("Parser type $type not found");
99
            }
100
            include_once($path);
101
            $class = strtolower($type) . "_parser";
102
            if (class_exists($class)) {
103
                self::$parsers[$type] = new $class;
104
                return true;
105
            } else {
106
                return false;
107
            }
108
        } else {
109
            return true;
110
        }
111
    }
112
}
113
 
114
require_once('utils.php');
115
 
116
abstract class generic_parser {
117
    protected $string;
118
 
119
    protected $blockrules = array();
120
    protected $tagrules = array();
121
 
122
    private $rulestack = array();
123
 
124
    protected $parserstatus = 'Before';
125
 
126
    /**
127
     * Dynamic return values
128
     */
129
 
130
    protected $returnvalues = array();
131
 
132
    private $nowikiindex = array();
133
 
134
    protected $nowikitoken = "%!";
135
 
136
    public function __construct() {
137
    }
138
 
139
    /**
140
     * Parse function
141
     */
142
    public function parse(&$string, $options = array()) {
143
        if (!is_string($string)) {
144
            return false;
145
        }
146
 
147
        $this->string =& $string;
148
 
149
        $this->set_options(is_array($options) ? $options : array());
150
 
151
        $this->initialize_nowiki_index();
152
 
153
        if (method_exists($this, 'before_parsing')) {
154
            $this->before_parsing();
155
        }
156
 
157
        $this->parserstatus = 'Parsing';
158
 
159
        foreach ($this->blockrules as $name => $block) {
160
            $this->process_block_rule($name, $block);
161
        }
162
 
163
        $this->commit_nowiki_index();
164
 
165
        $this->parserstatus = 'After';
166
 
167
        if (method_exists($this, 'after_parsing')) {
168
            $this->after_parsing();
169
        }
170
 
171
        return array('parsed_text' => $this->string) + $this->returnvalues;
172
    }
173
 
174
    /**
175
     * Initialize options
176
     */
177
    protected function set_options($options) {
178
    }
179
 
180
    /**
181
     * Block processing function & callbacks
182
     */
183
    protected function process_block_rule($name, $block) {
184
        $this->rulestack[] = array('callback' => method_exists($this, $name . "_block_rule") ? $name . "_block_rule" : null,
185
            'rule' => $block);
186
 
187
        $this->string = preg_replace_callback($block['expression'], array($this, 'block_callback'), $this->string);
188
 
189
        array_pop($this->rulestack);
190
    }
191
 
192
    private function block_callback($match) {
193
        $rule = end($this->rulestack);
194
        if (!empty($rule['callback'])) {
195
            $stuff = $this->{$rule['callback']}($match);
196
        } else {
197
            $stuff = $match[1];
198
        }
199
 
200
        if (is_array($stuff) && $rule['rule']['tag']) {
201
            $this->rules($stuff[0], $rule['rule']['tags']);
202
            $stuff = "\n" . parser_utils::h($rule['rule']['tag'], $stuff[0], $stuff[1]) . "\n";
203
        } else {
204
            if (!isset($rule['rule']['tags'])) {
205
                $rule['rule']['tags'] = null;
206
            }
207
            $this->rules($stuff, $rule['rule']['tags']);
208
            if (isset($rule['rule']['tag']) && is_string($rule['rule']['tag'])) {
209
                $stuff = "\n" . parser_utils::h($rule['rule']['tag'], $stuff) . "\n";
210
            }
211
        }
212
 
213
        return $stuff;
214
    }
215
 
216
    /**
217
     * Rules processing function & callback
218
     */
219
 
220
    final protected function rules(&$text, $rules = null) {
221
        if ($rules === null) {
222
            $rules = array('except' => array());
223
        } else if (is_array($rules) && count($rules) > 1) {
224
            $rules = array('only' => $rules);
225
        }
226
 
227
        if (isset($rules['only']) && is_array($rules['only'])) {
228
            $rules = $rules['only'];
229
            foreach ($rules as $r) {
230
                if (!empty($this->tagrules[$r])) {
231
                    $this->process_tag_rule($r, $this->tagrules[$r], $text);
232
                }
233
            }
234
        } else if (isset($rules['except']) && is_array($rules['except'])) {
235
            $rules = $rules['except'];
236
            foreach ($this->tagrules as $r => $tr) {
237
                if (!in_array($r, $rules)) {
238
                    $this->process_tag_rule($r, $tr, $text);
239
                }
240
            }
241
        }
242
    }
243
 
244
    private function process_tag_rule($name, $rule, &$text) {
245
        if (method_exists($this, $name . "_tag_rule")) {
246
            $this->rulestack[] = array('callback' => $name . "_tag_rule", 'rule' => $rule);
247
            $text = preg_replace_callback($rule['expression'], array($this, 'tag_callback'), $text);
248
            array_pop($this->rulestack);
249
        } else {
250
            if (isset($rule['simple'])) {
251
                $replace = "<{$rule['tag']} />";
252
            } else {
253
                $replace = parser_utils::h($rule['tag'], "$1");
254
            }
255
 
256
            $text = preg_replace($rule['expression'], $replace, $text);
257
        }
258
    }
259
 
260
    private function tag_callback($match) {
261
        $rule = end($this->rulestack);
262
        $stuff = $this->{$rule['callback']}($match);
263
 
264
        if (is_array($stuff)) {
265
            return parser_utils::h($rule['rule']['tag'], $stuff[0], $stuff[1]);
266
        } else {
267
            return $stuff;
268
        }
269
    }
270
 
271
    /**
272
     * Special nowiki parser index
273
     */
274
 
275
    private function initialize_nowiki_index() {
276
        $token = "\Q" . $this->nowikitoken . "\E";
277
        $this->string = preg_replace_callback("/" . $token . "\d+" . $token . "/",
278
            array($this, "initialize_nowiki_index_callback"), $this->string);
279
    }
280
 
281
    private function initialize_nowiki_index_callback($match) {
282
        return $this->protect($match[0]);
283
    }
284
 
285
    protected function protect($text) {
286
        $this->nowikiindex[] = $text;
287
 
288
        return $this->nowikitoken . (count($this->nowikiindex) - 1) . $this->nowikitoken;
289
    }
290
 
291
    private function commit_nowiki_index() {
292
        $token = "\Q" . $this->nowikitoken . "\E";
293
        $this->string = preg_replace_callback("/" . $token . "(\d+)" . $token . "/",
294
            array($this, "commit_nowiki_index_callback"), $this->string);
295
    }
296
 
297
    private function commit_nowiki_index_callback($match) {
298
        return $this->nowikiindex[intval($match[1])];
299
    }
300
 
301
    /**
302
     * Get token of the parsable element $name.
303
     */
304
    public function get_token($name) {
305
        foreach (array_merge($this->blockrules, $this->tagrules) as $n => $v) {
306
            if ($name == $n && isset($v['token'])) {
307
                return $v['token'] ? $v['token'] : false;
308
            }
309
        }
310
 
311
        return false;
312
    }
313
}