EMTTret::ss()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 1
1
<?php
2
3
/**
4
* Evgeny Muravjev Typograph, http://mdash.ru
5
* Version: 3.4 Gold Master
6
* Release Date: September 20, 2014
7
* Authors: Evgeny Muravjev & Alexander Drutsa  
8
*/
9
10
namespace Fenrizbes\TypographBundle\EMT;
11
12
/**
13
 * Базовый класс для группы правил обработки текста
14
 * Класс группы должен наследовать, данный класс и задавать
15
 * в нём EMTTret::rules и EMTTret::$name
16
 * 
17
 */
18
class EMTTret {
19
	
20
	/**
21
	 * Набор правил в данной группе, который задан изначально
22
	 * Его можно менять динамически добавляя туда правила с помощью put_rule
23
	 *
24
	 * @var unknown_type
25
	 */
26
	public    $rules;
27
	public    $title;
28
	
29
	
30
	private   $disabled = array();
31
	private   $enabled  = array();
32
	protected $_text= '';
33
	public $logging = false;
34
	public $logs    = false;
35
	public $errors  = false;	
36
	public $debug_enabled  = false;
37
	public $debug_info     = array();
38
	
39
	
40
	private $use_layout = false;
41
	private $use_layout_set = false;
42
	private $class_layout_prefix = false;
43
	
44
	public $class_names     = array();
45
	public $classes         = array();
46
	public $settings        = array();
47
	
48
	/**
49
	 * Защищенные теги
50
	 * 
51
	 * @todo привязать к методам из Jare_Typograph_Tool
52
	 */
53
	const BASE64_PARAGRAPH_TAG = 'cA==='; // p
54
	const BASE64_BREAKLINE_TAG = 'YnIgLw==='; // br / (с пробелом и слэшем)
55
	const BASE64_NOBR_OTAG = 'bm9icg==='; // nobr
56
	const BASE64_NOBR_CTAG = 'L25vYnI=='; // /nobr
57
	
58
	/**
59
	 * Типы кавычек
60
	 */
61
	const QUOTE_FIRS_OPEN = '&laquo;';
62
    const QUOTE_FIRS_CLOSE = '&raquo;';
63
    const QUOTE_CRAWSE_OPEN = '&bdquo;';
64
    const QUOTE_CRAWSE_CLOSE = '&ldquo;';
65
	
66
	
67
	private function log($str, $data = null)
68
	{
69
		if(!$this->logging) return;
70
		$this->logs[] = array('info' => $str, 'data' => $data);
71
	}
72
73
	private function error($info, $data = null)
74
	{
75
		$this->errors[] = array('info' => $info, 'data' => $data);
76
		$this->log('ERROR: '. $info , $data);
77
	}
78
	
79
	public function debug($place, &$after_text)
80
	{
81
		if(!$this->debug_enabled) return;
82
		$this->debug_info[] = array(
83
				'place' => $place,
84
				'text'  => $after_text,
85
			);
86
	}
87
	
88
	
89
	/**
90
	 * Установить режим разметки для данного Трэта если не было раньше установлено,
91
	 *   EMTLib::LAYOUT_STYLE - с помощью стилей
92
	 *   EMTLib::LAYOUT_CLASS - с помощью классов
93
	 *
94
	 * @param int $kind
0 ignored issues
show
Bug introduced by
There is no parameter named $kind. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
95
	 */
96
	public function set_tag_layout_ifnotset($layout)
97
	{
98
		if($this->use_layout_set) return;
99
		$this->use_layout = $layout;
100
	}
101
	
102
	/**
103
	 * Установить режим разметки для данного Трэта,
104
	 *   EMTLib::LAYOUT_STYLE - с помощью стилей
105
	 *   EMTLib::LAYOUT_CLASS - с помощью классов
106
	 *   EMTLib::LAYOUT_STYLE|EMTLib::LAYOUT_CLASS - оба метода
107
	 *
108
	 * @param int $kind
0 ignored issues
show
Bug introduced by
There is no parameter named $kind. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
109
	 */
110
	public function set_tag_layout($layout = EMTLib::LAYOUT_STYLE)
111
	{
112
		$this->use_layout = $layout;
113
		$this->use_layout_set = true;
114
	}
115
	
116
	public function set_class_layout_prefix($prefix)
117
	{
118
		$this->class_layout_prefix = $prefix;
119
	}
120
	
121
	
122
	public function debug_on()
123
	{
124
		$this->debug_enabled = true;
125
	}
126
	
127
	public function log_on()
128
	{
129
		$this->debug_enabled = true;
130
	}
131
	
132
	
133
	private function getmethod($name)
134
	{
135
		if(!$name) return false;
136
		if(!method_exists($this, $name)) return false;
137
		return array($this, $name);
138
	}
139
	
140 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...
141
	{
142
		$this->pre_parse();
143
		foreach($this->rules as $rule)
144
		{
145
			if(!isset($rule['init'])) continue;
146
			$m = $this->getmethod($rule['init']);
147
			if(!$m) continue;
148
			call_user_func($m);
149
		}
150
	}
151 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...
152
	{
153
		foreach($this->rules as $rule)
154
		{
155
			if(!isset($rule['deinit'])) continue;
156
			$m = $this->getmethod($rule['deinit']);
157
			if(!$m) continue;
158
			call_user_func($m);
159
		}
160
		$this->post_parse();
161
	}
162
	
163
	private function rule_order_sort($a, $b)
164
	{
165
		if($a['order'] == $b['order']) return 0;
166
		if($a['order'] < $b['order']) return -1;
167
		return 1;
168
	}
169
	
170
	private function apply_rule($rule)
171
	{
172
		$name = $rule['id'];
173
		//$this->log("Правило $name", "Применяем правило");
0 ignored issues
show
Unused Code Comprehensibility introduced by
80% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
174
		$disabled = (isset($this->disabled[$rule['id']]) && $this->disabled[$rule['id']]) || ((isset($rule['disabled']) && $rule['disabled']) && !(isset($this->enabled[$rule['id']]) && $this->enabled[$rule['id']]));
175
		if($disabled)
176
		{
177
			$this->log("Правило $name", "Правило отключено" . ((isset($rule['disabled']) && $rule['disabled'])? " (по умолчанию)" : ""));
178
			return;
179
		}
180
		if(isset($rule['function']) && $rule['function'])
181
		{
182
			if(!(isset($rule['pattern']) &&  $rule['pattern']))
183
			{
184 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...
185
				{
186
					$this->log("Правило $name", "Используется метод ".$rule['function']." в правиле");
187
					
188
					call_user_func(array($this, $rule['function']));
189
					return;
190
				} 
191 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...
192
				{
193
					$this->log("Правило $name", "Используется функция ".$rule['function']." в правиле");
194
					
195
					call_user_func($rule['function']);
196
					return;
197
				}
198
				
199
				$this->error('Функция '.$rule['function'].' из правила '.$rule['id']. " не найдена");
200
				return ;
201
			} else {
202
				if(preg_match("/^[a-z_0-9]+$/i", $rule['function']))
203
				{
204 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...
205
					{
206
						$this->log("Правило $name", "Замена с использованием preg_replace_callback с методом ".$rule['function']."");
207
						
208
						$this->_text = preg_replace_callback($rule['pattern'], array($this, $rule['function']), $this->_text);
209
						return;
210
					} 
211 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...
212
					{
213
						$this->log("Правило $name", "Замена с использованием preg_replace_callback с функцией ".$rule['function']."");
214
						
215
						$this->_text = preg_replace_callback($rule['pattern'], $rule['function'], $this->_text);
216
						return;
217
					}
218
					$this->error('Функция '.$rule['function'].' из правила '.$rule['id']. " не найдена");
219
				} else {
220
					$this->_text = preg_replace_callback($rule['pattern'],  create_function('$m', $rule['function']), $this->_text);
0 ignored issues
show
Security Best Practice introduced by
The use of create_function is highly discouraged, better use a closure.

create_function can pose a great security vulnerability as it is similar to eval, and could be used for arbitrary code execution. We highly recommend to use a closure instead.

// Instead of
$function = create_function('$a, $b', 'return $a + $b');

// Better use
$function = function($a, $b) { return $a + $b; }
Loading history...
221
					$this->log('Замена с использованием preg_replace_callback с инлайн функцией из правила '.$rule['id']);
222
					return;
223
				}
224
				return ;
225
			}
226
		}
227
		
228
		if(isset($rule['simple_replace']) && $rule['simple_replace'])
229
		{
230
			if(isset($rule['case_sensitive']) && $rule['case_sensitive'])
231
			{
232
				$this->log("Правило $name", "Простая замена с использованием str_replace");
233
				$this->_text = str_replace($rule['pattern'], $rule['replacement'], $this->_text);
234
				return;
235
			}
236
			$this->log("Правило $name", "Простая замена с использованием str_ireplace");		
237
			$this->_text = str_ireplace($rule['pattern'], $rule['replacement'], $this->_text);
238
			return;
239
		}
240
		
241
		$pattern = $rule['pattern'];
242
		if(is_string($pattern)) $pattern = array($pattern);
243
		$eval = false;
244
		foreach($pattern as $patt)
245
		{
246
			$chr = substr($patt,0,1);
247
			$preg_arr = explode($chr, $patt);		
248
			if(strpos($preg_arr[count($preg_arr)-1], "e")!==false)
249
			{
250
				$eval = true;
251
				break;
252
			}
253
		}
254
		if(!$eval)
255
		{
256
			$this->log("Правило $name", "Замена с использованием preg_replace");		
257
			
258
			do {
259
				$this->_text = preg_replace($rule['pattern'], $rule['replacement'], $this->_text);
260
				if(!(isset($rule['cycled']) && $rule['cycled'])) break;
261
			} while(preg_match($rule['pattern'], $this->_text));
262
			
263
			return;
264
		}
265
		
266
		$this->log("Правило $name", "Замена с использованием preg_replace_callback вместо eval");		
267
		$k = 0;
268
		foreach($pattern as $patt)
269
		{
270
			$repl = is_string($rule['replacement']) ? $rule['replacement'] : $rule['replacement'][$k];
271
			
272
			$chr = substr($patt,0,1);
273
			$preg_arr = explode($chr, $patt);		
274
			if(strpos($preg_arr[count($preg_arr)-1], "e")!==false) // eval система
275
			{
276
				$preg_arr[count($preg_arr)-1] = str_replace("e","",$preg_arr[count($preg_arr)-1]);
277
				$patt = implode($chr, $preg_arr);
278
				$this->thereplacement = $repl;
279 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...
280
					$this->_text = preg_replace_callback($patt, array($this, "thereplcallback"), $this->_text);
281
					if(!(isset($rule['cycled']) && $rule['cycled'])) break;
282
				} while(preg_match($patt, $this->_text));
283
				
284
			} else {
285 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...
286
					$this->_text = preg_replace($patt, $repl, $this->_text);
287
					if(!(isset($rule['cycled']) && $rule['cycled'])) break;
288
				} while(preg_match($patt, $this->_text));
289
			}
290
			$k++;
291
		}
