[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @package s9e\TextFormatter 5 * @copyright Copyright (c) 2010-2022 The s9e authors 6 * @license http://www.opensource.org/licenses/mit-license.php The MIT License 7 */ 8 namespace s9e\TextFormatter\Configurator\Helpers; 9 10 use s9e\TextFormatter\Configurator\Collections\Ruleset; 11 use s9e\TextFormatter\Configurator\Collections\TagCollection; 12 13 abstract class RulesHelper 14 { 15 /** 16 * Generate the allowedChildren and allowedDescendants bitfields for every tag and for the root context 17 * 18 * @param TagCollection $tags 19 * @param Ruleset $rootRules 20 * @return array 21 */ 22 public static function getBitfields(TagCollection $tags, Ruleset $rootRules) 23 { 24 $rules = ['*root*' => iterator_to_array($rootRules)]; 25 foreach ($tags as $tagName => $tag) 26 { 27 $rules[$tagName] = iterator_to_array($tag->rules); 28 } 29 30 // Create a matrix that contains all of the tags and whether every other tag is allowed as 31 // a child and as a descendant 32 $matrix = self::unrollRules($rules); 33 34 // Remove unusable tags from the matrix 35 self::pruneMatrix($matrix); 36 37 // Group together tags are allowed in the exact same contexts 38 $groupedTags = []; 39 foreach (array_keys($matrix) as $tagName) 40 { 41 if ($tagName === '*root*') 42 { 43 continue; 44 } 45 46 $k = ''; 47 foreach ($matrix as $tagMatrix) 48 { 49 $k .= $tagMatrix['allowedChildren'][$tagName]; 50 $k .= $tagMatrix['allowedDescendants'][$tagName]; 51 } 52 53 $groupedTags[$k][] = $tagName; 54 } 55 56 // Record the bit number of each tag, and the name of a tag for each bit 57 $bitTag = []; 58 $bitNumber = 0; 59 $tagsConfig = []; 60 foreach ($groupedTags as $tagNames) 61 { 62 foreach ($tagNames as $tagName) 63 { 64 $tagsConfig[$tagName]['bitNumber'] = $bitNumber; 65 $bitTag[$bitNumber] = $tagName; 66 } 67 68 ++$bitNumber; 69 } 70 71 // Build the bitfields of each tag, including the *root* pseudo-tag 72 foreach ($matrix as $tagName => $tagMatrix) 73 { 74 $allowedChildren = ''; 75 $allowedDescendants = ''; 76 foreach ($bitTag as $targetName) 77 { 78 $allowedChildren .= $tagMatrix['allowedChildren'][$targetName]; 79 $allowedDescendants .= $tagMatrix['allowedDescendants'][$targetName]; 80 } 81 82 $tagsConfig[$tagName]['allowed'] = self::pack($allowedChildren, $allowedDescendants); 83 } 84 85 // Prepare the return value 86 $return = [ 87 'root' => $tagsConfig['*root*'], 88 'tags' => $tagsConfig 89 ]; 90 unset($return['tags']['*root*']); 91 92 return $return; 93 } 94 95 /** 96 * Initialize a matrix of settings 97 * 98 * @param array $rules Rules for each tag 99 * @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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |