Issues (64)

src/Configurator/Items/Tag.php (1 issue)

Severity
1
<?php
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) The s9e authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\TextFormatter\Configurator\Items;
9
10
use InvalidArgumentException;
11
use s9e\TextFormatter\Configurator\Collections\AttributeCollection;
12
use s9e\TextFormatter\Configurator\Collections\AttributePreprocessorCollection;
13
use s9e\TextFormatter\Configurator\Collections\Ruleset;
14
use s9e\TextFormatter\Configurator\Collections\TagFilterChain;
15
use s9e\TextFormatter\Configurator\ConfigProvider;
16
use s9e\TextFormatter\Configurator\Helpers\ConfigHelper;
17
use s9e\TextFormatter\Configurator\Items\Template;
18
use s9e\TextFormatter\Configurator\Traits\Configurable;
19
20
/**
21
* @property AttributeCollection $attributes This tag's attributes
22
* @property AttributePreprocessorCollection $attributePreprocessors This tag's attribute parsers
23
* @property TagFilterChain $filterChain This tag's filter chain
24
* @property integer $nestingLimit Maximum nesting level for this tag
25
* @property Ruleset $rules Rules associated with this tag
26
* @property integer $tagLimit Maximum number of this tag per message
27
* @property-read Template $template Template associated with this tag
28
* @property-write string|Template $template Template associated with this tag
29
*/
30
class Tag implements ConfigProvider
31
{
32
	use Configurable;
33
34
	/**
35
	* @var AttributeCollection This tag's attributes
36
	*/
37
	protected $attributes;
38
39
	/**
40
	* @var AttributePreprocessorCollection This tag's attribute parsers
41
	*/
42
	protected $attributePreprocessors;
43
44
	/**
45
	* @var TagFilterChain This tag's filter chain
46
	*/
47
	protected $filterChain;
48
49
	/**
50
	* @var integer Maximum nesting level for this tag
51
	*/
52
	protected $nestingLimit = 10;
53
54
	/**
55
	* @var Ruleset Rules associated with this tag
56
	*/
57
	protected $rules;
58
59
	/**
60
	* @var integer Maximum number of this tag per message
61
	*/
62
	protected $tagLimit = 5000;
63
64
	/**
65
	* @var Template Template associated with this tag
66
	*/
67
	protected $template;
68
69
	/**
70
	* Constructor
71
	*
72
	* @param  array $options This tag's options
73
	*/
74 22
	public function __construct(?array $options = null)
75
	{
76 22
		$this->attributes             = new AttributeCollection;
77 22
		$this->attributePreprocessors = new AttributePreprocessorCollection;
78 22
		$this->filterChain            = new TagFilterChain;
79 22
		$this->rules                  = new Ruleset;
80
81
		// Start the filterChain with the default processing
82 22
		$this->filterChain->append('s9e\\TextFormatter\\Parser\\FilterProcessing::executeAttributePreprocessors')
83 22
		                  ->addParameterByName('tagConfig')
84 22
		                  ->setJS('executeAttributePreprocessors');
85
86 22
		$this->filterChain->append('s9e\\TextFormatter\\Parser\\FilterProcessing::filterAttributes')
87 22
		                  ->addParameterByName('tagConfig')
88 22
		                  ->addParameterByName('registeredVars')
89 22
		                  ->addParameterByName('logger')
90 22
		                  ->setJS('filterAttributes');
91
92 22
		if (isset($options))
93
		{
94
			// Sort the options by name so that attributes are set before the template, which is
95
			// necessary to evaluate whether the template is safe
96 1
			ksort($options);
97
98 1
			foreach ($options as $optionName => $optionValue)
99
			{
100 1
				$this->__set($optionName, $optionValue);
101
			}
102
		}
103
	}
104
105
	/**
106
	* {@inheritdoc}
107
	*/
108 3
	public function asConfig()
109
	{
110 3
		$vars = get_object_vars($this);
111
112
		// Remove properties that are not needed during parsing
113 3
		unset($vars['template']);
114
115
		// If there are no attribute preprocessors defined, we can remove the step from this tag's
116
		// filterChain
117 3
		if (!count($this->attributePreprocessors))
118
		{
119 3
			$callback = 's9e\\TextFormatter\\Parser\\FilterProcessing::executeAttributePreprocessors';
120
121
			// We operate on a copy of the filterChain, without modifying the original
122 3
			$filterChain = clone $vars['filterChain'];
123
124
			// Process the chain in reverse order so that we don't skip indices
125 3
			$i = count($filterChain);
126 3
			while (--$i >= 0)
127
			{
128 3
				if ($filterChain[$i]->getCallback() === $callback)
129
				{
130 3
					unset($filterChain[$i]);
131
				}
132
			}
133
134 3
			$vars['filterChain'] = $filterChain;
135
		}
136
137 3
		return ConfigHelper::toArray($vars) + ['attributes' => [], 'filterChain' => []];
138
	}
139
140
	/**
141
	* Return this tag's template
142
	*
143
	* @return Template
144
	*/
145 1
	public function getTemplate()
146
	{
147 1
		return $this->template;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->template also could return the type string which is incompatible with the documented return type s9e\TextFormatter\Configurator\Items\Template.
Loading history...
148
	}
149
150
	/**
151
	* Test whether this tag has a template
152
	*
153
	* @return bool
154
	*/
155 2
	public function issetTemplate()
156
	{
157 2
		return isset($this->template);
158
	}
159
160
	/**
161
	* Set this tag's attribute preprocessors
162
	*
163
	* @param  array|AttributePreprocessorCollection $attributePreprocessors 2D array of [attrName=>[regexp]], or an instance of AttributePreprocessorCollection
164
	* @return void
165
	*/
166 3
	public function setAttributePreprocessors($attributePreprocessors)
167
	{
168 3
		$this->attributePreprocessors->clear();
169 3
		$this->attributePreprocessors->merge($attributePreprocessors);
170
	}
171
172
	/**
173
	* Set this tag's nestingLimit
174
	*
175
	* @param  integer $limit
176
	* @return void
177
	*/
178 5
	public function setNestingLimit($limit)
179
	{
180 5
		$limit = (int) $limit;
181
182 5
		if ($limit < 1)
183
		{
184 2
			throw new InvalidArgumentException('nestingLimit must be a number greater than 0');
185
		}
186
187 3
		$this->nestingLimit = $limit;
188
	}
189
190
	/**
191
	* Set this tag's rules
192
	*
193
	* @param  array|Ruleset $rules 2D array of rule definitions, or instance of Ruleset
194
	* @return void
195
	*/
196 3
	public function setRules($rules)
197
	{
198 3
		$this->rules->clear();
199 3
		$this->rules->merge($rules);
200
	}
201
202
	/**
203
	* Set this tag's tagLimit
204
	*
205
	* @param  integer $limit
206
	* @return void
207
	*/
208 4
	public function setTagLimit($limit)
209
	{
210 4
		$limit = (int) $limit;
211
212 4
		if ($limit < 1)
213
		{
214 2
			throw new InvalidArgumentException('tagLimit must be a number greater than 0');
215
		}
216
217 2
		$this->tagLimit = $limit;
218
	}
219
220
	/**
221
	* Set the template associated with this tag
222
	*
223
	* @param  string|Template $template
224
	* @return void
225
	*/
226 5
	public function setTemplate($template)
227
	{
228 5
		if (!($template instanceof Template))
229
		{
230 5
			$template = new Template($template);
231
		}
232
233 5
		$this->template = $template;
234
	}
235
236
	/**
237
	* Unset this tag's template
238
	*
239
	* @return void
240
	*/
241 1
	public function unsetTemplate()
242
	{
243 1
		unset($this->template);
244
	}
245
}