292
	}
293
	
294
	
295
	protected function preg_replace_e($pattern, $replacement, $text)
296
	{
297
		$chr = substr($pattern,0,1);
298
		$preg_arr = explode($chr, $pattern);				
299
		if(strpos($preg_arr[count($preg_arr)-1], "e")===false) return preg_replace($pattern, $replacement, $text);
300
		$preg_arr[count($preg_arr)-1] = str_replace("e","",$preg_arr[count($preg_arr)-1]);
301
		$patt = implode($chr, $preg_arr);
302
		$this->thereplacement = $replacement;
303
		return preg_replace_callback($patt, array($this, "thereplcallback"), $text);
304
	}
305
	
306
	private $thereplacement = "";
307
	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...
308
	{
309
		$x = "";
310
		eval('$x = '.($this->thereplacement?$this->thereplacement:'""').';');
0 ignored issues
show
Coding Style introduced by
It is generally not recommended to use eval unless absolutely required.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
311
		return $x;
312
	}
313
	
314
	private function _apply($list)
315
	{
316
		$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...
317
		$this->_pre_parse();
318
		
319
		$this->log("Применяется набор правил", implode(",",$list));
320
		
321
		$rulelist = array();
322
		foreach($list as $k)
323
		{			
324
			$rule = $this->rules[$k];
325
			$rule['id']    = $k;
326
			$rule['order'] = isset($rule['order'])? $rule['order'] : 5 ;
327
			$rulelist[] = $rule;
328
		}
329
		//usort($rulelist, array($this, "rule_order_sort"));
0 ignored issues
show
Unused Code Comprehensibility introduced by
79% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
330
		
331
		foreach($rulelist as $rule)
332
		{
333
			$this->apply_rule($rule);			
334
			$this->debug($rule['id'], $this->_text);
335
		}
336
		
337
		$this->_post_parse();
338
	}
