[ Index ]

PHP Cross Reference of phpBB-3.3.14-deutsch

title

Body

[close]

/vendor/s9e/text-formatter/src/Configurator/Helpers/ -> RulesHelper.php (source)

   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  }


Generated: Mon Nov 25 19:05:08 2024 Cross-referenced by PHPXref 0.7.1