AbstractTret::set()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
namespace EMT\Tret;
4
5
use EMT\Util;
6
7
/**
8
 * Базовый класс для группы правил обработки текста
9
 * Класс группы должен наследовать, данный класс и задавать
10
 * в нём EMT_Tret::rules и EMT_Tret::$name
11
 *
12
 */
13
abstract class AbstractTret
14
{
15
    /**
16
     * Набор правил в данной группе, который задан изначально
17
     * Его можно менять динамически добавляя туда правила с помощью put_rule
18
     *
19
     * @var array
20
     */
21
    public $rules;
22
    public $title;
23
    public $logging = false;
24
    public $logs = false;
25
    public $errors = false;
26
    public $debug_enabled = false;
27
    public $debug_info = array();
28
    public $class_names = array();
29
    public $classes = array();
30
    public $settings = array();
31
32
    private $disabled = array();
33
    private $enabled = array();
34
    private $use_layout = false;
35
    private $use_layout_set = false;
36
    private $class_layout_prefix = false;
37
38
    protected $_text = '';
39
40
    /**
41
     * Защищенные теги
42
     *
43
     * @todo привязать к методам из Jare_Typograph_Tool
44
     */
45
    const BASE64_PARAGRAPH_TAG = 'cA==='; // p
46
    const BASE64_BREAKLINE_TAG = 'YnIgLw==='; // br / (с пробелом и слэшем)
47
    const BASE64_NOBR_OTAG = 'bm9icg==='; // nobr
48
    const BASE64_NOBR_CTAG = 'L25vYnI=='; // /nobr
49
50
    /**
51
     * Типы кавычек
52
     */
53
    const QUOTE_FIRS_OPEN = '&laquo;';
54
    const QUOTE_FIRS_CLOSE = '&raquo;';
55
    const QUOTE_CRAWSE_OPEN = '&bdquo;';
56
    const QUOTE_CRAWSE_CLOSE = '&ldquo;';
57
58
    private function log($str, $data = null)
59
    {
60
        if (!$this->logging) return;
61
        $this->logs[] = array('info' => $str, 'data' => $data);
62
    }
63
64
    /**
65
     * @param string $info
66
     */
67
    private function error($info, $data = null)
68
    {
69
        $this->errors[] = array('info' => $info, 'data' => $data);
70
        $this->log('ERROR: ' . $info, $data);
71
    }
72
73
    public function debug($place, &$after_text)
74
    {
75
        if (!$this->debug_enabled) return;
76
        $this->debug_info[] = array(
77
            'place' => $place,
78
            'text' => $after_text,
79
        );
80
    }
81
82
    /**
83
     * Установить режим разметки для данного Трэта если не было раньше установлено,
84
     *   Util::LAYOUT_STYLE - с помощью стилей
85
     *   Util::LAYOUT_CLASS - с помощью классов
86
     *
87
     */
88
    public function set_tag_layout_ifnotset($layout)
89
    {
90
        if ($this->use_layout_set) return;
91
        $this->use_layout = $layout;
92
    }
93
94
    /**
95
     * Установить режим разметки для данного Трэта,
96
     *   Util::LAYOUT_STYLE - с помощью стилей
97
     *   Util::LAYOUT_CLASS - с помощью классов
98
     *   Util::LAYOUT_STYLE|Util::LAYOUT_CLASS - оба метода
99
     *
100
     */
101
    public function set_tag_layout($layout = Util::LAYOUT_STYLE)
102
    {
103
        $this->use_layout = $layout;
104
        $this->use_layout_set = true;
105
    }
106
107
    public function set_class_layout_prefix($prefix)
108
    {
109
        $this->class_layout_prefix = $prefix;
110
    }
111
112
    public function debug_on()
113
    {
114
        $this->debug_enabled = true;
115
    }
116
117
    public function log_on()
118
    {
119
        $this->debug_enabled = true;
120
    }
121
122
    private function getmethod($name)
123
    {
124
        if (!$name) return false;
125
        if (!method_exists($this, $name)) return false;
126
127
        return array($this, $name);
128
    }
129
130 View Code Duplication
    private function _pre_parse()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
131
    {
132
        $this->pre_parse();
133
        foreach ($this->rules as $rule) {
134
            if (!isset($rule['init'])) continue;
135
            $m = $this->getmethod($rule['init']);
136
            if (!$m) continue;
137
            call_user_func($m);
138
        }
139
    }
140
141 View Code Duplication
    private function _post_parse()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
142
    {
143
        foreach ($this->rules as $rule) {
144
            if (!isset($rule['deinit'])) continue;
145
            $m = $this->getmethod($rule['deinit']);
146
            if (!$m) continue;
147
            call_user_func($m);
148
        }
149
        $this->post_parse();
150
    }
151
152
    private function rule_order_sort($a, $b)
153
    {
154
        if ($a['order'] == $b['order']) return 0;
155
        if ($a['order'] < $b['order']) return -1;
156
157
        return 1;
158
    }
159
160
    private function apply_rule($rule)
161
    {
162
        $name = $rule['id'];
163
        //$this->log("Правило $name", "Применяем правило");
164
        $disabled = (isset($this->disabled[$rule['id']]) && $this->disabled[$rule['id']]) || ((isset($rule['disabled']) && $rule['disabled']) && !(isset($this->enabled[$rule['id']]) && $this->enabled[$rule['id']]));
165
        if ($disabled) {
166
            $this->log("Правило $name", "Правило отключено" . ((isset($rule['disabled']) && $rule['disabled']) ? " (по умолчанию)" : ""));
167
168
            return;
169
        }
170
        if (isset($rule['function']) && $rule['function']) {
171
            if (!(isset($rule['pattern']) && $rule['pattern'])) {
172 View Code Duplication
                if (method_exists($this, $rule['function'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
173
                    $this->log("Правило $name", "Используется метод " . $rule['function'] . " в правиле");
174
175
                    call_user_func(array($this, $rule['function']));
176
177
                    return;
178
                }
179 View Code Duplication
                if (function_exists($rule['function'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
                    $this->log("Правило $name", "Используется функция " . $rule['function'] . " в правиле");
181
182
                    call_user_func($rule['function']);
183
184
                    return;
185
                }
186
187
                $this->error('Функция ' . $rule['function'] . ' из правила ' . $rule['id'] . " не найдена");
188
189
                return;
190
            } else {
191
                if (preg_match("/^[a-z_0-9]+$/i", $rule['function'])) {
192 View Code Duplication
                    if (method_exists($this, $rule['function'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
193
                        $this->log("Правило $name", "Замена с использованием preg_replace_callback с методом " . $rule['function'] . "");
194
195
                        $this->_text = preg_replace_callback($rule['pattern'], array($this, $rule['function']), $this->_text);
196
197
                        return;
198
                    }
199 View Code Duplication
                    if (function_exists($rule['function'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
200
                        $this->log("Правило $name", "Замена с использованием preg_replace_callback с функцией " . $rule['function'] . "");
201
202
                        $this->_text = preg_replace_callback($rule['pattern'], $rule['function'], $this->_text);
203
204
                        return;
205
                    }
206
                    $this->error('Функция ' . $rule['function'] . ' из правила ' . $rule['id'] . " не найдена");
207
                } else {
208
                    $this->_text = preg_replace_callback($rule['pattern'], create_function('$m', $rule['function']), $this->_text);
209
                    $this->log('Замена с использованием preg_replace_callback с инлайн функцией из правила ' . $rule['id']);
210
211
                    return;
212
                }
213
214
                return;
215
            }
216
        }
217
218
        if (isset($rule['simple_replace']) && $rule['simple_replace']) {
219
            if (isset($rule['case_sensitive']) && $rule['case_sensitive']) {
220
                $this->log("Правило $name", "Простая замена с использованием str_replace");
221
                $this->_text = str_replace($rule['pattern'], $rule['replacement'], $this->_text);
222
223
                return;
224
            }
225
            $this->log("Правило $name", "Простая замена с использованием str_ireplace");
226
            $this->_text = str_ireplace($rule['pattern'], $rule['replacement'], $this->_text);
227
228
            return;
229
        }
230
231
        $pattern = $rule['pattern'];
232
        if (is_string($pattern)) $pattern = array($pattern);
233
        $eval = false;
234
        foreach ($pattern as $patt) {
235
            $chr = substr($patt, 0, 1);
236
            $preg_arr = explode($chr, $patt);
237
            if (strpos($preg_arr[count($preg_arr) - 1], "e") !== false) {
238
                $eval = true;
239
                break;
240
            }
241
        }
242
        if (!$eval) {
243
            $this->log("Правило $name", "Замена с использованием preg_replace");
244
245
            do {
246
                $this->_text = preg_replace($rule['pattern'], $rule['replacement'], $this->_text);
247
                if (!(isset($rule['cycled']) && $rule['cycled'])) break;
248
            } while (preg_match($rule['pattern'], $this->_text));
249
250
            return;
251
        }
252
253
        $this->log("Правило $name", "Замена с использованием preg_replace_callback вместо eval");
254
        $k = 0;
255
        foreach ($pattern as $patt) {
256
            $repl = is_string($rule['replacement']) ? $rule['replacement'] : $rule['replacement'][$k];
257
258
            $chr = substr($patt, 0, 1);
259
            $preg_arr = explode($chr, $patt);
260
            if (strpos($preg_arr[count($preg_arr) - 1], "e") !== false) { // eval система
261
                $preg_arr[count($preg_arr) - 1] = str_replace("e", "", $preg_arr[count($preg_arr) - 1]);
262
                $patt = implode($chr, $preg_arr);
263
                $this->thereplacement = $repl;
264 View Code Duplication
                do {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
265
                    $this->_text = preg_replace_callback($patt, array($this, "thereplcallback"), $this->_text);
266
                    if (!(isset($rule['cycled']) && $rule['cycled'])) break;
267
                } while (preg_match($patt, $this->_text));
268
269
            } else {
270 View Code Duplication
                do {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
271
                    $this->_text = preg_replace($patt, $repl, $this->_text);
272
                    if (!(isset($rule['cycled']) && $rule['cycled'])) break;
273
                } while (preg_match($patt, $this->_text));
274
            }
275
            $k++;
276
        }
277
    }
278
279
    /**
280
     * @param string $pattern
281
     * @param string $replacement
282
     */
283
    protected function preg_replace_e($pattern, $replacement, $text)
284
    {
285
        $chr = substr($pattern, 0, 1);
286
        $preg_arr = explode($chr, $pattern);
287
        if (strpos($preg_arr[count($preg_arr) - 1], "e") === false) return preg_replace($pattern, $replacement, $text);
288
        $preg_arr[count($preg_arr) - 1] = str_replace("e", "", $preg_arr[count($preg_arr) - 1]);
289
        $patt = implode($chr, $preg_arr);
290
        $this->thereplacement = $replacement;
291
292
        return preg_replace_callback($patt, array($this, "thereplcallback"), $text);
293
    }
294
295
    private $thereplacement = "";
296
297
    private function thereplcallback($m)
0 ignored issues
show
Unused Code introduced by
The parameter $m 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...
298
    {
299
        $x = "";
300
        eval('$x = ' . ($this->thereplacement ? $this->thereplacement : '""') . ';');
301
302
        return $x;
303
    }
304
305
    private function _apply($list)
306
    {
307
        $this->errors = array();
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type boolean of property $errors.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
308
        $this->_pre_parse();
309
310
        $this->log("Применяется набор правил", implode(",", $list));
311
312
        $rulelist = array();
313
        foreach ($list as $k) {
314
            $rule = $this->rules[$k];
315
            $rule['id'] = $k;
316
            $rule['order'] = isset($rule['order']) ? $rule['order'] : 5;
317
            $rulelist[] = $rule;
318
        }
319
        //usort($rulelist, array($this, "rule_order_sort"));
320
321
        foreach ($rulelist as $rule) {
322
            $this->apply_rule($rule);
323
            $this->debug($rule['id'], $this->_text);
324
        }
325
326
        $this->_post_parse();
327
    }
328
329
    /**
330
     * Создание защищенного тега с содержимым
331
     *
332
     * @see    EMT_lib::build_safe_tag
333
     * @param  string $content
334
     * @param  string $tag
335
     * @param  array $attribute
336
     * @return string
337
     */
338
    protected function tag($content, $tag = 'span', $attribute = array())
339
    {
340
        if (isset($attribute['class'])) {
341
            $classname = $attribute['class'];
342
            if ($classname == "nowrap") {
343
                if (!$this->is_on('nowrap')) {
344
                    $tag = "nobr";
345
                    $attribute = array();
346
                    $classname = "";
347
                }
348
            }
349
            if (isset($this->classes[$classname])) {
350
                $style_inline = $this->classes[$classname];
351
                if ($style_inline) $attribute['__style'] = $style_inline;
352
            }
353
            $classname = (isset($this->class_names[$classname]) ? $this->class_names[$classname] : $classname);
354
            $classname = ($this->class_layout_prefix ? $this->class_layout_prefix : "") . $classname;
355
            $attribute['class'] = $classname;
356
        }
357
358
        return Util::build_safe_tag($content, $tag, $attribute,
359
            $this->use_layout === false ? Util::LAYOUT_STYLE : $this->use_layout);
360
    }
361
362
    /**
363
     * Добавить правило в группу
364
     *
365
     * @param string $name
366
     * @param array $params
367
     */
368
    public function put_rule($name, $params)
369
    {
370
        $this->rules[$name] = $params;
371
372
        return $this;
373
    }
374
375
    /**
376
     * Отключить правило, в обработке
377
     *
378
     * @param string $name
379
     */
380
    public function disable_rule($name)
381
    {
382
        $this->disabled[$name] = true;
383
        unset($this->enabled[$name]);
384
    }
385
386
    /**
387
     * Включить правило
388
     *
389
     * @param string $name
390
     */
391
    public function enable_rule($name)
392
    {
393
        $this->enabled[$name] = true;
394
        unset($this->disabled[$name]);
395
    }
396
397
    /**
398
     * Добавить настройку в трет
399
     *
400
     * @param string $key ключ
401
     * @param mixed $value значение
402
     */
403
    public function set($key, $value)
404
    {
405
        $this->settings[$key] = $value;
406
    }
407
408
    /**
409
     * Установлена ли настройка
410
     *
411
     * @param string $key
412
     */
413 View Code Duplication
    public function is_on($key)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
414
    {
415
        if (!isset($this->settings[$key])) return false;
416
        $kk = $this->settings[$key];
417
418
        return ((strtolower($kk) == "on") || ($kk === "1") || ($kk === true) || ($kk === 1));
419
    }
420
421
    /**
422
     * Получить строковое значение настройки
423
     *
424
     * @param  unknown_type $key
425
     * @return string
426
     */
427
    public function ss($key)
428
    {
429
        if (!isset($this->settings[$key])) return "";
430
431
        return strval($this->settings[$key]);
432
    }
433
434
    /**
435
     * Добавить настройку в правило
436
     *
437
     * @param string $rulename идентификатор правила
438
     * @param string $key ключ
439
     * @param mixed $value значение
440
     */
441
    public function set_rule($rulename, $key, $value)
442
    {
443
        $this->rules[$rulename][$key] = $value;
444
    }
445
446
    /**
447
     * Включить правила, согласно списку
448
     *
449
     * @param array $list список правил
450
     * @param boolean $disable выкллючить их или включить
451
     * @param boolean $strict строго, т.е. те которые не в списку будут тоже обработаны
452
     */
453
    public function activate($list, $disable = false, $strict = true)
454
    {
455
        if (!is_array($list)) return;
456
457
        foreach ($list as $rulename) {
458
            if ($disable) $this->disable_rule($rulename); else $this->enable_rule($rulename);
459
        }
460
461
        if ($strict) {
462
            foreach ($this->rules as $rulename => $v) {
463
                if (in_array($rulename, $list)) continue;
464
                if (!$disable) $this->disable_rule($rulename); else $this->enable_rule($rulename);
465
            }
466
        }
467
    }
468
469
    public function set_text(&$text)
470
    {
471
        $this->_text = & $text;
472
        $this->debug_info = array();
473
        $this->logs = array();
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type boolean of property $logs.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
474
    }
475
476
    /**
477
     * Применить к тексту
478
     *
479
     * @param  mixed $list - список правил, null - все правила
480
     * @return string
481
     */
482
    public function apply($list = null)
483
    {
484
        if (is_string($list)) $rlist = array($list);
485
        elseif (is_array($list)) $rlist = $list;
486
        else $rlist = array_keys($this->rules);
487
        $this->_apply($rlist);
488
489
        return $this->_text;
490
    }
491
492
    /**
493
     * Код, выполняем до того, как применить правила
494
     *
495
     */
496
    public function pre_parse()
497
    {
498
    }
499
500
    /**
501
     * После выполнения всех правил, выполняется этот метод
502
     *
503
     */
504
    public function post_parse()
505
    {
506
    }
507
508
}
509