339
	
340
	
341
	/**
342
	 * Создание защищенного тега с содержимым
343
	 *
344
	 * @see 	EMTLib::build_safe_tag
345
	 * @param 	string $content
346
	 * @param 	string $tag
347
	 * @param 	array $attribute
348
	 * @return 	string
349
	 */
350
	protected function tag($content, $tag = 'span', $attribute = array())
351
	{
352
		if(isset($attribute['class']))
353
		{
354
			$classname = $attribute['class'];
355
			if($classname == "nowrap")
356
			{
357
				if(!$this->is_on('nowrap'))
358
				{
359
					$tag = "nobr";
360
					$attribute = array();
361
					$classname = "";
362
				}
363
			}
364
			if(isset($this->classes[$classname]))
365
			{
366
				$style_inline = $this->classes[$classname];
367
				if($style_inline) $attribute['__style'] = $style_inline;
368
			}
369
			$classname = (isset($this->class_names[$classname]) ? $this->class_names[$classname] :$classname);
370
			$classname = ($this->class_layout_prefix ? $this->class_layout_prefix : "" ).$classname;
371
			$attribute['class'] = $classname;
372
		}
373
		
374
		return EMTLib::build_safe_tag($content, $tag, $attribute,
375
				$this->use_layout === false? EMTLib::LAYOUT_STYLE  : $this->use_layout );
376
	}
