Completed
Push — master ( 25d3bb...a9232e )
by smiley
04:11
created

BaseModuleAbstract::eol()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 3
1
<?php
2
/**
3
 * Class BaseModuleAbstract
4
 *
5
 * @filesource   BaseModuleAbstract.php
6
 * @created      12.10.2015
7
 * @package      chillerlan\bbcode\Modules
8
 * @author       Smiley <[email protected]>
9
 * @copyright    2015 Smiley
10
 * @license      MIT
11
 */
12
13
namespace chillerlan\bbcode\Modules;
14
15
use chillerlan\bbcode\{BBCodeException, BBTemp};
16
17
/**
18
 * The base module implements the basic functionality for each module
19
 */
20
abstract class BaseModuleAbstract implements BaseModuleInterface{
21
22
	/**
23
	 * The current bbcode tag
24
	 *
25
	 * @var string
26
	 * @see \chillerlan\bbcode\BBTemp::$tag
27
	 */
28
	protected $tag;
29
30
	/**
31
	 * An array of the bbcode's attributes
32
	 *
33
	 * @var array
34
	 * @see \chillerlan\bbcode\BBTemp::$attributes
35
	 */
36
	protected $attributes;
37
38
	/**
39
	 * The content between the current bbcode tags
40
	 *
41
	 * @var string
42
	 * @see \chillerlan\bbcode\BBTemp::$content
43
	 */
44
	protected $content;
45
46
	/**
47
	 * The current callback depth
48
	 *
49
	 * @var int
50
	 * @see \chillerlan\bbcode\BBTemp::$depth
51
	 */
52
	protected $depth;
53
54
	/**
55
	 * Holds the current base module's EOL token which will replace any newlines
56
	 *
57
	 * @var string
58
	 * @see \chillerlan\bbcode\Modules\ModuleInfo::$eol_token
59
	 */
60
	protected $eol_token = PHP_EOL;
61
62
	/**
63
	 * Holds an array of FQN strings to the current base module's children
64
	 *
65
	 * @var array
66
	 * @see \chillerlan\bbcode\Modules\ModuleInfo::$modules
67
	 */
68
	protected $modules = [];
69
70
	/**
71
	 * An array of tags the module is able to process
72
	 *
73
	 * @var array
74
	 * @see \chillerlan\bbcode\Modules\Tagmap::$tags
75
	 */
76
	protected $tags = [];
77
78
	/**
79
	 * An optional array of tags contained in self::$tags which are marked as "noparse"
80
	 *
81
	 * @var array
82
	 * @see \chillerlan\bbcode\Modules\Tagmap::$noparse_tags
83
	 */
84
	protected $noparse_tags = [];
85
86
	/**
87
	 * An optional array of tags contained in self::$tags which are marked as "single tag"
88
	 *
89
	 * @var array
90
	 * @see \chillerlan\bbcode\Modules\Tagmap::$singletags
91
	 */
92
	protected $singletags = [];
93
94
	/**
95
	 * The parser options
96
	 *
97
	 * @var \chillerlan\bbcode\ParserOptions
98
	 * @see \chillerlan\bbcode\parserOptions::$options
99
	 */
100
	protected $parserOptions;
101
102
	/**
103
	 * Holds the translation class for the current language
104
	 *
105
	 * @var \chillerlan\bbcode\Language\LanguageInterface
106
	 */
107
	protected $languageInterface;
108
109
	/**
110
	 * Constructor
111
	 *
112
	 * calls self::setBBTemp() in case $bbtemp is set
113
	 *
114
	 * @param \chillerlan\bbcode\BBTemp $bbtemp
0 ignored issues
show
Documentation introduced by
Should the type for parameter $bbtemp not be null|\chillerlan\bbcode\BBTemp?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
115
	 */
116
	public function __construct(BBTemp $bbtemp = null){
117
		if($bbtemp instanceof BBTemp){
118
			$this->setBBTemp($bbtemp);
119
		}
120
	}
121
122
	/**
123
	 * Sets self::$tag, self::$attributes, self::$content and self::$options
124
	 *
125
	 * @param \chillerlan\bbcode\BBTemp $bbtemp
126
	 *
127
	 * @return $this
128
	 */
129
	public function setBBTemp(BBTemp $bbtemp){
130
		foreach(['tag', 'attributes', 'content', 'parserOptions', 'languageInterface', 'depth'] as $var){
131
			$this->{$var} = $bbtemp->{$var};
132
		}
133
134
		return $this;
135
	}
136
137
	/**
138
	 * Returns a list of the BaseModuleAbstract's modules
139
	 *
140
	 * @return \chillerlan\bbcode\Modules\BaseModuleInfo
141
	 */
142
	public function getInfo():BaseModuleInfo{
143
		$info = new BaseModuleInfo;
144
145
		foreach(['modules', 'eol_token'] as $option){
146
			$info->{$option} = $this->{$option};
147
		}
148
149
		return $info;
150
	}
151
152
	/**
153
	 * Returns an array of tags which the module is able to process
154
	 *
155
	 * @return \chillerlan\bbcode\Modules\Tagmap
156
	 * @see \chillerlan\bbcode\Modules\ModuleInterface
157
	 */
158
	public function getTags():Tagmap{
159
		$tags = new Tagmap;
160
		$tags->tags = $this->tags;
161
		$tags->noparse_tags = $this->noparse_tags;
162
		$tags->singletags = $this->singletags;
163
164
		return $tags;
165
	}
166
167
	/**
168
	 * Checks if the module supports the current tag
169
	 *
170
	 * @return $this
171
	 * @throws \chillerlan\bbcode\BBCodeException
172
	 */
173
	public function checkTag(){
174
		if(!$this->tag || !in_array($this->tag, $this->tags)){
175
			throw new BBCodeException('tag ['.$this->tag.'] not supported.');
176
		}
177
178
		return $this;
179
	}
180
181
	/**
182
	 * Replaces the EOL placeholder in the given string with a custom token
183
	 *
184
	 * @param string $str   haystack
185
	 * @param string $eol   [optional] custom EOL token, default: ''
186
	 * @param int    $count [optional] replace first $count occurences
0 ignored issues
show
Documentation introduced by
Should the type for parameter $count not be null|integer?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
187
	 *
188
	 * @return string
189
	 */
190
	public function eol(string $str, string $eol = '', int $count = null):string{
191
		return str_replace($this->parserOptions->eol_placeholder, $eol, $str, $count);
192
	}
193
194
	/**
195
	 * Clears all EOL placeholders from self::$content with the base modules EOL token
196
	 *
197
	 * @param string $eol [optional] custom EOL token
0 ignored issues
show
Documentation introduced by
Should the type for parameter $eol not be null|string?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
198
	 *
199
	 * @return $this
200
	 */
201
	public function clearEOL(string $eol = null){
202
		$eol = $eol ?: $this->eol_token;
203
		$this->content = str_replace($this->parserOptions->eol_placeholder, $eol, $this->content);
204
205
		return $this;
206
	}
207
208
	/**
209
	 * Clears all pseudo closing single tag bbcodes like [/br]
210
	 *
211
	 * @return $this
212
	 */
213
	public function clearPseudoClosingTags(){
214
		$this->content = preg_replace('#\[/('.$this->parserOptions->singletags.')]#is', '', $this->content);
215
216
		return $this;
217
	}
218
219
	/**
220
	 * Retrieves an attribute's value by it's name
221
	 *
222
	 * @param string $name     the desired attributes name
223
	 * @param mixed  $default  [optional] a default value in case the attribute isn't set, defaults to false
224
	 *
225
	 * @return mixed the attribute's value in case it exists, otherwise $default
226
	 */
227
	public function getAttribute(string $name, $default = false){
228
		return isset($this->attributes[$name]) && !empty($this->attributes[$name]) ? $this->attributes[$name] : $default;
229
	}
230
231
	/**
232
	 * Retrieves an attribute's value by it's name and checks if it's whitelisted
233
	 *
234
	 * @param string $name      the desired attributes name
235
	 * @param array  $whitelist an array with whitelisted values
236
	 * @param mixed  $default   [optional] a default value in case the attribute isn't set, defaults to false
237
	 *
238
	 * @return mixed boolean if no $default is set, otherwise the attribute's value in case it exists and is whitelisted or $default
239
	 */
240
	public function attributeIn(string $name, array $whitelist, $default = false){
241
		return isset($this->attributes[$name]) && in_array($this->attributes[$name], $whitelist)
242
			? $default !== false ? $this->attributes[$name] : true
243
			: $default;
244
	}
245
246
	/**
247
	 * Checks if an attribute exists and if it exists as key in a whitelist
248
249
	 * @param string $name      the desired attributes name
250
	 * @param array  $whitelist an array with whitelisted key -> value pairs
251
	 * @param mixed  $default   [optional] a default value in case the attribute isn't set, defaults to false
252
	 *
253
	 * @return mixed boolean if no $default is set, otherwise the whitelist value to the given key in case it exists or $default
254
	 */
255
	public function attributeKeyIn(string $name, array $whitelist, $default = false){
256
		return isset($this->attributes[$name]) && array_key_exists($this->attributes[$name], $whitelist)
257
				? $default !== false ? $whitelist[$this->attributes[$name]] : true
258
				: $default;
259
	}
260
261
	/**
262
	 * Checks if the current tag is whitelisted
263
	 *
264
	 * @param array $whitelist an array with whitelisted tag names
265
	 * @param mixed $default   [optional] a default value in case the tag isn't whitelisted
266
	 *
267
	 * @return mixed boolean if no $default is set, otherwise the whitelisted tag or $default
268
	 */
269
	public function tagIn(array $whitelist, $default = false){
270
		return in_array($this->tag, $whitelist)
271
				? $default !== false ? $this->tag : true
272
				: $default;
273
	}
274
275
	/**
276
	 * Sanitizes the content to prevent vulnerabilities or compatibility problems
277
	 *
278
	 * @param $content string to sanitize
279
	 *
280
	 * @return string
281
	 * @codeCoverageIgnore
282
	 */
283
	public function sanitize(string $content):string{
284
		return 'Implement sanitize() method!';
285
	}
286
287
	/**
288
	 * Checks the tag and returns the processed bbcode, called from the parser within a module
289
	 *
290
	 * @see \chillerlan\bbcode\Modules\ModuleInterface::transform()
291
	 */
292
	public function transform():string{
293
		$this->checkTag();
294
295
		/** @var $this \chillerlan\bbcode\Modules\ModuleInterface */
296
		return $this->__transform();
0 ignored issues
show
Bug introduced by
The method __transform() does not exist on chillerlan\bbcode\Modules\BaseModuleAbstract. Did you maybe mean transform()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
297
	}
298
299
	/**
300
	 * shorthand for self::getAttribute('__BBTAG__')
301
	 *
302
	 * @param mixed $default
303
	 *
304
	 * @return mixed $this->attributes['__BBTAG__']
305
	 */
306
	protected function bbtag($default = false){
307
		return $this->getAttribute($this->parserOptions->bbtag_placeholder, $default);
308
	}
309
310
	/**
311
	 * shorthand for self::attributeIn('__BBTAG__', $array)
312
	 *
313
	 * @param array $array
314
	 * @param mixed $default
315
	 *
316
	 * @return mixed
317
	 */
318
	protected function bbtagIn(array $array, $default = false){
319
		return $this->attributeIn($this->parserOptions->bbtag_placeholder, $array, $default);
320
	}
321
322
	/**
323
	 * Checks if an URL is valid using filter_var()
324
	 *
325
	 * @param string $url the URL to check
326
	 *
327
	 * @return bool|string the url if valid, otherwise false
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use false|string.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
328
	 */
329
	public function checkUrl(string $url){
330
		if(filter_var($url, FILTER_VALIDATE_URL) === false){
331
			return false;
332
		}
333
		// todo: check against whitelist?
334
335
		return $url;
336
	}
337
338
	/**
339
	 * Wraps the given content between the wrapper. Obvious, eh?
340
	 *
341
	 * @param string $content
342
	 * @param string $wrapper
343
	 *
344
	 * @return string
345
	 */
346
	public function wrap(string $content, string $wrapper):string{
347
		return $wrapper.$content.$wrapper;
348
	}
349
350
}
351