Completed
Push — master ( ba76dd...955c8e )
by Josh
27:23
created

RulesGenerator::getTagInspectors()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 1
1
<?php
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) 2010-2017 The s9e Authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\TextFormatter\Configurator;
9
10
use ArrayAccess;
11
use DOMDocument;
12
use Iterator;
13
use s9e\TextFormatter\Configurator\Collections\RulesGeneratorList;
14
use s9e\TextFormatter\Configurator\Collections\TagCollection;
15
use s9e\TextFormatter\Configurator\Helpers\TemplateInspector;
16
use s9e\TextFormatter\Configurator\RulesGenerators\Interfaces\BooleanRulesGenerator;
17
use s9e\TextFormatter\Configurator\RulesGenerators\Interfaces\TargetedRulesGenerator;
18
use s9e\TextFormatter\Configurator\Traits\CollectionProxy;
19
20
/**
21
* @method mixed   add(mixed $value, null $void)
22
* @method mixed   append(mixed $value)
23
* @method array   asConfig()
24
* @method void    clear()
25
* @method bool    contains(mixed $value)
26
* @method integer count()
27
* @method mixed   current()
28
* @method void    delete(string $key)
29
* @method bool    exists(string $key)
30
* @method mixed   get(string $key)
31
* @method mixed   indexOf(mixed $value)
32
* @method mixed   insert(integer $offset, mixed $value)
33
* @method integer|string key()
34
* @method mixed   next()
35
* @method integer normalizeKey(mixed $key)
36
* @method BooleanRulesGenerator|TargetedRulesGenerator normalizeValue(string|BooleanRulesGenerator|TargetedRulesGenerator $generator)
37
* @method bool    offsetExists(string|integer $offset)
38
* @method mixed   offsetGet(string|integer $offset)
39
* @method void    offsetSet(mixed $offset, mixed $value)
40
* @method void    offsetUnset(string|integer $offset)
41
* @method string  onDuplicate(string|null $action)
42
* @method mixed   prepend(mixed $value)
43
* @method integer remove(mixed $value)
44
* @method void    rewind()
45
* @method mixed   set(string $key, mixed $value)
46
* @method bool    valid()
47
*/
48
class RulesGenerator implements ArrayAccess, Iterator
49
{
50
	use CollectionProxy;
51
52
	/**
53
	* @var RulesGeneratorList Collection of objects
54
	*/
55
	protected $collection;
56
57
	/**
58
	* Constructor
59
	*
60
	* Will load the default rule generators
61
	*/
62
	public function __construct()
63
	{
64
		$this->collection = new RulesGeneratorList;
65
		$this->collection->append('AutoCloseIfVoid');
66
		$this->collection->append('AutoReopenFormattingElements');
67
		$this->collection->append('BlockElementsCloseFormattingElements');
68
		$this->collection->append('BlockElementsFosterFormattingElements');
69
		$this->collection->append('DisableAutoLineBreaksIfNewLinesArePreserved');
70
		$this->collection->append('EnforceContentModels');
71
		$this->collection->append('EnforceOptionalEndTags');
72
		$this->collection->append('IgnoreTagsInCode');
73
		$this->collection->append('IgnoreTextIfDisallowed');
74
		$this->collection->append('IgnoreWhitespaceAroundBlockElements');
75
		$this->collection->append('TrimFirstLineInCodeBlocks');
76
	}
77
78
	/**
79
	* Generate rules for given tag collection
80
	*
81
	* @param  TagCollection $tags Tags collection
82
	* @return array
83
	*/
84
	public function getRules(TagCollection $tags)
85
	{
86
		$tagInspectors = $this->getTagInspectors($tags);
87
88
		return [
89
			'root' => $this->generateRootRules($tagInspectors),
90
			'tags' => $this->generateTagRules($tagInspectors)
91
		];
92
	}
93
94
	/**
95
	* Generate and return rules based on a set of TemplateInspector
96
	*
97
	* @param  array $tagInspectors Array of [tagName => TemplateInspector]
98
	* @return array                Array of [tagName => [<rules>]]
99
	*/
100
	protected function generateTagRules(array $tagInspectors)
101
	{
102
		$rules = [];
103
		foreach ($tagInspectors as $tagName => $tagInspector)
104
		{
105
			$rules[$tagName] = $this->generateRuleset($tagInspector, $tagInspectors);
106
		}
107
108
		return $rules;
109
	}
110
111
	/**
112
	* Generate a set of rules to be applied at the root of a document
113
	*
114
	* @param  array $tagInspectors Array of [tagName => TemplateInspector]
115
	* @return array
116
	*/
117
	protected function generateRootRules(array $tagInspectors)
118
	{
119
		// Create a proxy for the parent markup so that we can determine which tags are allowed at
120
		// the root of the text (IOW, with no parent) or even disabled altogether
121
		$rootInspector = new TemplateInspector('<div><xsl:apply-templates/></div>');
122
		$rules         = $this->generateRuleset($rootInspector, $tagInspectors);
123
124
		// Remove root rules that wouldn't be applied anyway
125
		unset($rules['autoClose']);
126
		unset($rules['autoReopen']);
127
		unset($rules['breakParagraph']);
128
		unset($rules['closeAncestor']);
129
		unset($rules['closeParent']);
130
		unset($rules['fosterParent']);
131
		unset($rules['ignoreSurroundingWhitespace']);
132
		unset($rules['isTransparent']);
133
		unset($rules['requireAncestor']);
134
		unset($rules['requireParent']);
135
136
		return $rules;
137
	}
138
139
	/**
140
	* Generate a set of rules for a single TemplateInspector instance
141
	*
142
	* @param  TemplateInspector $srcInspector  Source of the rules
143
	* @param  array             $trgInspectors Array of [tagName => TemplateInspector]
144
	* @return array
145
	*/
146
	protected function generateRuleset(TemplateInspector $srcInspector, array $trgInspectors)
147
	{
148
		$rules = [];
149
		foreach ($this->collection as $rulesGenerator)
150
		{
151
			if ($rulesGenerator instanceof BooleanRulesGenerator)
152
			{
153
				foreach ($rulesGenerator->generateBooleanRules($srcInspector) as $ruleName => $bool)
154
				{
155
					$rules[$ruleName] = $bool;
156
				}
157
			}
158
159
			if ($rulesGenerator instanceof TargetedRulesGenerator)
160
			{
161
				foreach ($trgInspectors as $tagName => $trgInspector)
162
				{
163
					$targetedRules = $rulesGenerator->generateTargetedRules($srcInspector, $trgInspector);
164
					foreach ($targetedRules as $ruleName)
165
					{
166
						$rules[$ruleName][] = $tagName;
167
					}
168
				}
169
			}
170
		}
171
172
		return $rules;
173
	}
174
175
	/**
176
	* Inspect given list of tags
177
	*
178
	* @param  TagCollection $tags Tags collection
179
	* @return array               Array of [tagName => TemplateInspector]
180
	*/
181
	protected function getTagInspectors(TagCollection $tags)
182
	{
183
		$tagInspectors = [];
184
		foreach ($tags as $tagName => $tag)
185
		{
186
			// Use the tag's template if applicable or XSLT's implicit default otherwise
187
			$template = (isset($tag->template)) ? $tag->template : '<xsl:apply-templates/>';
188
			$tagInspectors[$tagName] = new TemplateInspector($template);
189
		}
190
191
		return $tagInspectors;
192
	}
193
}