Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
RulesHelper.php
001 <?php
002
003 /**
004 * @package s9e\TextFormatter
005 * @copyright Copyright (c) 2010-2022 The s9e authors
006 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
007 */
008 namespace s9e\TextFormatter\Configurator\Helpers;
009
010 use s9e\TextFormatter\Configurator\Collections\Ruleset;
011 use s9e\TextFormatter\Configurator\Collections\TagCollection;
012
013 abstract class RulesHelper
014 {
015 /**
016 * Generate the allowedChildren and allowedDescendants bitfields for every tag and for the root context
017 *
018 * @param TagCollection $tags
019 * @param Ruleset $rootRules
020 * @return array
021 */
022 public static function getBitfields(TagCollection $tags, Ruleset $rootRules)
023 {
024 $rules = ['*root*' => iterator_to_array($rootRules)];
025 foreach ($tags as $tagName => $tag)
026 {
027 $rules[$tagName] = iterator_to_array($tag->rules);
028 }
029
030 // Create a matrix that contains all of the tags and whether every other tag is allowed as
031 // a child and as a descendant
032 $matrix = self::unrollRules($rules);
033
034 // Remove unusable tags from the matrix
035 self::pruneMatrix($matrix);
036
037 // Group together tags are allowed in the exact same contexts
038 $groupedTags = [];
039 foreach (array_keys($matrix) as $tagName)
040 {
041 if ($tagName === '*root*')
042 {
043 continue;
044 }
045
046 $k = '';
047 foreach ($matrix as $tagMatrix)
048 {
049 $k .= $tagMatrix['allowedChildren'][$tagName];
050 $k .= $tagMatrix['allowedDescendants'][$tagName];
051 }
052
053 $groupedTags[$k][] = $tagName;
054 }
055
056 // Record the bit number of each tag, and the name of a tag for each bit
057 $bitTag = [];
058 $bitNumber = 0;
059 $tagsConfig = [];
060 foreach ($groupedTags as $tagNames)
061 {
062 foreach ($tagNames as $tagName)
063 {
064 $tagsConfig[$tagName]['bitNumber'] = $bitNumber;
065 $bitTag[$bitNumber] = $tagName;
066 }
067
068 ++$bitNumber;
069 }
070
071 // Build the bitfields of each tag, including the *root* pseudo-tag
072 foreach ($matrix as $tagName => $tagMatrix)
073 {
074 $allowedChildren = '';
075 $allowedDescendants = '';
076 foreach ($bitTag as $targetName)
077 {
078 $allowedChildren .= $tagMatrix['allowedChildren'][$targetName];
079 $allowedDescendants .= $tagMatrix['allowedDescendants'][$targetName];
080 }
081
082 $tagsConfig[$tagName]['allowed'] = self::pack($allowedChildren, $allowedDescendants);
083 }
084
085 // Prepare the return value
086 $return = [
087 'root' => $tagsConfig['*root*'],
088 'tags' => $tagsConfig
089 ];
090 unset($return['tags']['*root*']);
091
092 return $return;
093 }
094
095 /**
096 * Initialize a matrix of settings
097 *
098 * @param array $rules Rules for each tag
099 * @return array Multidimensional array of [tagName => [scope => [targetName => setting]]]
100 */
101 protected static function initMatrix(array $rules)
102 {
103 $matrix = [];
104 $tagNames = array_keys($rules);
105
106 foreach ($rules as $tagName => $tagRules)
107 {
108 $matrix[$tagName]['allowedChildren'] = array_fill_keys($tagNames, 0);
109 $matrix[$tagName]['allowedDescendants'] = array_fill_keys($tagNames, 0);
110 }
111
112 return $matrix;
113 }
114
115 /**
116 * Apply given rule from each applicable tag
117 *
118 * For each tag, if the rule has any target we set the corresponding value for each target in the
119 * matrix
120 *
121 * @param array &$matrix Settings matrix
122 * @param array $rules Rules for each tag
123 * @param string $ruleName Rule name
124 * @param string $key Key in the matrix
125 * @param integer $value Value to be set
126 * @return void
127 */
128 protected static function applyTargetedRule(array &$matrix, $rules, $ruleName, $key, $value)
129 {
130 foreach ($rules as $tagName => $tagRules)
131 {
132 if (!isset($tagRules[$ruleName]))
133 {
134 continue;
135 }
136
137 foreach ($tagRules[$ruleName] as $targetName)
138 {
139 $matrix[$tagName][$key][$targetName] = $value;
140 }
141 }
142 }
143
144 /**
145 * @param array $rules
146 * @return array
147 */
148 protected static function unrollRules(array $rules)
149 {
150 // Initialize the matrix with default values
151 $matrix = self::initMatrix($rules);
152
153 // Convert ignoreTags and requireParent to denyDescendant and denyChild rules
154 $tagNames = array_keys($rules);
155 foreach ($rules as $tagName => $tagRules)
156 {
157 if (!empty($tagRules['ignoreTags']))
158 {
159 $rules[$tagName]['denyChild'] = $tagNames;
160 $rules[$tagName]['denyDescendant'] = $tagNames;
161 }
162
163 if (!empty($tagRules['requireParent']))
164 {
165 $denyParents = array_diff($tagNames, $tagRules['requireParent']);
166 foreach ($denyParents as $parentName)
167 {
168 $rules[$parentName]['denyChild'][] = $tagName;
169 }
170 }
171 }
172
173 // Apply "allow" rules to grant usage, overwriting the default settings
174 self::applyTargetedRule($matrix, $rules, 'allowChild', 'allowedChildren', 1);
175 self::applyTargetedRule($matrix, $rules, 'allowDescendant', 'allowedDescendants', 1);
176
177 // Apply "deny" rules to remove usage
178 self::applyTargetedRule($matrix, $rules, 'denyChild', 'allowedChildren', 0);
179 self::applyTargetedRule($matrix, $rules, 'denyDescendant', 'allowedDescendants', 0);
180
181 return $matrix;
182 }
183
184 /**
185 * Remove unusable tags from the matrix
186 *
187 * @param array &$matrix
188 * @return void
189 */
190 protected static function pruneMatrix(array &$matrix)
191 {
192 $usableTags = ['*root*' => 1];
193
194 // Start from the root and keep digging
195 $parentTags = $usableTags;
196 do
197 {
198 $nextTags = [];
199 foreach (array_keys($parentTags) as $tagName)
200 {
201 // Accumulate the names of tags that are allowed as children of our parent tags
202 $nextTags += array_filter($matrix[$tagName]['allowedChildren']);
203 }
204
205 // Keep only the tags that are in the matrix but aren't in the usable array yet, then
206 // add them to the array
207 $parentTags = array_diff_key($nextTags, $usableTags);
208 $parentTags = array_intersect_key($parentTags, $matrix);
209 $usableTags += $parentTags;
210 }
211 while (!empty($parentTags));
212
213 // Remove unusable tags from the matrix
214 $matrix = array_intersect_key($matrix, $usableTags);
215 unset($usableTags['*root*']);
216
217 // Remove unusable tags from the targets
218 foreach ($matrix as $tagName => &$tagMatrix)
219 {
220 $tagMatrix['allowedChildren']
221 = array_intersect_key($tagMatrix['allowedChildren'], $usableTags);
222
223 $tagMatrix['allowedDescendants']
224 = array_intersect_key($tagMatrix['allowedDescendants'], $usableTags);
225 }
226 unset($tagMatrix);
227 }
228
229 /**
230 * Convert a binary representation such as "101011" to an array of integer
231 *
232 * Each bitfield is split in groups of 8 bits, then converted to a 16-bit integer where the
233 * allowedChildren bitfield occupies the least significant bits and the allowedDescendants
234 * bitfield occupies the most significant bits
235 *
236 * @param string $allowedChildren
237 * @param string $allowedDescendants
238 * @return integer[]
239 */
240 protected static function pack($allowedChildren, $allowedDescendants)
241 {
242 $allowedChildren = str_split($allowedChildren, 8);
243 $allowedDescendants = str_split($allowedDescendants, 8);
244
245 $allowed = [];
246 foreach (array_keys($allowedChildren) as $k)
247 {
248 $allowed[] = bindec(sprintf(
249 '%1$08s%2$08s',
250 strrev($allowedDescendants[$k]),
251 strrev($allowedChildren[$k])
252 ));
253 }
254
255 return $allowed;
256 }
257 }