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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

RulesHelper.php

Zuletzt modifiziert: 02.04.2025, 15:04 - Dateigröße: 6.84 KiB


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  }