377
	
378
	
379
	/**
380
	 * Добавить правило в группу
381
	 *
382
	 * @param string $name
383
	 * @param array $params
384
	 */
385
	public function put_rule($name, $params)
386
	{
387
		$this->rules[$name] = $params; 
388
		return $this;
389
	}
390
391
	/**
392
	 * Отключить правило, в обработке
393
	 *
394
	 * @param string $name
395
	 */
396
	public function disable_rule($name)
397
	{
398
		$this->disabled[$name] = true;
399
		unset($this->enabled[$name]);
400
	}
401
	
402
	/**
403
	 * Включить правило
404
	 *
405
	 * @param string $name
406
	 */
407
	public function enable_rule($name)
408
	{
409
		$this->enabled[$name] = true;
410
		unset($this->disabled[$name]);
411
	}
412
	
413
	/**
414
	 * Добавить настройку в трет
415
	 *
416
	 * @param string $key ключ
417
	 * @param mixed $value значение
418
	 */
419
	public function set($key, $value)
420
	{
421
		$this->settings[$key] = $value;
422
	}
423
	
424
	/**
425
	 * Установлена ли настройка
426
	 *
427
	 * @param string $key
428
	 */
429
	public function is_on($key)
430
	{
431
		if(!isset($this->settings[$key])) return false;
432
		$kk = $this->settings[$key];
433
		return ((strtolower($kk)=="on") || ($kk === "1") || ($kk === true) || ($kk === 1));
434
	}
435
	
436
	/**
437
	 * Получить строковое значение настройки
438
	 *
439
	 * @param unknown_type $key
440
	 * @return unknown
441
	 */
442
	public function ss($key)
443
	{
444
		if(!isset($this->settings[$key])) return "";
445
		return strval($this->settings[$key]);
446
	}
447
	
448
	/**
449
	 * Добавить настройку в правило
450
	 *
451
	 * @param string $rulename идентификатор правила 
452
	 * @param string $key ключ
453
	 * @param mixed $value значение
454
	 */
455
	public function set_rule($rulename, $key, $value)
456
	{
457
		$this->rules[$rulename][$key] = $value;
458
	}
459
	
460
	/**
461
	 * Включить правила, согласно списку
462
	 *
463
	 * @param array $list список правил
464
	 * @param boolean $disable выкллючить их или включить
465
	 * @param boolean $strict строго, т.е. те которые не в списку будут тоже обработаны
466
	 */
467
	public function activate($list,$disable =false, $strict = true)
468
	{
469
		if(!is_array($list)) return ;
470
		
471
		foreach($list as $rulename)
472
		{
473
			if($disable) $this->disable_rule($rulename); else $this->enable_rule($rulename);
474
		}
475
		
476
		if($strict)
477
		{
478
			foreach($this->rules as $rulename => $v)
479
			{
480
				if(in_array($rulename, $list)) continue;
481
				if(!$disable) $this->disable_rule($rulename); else $this->enable_rule($rulename);
482
			}
483
		}
484
	}
485
	
486
	public function set_text(&$text)
487
	{
488
		$this->_text = &$text;
489
		$this->debug_info = array();
490
		$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...
491
	}
492
	
493
494
	/**
495
	 * Применить к тексту
496
	 *
497
	 * @param string $text - текст к которому применить
0 ignored issues
show
Bug introduced by
There is no parameter named $text. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
498
	 * @param mixed $list - список правил, null - все правила
499
	 * @return string
500
	 */
501
	public function apply($list = null)
502
	{
503
		if(is_string($list)) $rlist = array($list);
504
		elseif(is_array($list)) $rlist = $list;
505
		else $rlist = array_keys($this->rules);
506
		$this->_apply($rlist);
507
		return $this->_text;
508
	}
509
	
510
	
511
	
512
	
513
	/**
514
	 * Код, выполняем до того, как применить правила
515
	 *
516
	 */
517
	public function pre_parse()
518
	{
519
	}
520
	
521
	/**
522
	 * После выполнения всех правил, выполняется этот метод
523
	 *
524
	 */
525
	public function post_parse()
526
	{
527
	}
528
	
529
	
530
}