[ Index ]

PHP Cross Reference of phpBB-3.3.3-deutsch

title

Body

[close]

/vendor/s9e/text-formatter/src/Configurator/RendererGenerators/PHP/ -> Serializer.php (source)

   1  <?php
   2  
   3  /**
   4  * @package   s9e\TextFormatter
   5  * @copyright Copyright (c) 2010-2020 The s9e authors
   6  * @license   http://www.opensource.org/licenses/mit-license.php The MIT License
   7  */
   8  namespace s9e\TextFormatter\Configurator\RendererGenerators\PHP;
   9  
  10  use DOMElement;
  11  use DOMXPath;
  12  use RuntimeException;
  13  use s9e\TextFormatter\Configurator\Helpers\AVTHelper;
  14  use s9e\TextFormatter\Configurator\Helpers\TemplateParser;
  15  
  16  class Serializer
  17  {
  18      /**
  19      * @var XPathConvertor XPath-to-PHP convertor
  20      */
  21      public $convertor;
  22  
  23      /**
  24      * @var array Value of the "void" attribute of all elements, using the element's "id" as key
  25      */
  26      protected $isVoid;
  27  
  28      /**
  29      * @var DOMXPath
  30      */
  31      protected $xpath;
  32  
  33      /**
  34      * Constructor
  35      */
  36  	public function __construct()
  37      {
  38          $this->convertor = new XPathConvertor;
  39      }
  40  
  41      /**
  42      * Convert an XPath expression (used in a condition) into PHP code
  43      *
  44      * This method is similar to convertXPath() but it selectively replaces some simple conditions
  45      * with the corresponding DOM method for performance reasons
  46      *
  47      * @param  string $expr XPath expression
  48      * @return string       PHP code
  49      */
  50  	public function convertCondition($expr)
  51      {
  52          return $this->convertor->convertCondition($expr);
  53      }
  54  
  55      /**
  56      * Convert an XPath expression (used as value) into PHP code
  57      *
  58      * @param  string $expr XPath expression
  59      * @return string       PHP code
  60      */
  61  	public function convertXPath($expr)
  62      {
  63          $php = $this->convertor->convertXPath($expr);
  64          if (is_numeric($php))
  65          {
  66              $php = "'" . $php . "'";
  67          }
  68  
  69          return $php;
  70      }
  71  
  72      /**
  73      * Serialize the internal representation of a template into PHP
  74      *
  75      * @param  DOMElement $ir Internal representation
  76      * @return string
  77      */
  78  	public function serialize(DOMElement $ir)
  79      {
  80          $this->xpath  = new DOMXPath($ir->ownerDocument);
  81          $this->isVoid = [];
  82          foreach ($this->xpath->query('//element') as $element)
  83          {
  84              $this->isVoid[$element->getAttribute('id')] = $element->getAttribute('void');
  85          }
  86  
  87          return $this->serializeChildren($ir);
  88      }
  89  
  90      /**
  91      * Convert an attribute value template into PHP
  92      *
  93      * NOTE: escaping must be performed by the caller
  94      *
  95      * @link https://www.w3.org/TR/1999/REC-xslt-19991116#dt-attribute-value-template
  96      *
  97      * @param  string $attrValue Attribute value template
  98      * @return string
  99      */
 100  	protected function convertAttributeValueTemplate($attrValue)
 101      {
 102          $phpExpressions = [];
 103          foreach (AVTHelper::parse($attrValue) as $token)
 104          {
 105              if ($token[0] === 'literal')
 106              {
 107                  $phpExpressions[] = var_export($token[1], true);
 108              }
 109              else
 110              {
 111                  $phpExpressions[] = $this->convertXPath($token[1]);
 112              }
 113          }
 114  
 115          return implode('.', $phpExpressions);
 116      }
 117  
 118      /**
 119      * Escape given literal
 120      *
 121      * @param  string $text    Literal
 122      * @param  string $context Either "raw", "text" or "attribute"
 123      * @return string          Escaped literal
 124      */
 125  	protected function escapeLiteral($text, $context)
 126      {
 127          if ($context === 'raw')
 128          {
 129              return $text;
 130          }
 131  
 132          $escapeMode = ($context === 'attribute') ? ENT_COMPAT : ENT_NOQUOTES;
 133  
 134          return htmlspecialchars($text, $escapeMode);
 135      }
 136  
 137      /**
 138      * Escape the output of given PHP expression
 139      *
 140      * @param  string $php     PHP expression
 141      * @param  string $context Either "raw", "text" or "attribute"
 142      * @return string          PHP expression, including escaping mechanism
 143      */
 144  	protected function escapePHPOutput($php, $context)
 145      {
 146          if ($context === 'raw')
 147          {
 148              return $php;
 149          }
 150  
 151          $escapeMode = ($context === 'attribute') ? ENT_COMPAT : ENT_NOQUOTES;
 152  
 153          return 'htmlspecialchars(' . $php . ',' . $escapeMode . ')';
 154      }
 155  
 156      /**
 157      * Test whether given switch has more than one non-default case
 158      *
 159      * @param  DOMElement $switch <switch/> node
 160      * @return bool
 161      */
 162  	protected function hasMultipleCases(DOMElement $switch)
 163      {
 164          return $this->xpath->evaluate('count(case[@test]) > 1', $switch);
 165      }
 166  
 167      /**
 168      * Test whether given attribute declaration is a minimizable boolean attribute
 169      *
 170      * The test is case-sensitive and only covers attribute that are minimized by libxslt
 171      *
 172      * @param  string $attrName Attribute name
 173      * @param  string $php      Attribute content, in PHP
 174      * @return boolean
 175      */
 176  	protected function isBooleanAttribute(string $attrName, string $php): bool
 177      {
 178          $attrNames = ['checked', 'compact', 'declare', 'defer', 'disabled', 'ismap', 'multiple', 'nohref', 'noresize', 'noshade', 'nowrap', 'readonly', 'selected'];
 179          if (!in_array($attrName, $attrNames, true))
 180          {
 181              return false;
 182          }
 183  
 184          return ($php === '' || $php === "\$this->out.='" . $attrName . "';");
 185      }
 186  
 187      /**
 188      * Serialize an <applyTemplates/> node
 189      *
 190      * @param  DOMElement $applyTemplates <applyTemplates/> node
 191      * @return string
 192      */
 193  	protected function serializeApplyTemplates(DOMElement $applyTemplates)
 194      {
 195          $php = '$this->at($node';
 196          if ($applyTemplates->hasAttribute('select'))
 197          {
 198              $php .= ',' . var_export($applyTemplates->getAttribute('select'), true);
 199          }
 200          $php .= ');';
 201  
 202          return $php;
 203      }
 204  
 205      /**
 206      * Serialize an <attribute/> node
 207      *
 208      * @param  DOMElement $attribute <attribute/> node
 209      * @return string
 210      */
 211  	protected function serializeAttribute(DOMElement $attribute)
 212      {
 213          $attrName = $attribute->getAttribute('name');
 214  
 215          // PHP representation of this attribute's name
 216          $phpAttrName = $this->convertAttributeValueTemplate($attrName);
 217  
 218          // NOTE: the attribute name is escaped by default to account for dynamically-generated names
 219          $phpAttrName = 'htmlspecialchars(' . $phpAttrName . ',' . ENT_QUOTES . ')';
 220  
 221          $php     = "\$this->out.=' '." . $phpAttrName;
 222          $content = $this->serializeChildren($attribute);
 223          if (!$this->isBooleanAttribute($attrName, $content))
 224          {
 225              $php .= ".'=\"';" . $content . "\$this->out.='\"'";
 226          }
 227          $php .= ';';
 228  
 229          return $php;
 230      }
 231  
 232      /**
 233      * Serialize all the children of given node into PHP
 234      *
 235      * @param  DOMElement $ir Internal representation
 236      * @return string
 237      */
 238  	protected function serializeChildren(DOMElement $ir)
 239      {
 240          $php = '';
 241          foreach ($ir->childNodes as $node)
 242          {
 243              if ($node instanceof DOMElement)
 244              {
 245                  $methodName = 'serialize' . ucfirst($node->localName);
 246                  $php .= $this->$methodName($node);
 247              }
 248          }
 249  
 250          return $php;
 251      }
 252  
 253      /**
 254      * Serialize a <closeTag/> node
 255      *
 256      * @param  DOMElement $closeTag <closeTag/> node
 257      * @return string
 258      */
 259  	protected function serializeCloseTag(DOMElement $closeTag)
 260      {
 261          $php = "\$this->out.='>';";
 262          $id  = $closeTag->getAttribute('id');
 263  
 264          if ($closeTag->hasAttribute('set'))
 265          {
 266              $php .= '$t' . $id . '=1;';
 267          }
 268  
 269          if ($closeTag->hasAttribute('check'))
 270          {
 271              $php = 'if(!isset($t' . $id . ')){' . $php . '}';
 272          }
 273  
 274          if ($this->isVoid[$id] === 'maybe')
 275          {
 276              // Check at runtime whether this element is not void
 277              $php .= 'if(!$v' . $id . '){';
 278          }
 279  
 280          return $php;
 281      }
 282  
 283      /**
 284      * Serialize a <comment/> node
 285      *
 286      * @param  DOMElement $comment <comment/> node
 287      * @return string
 288      */
 289  	protected function serializeComment(DOMElement $comment)
 290      {
 291          return "\$this->out.='<!--';"
 292               . $this->serializeChildren($comment)
 293               . "\$this->out.='-->';";
 294      }
 295  
 296      /**
 297      * Serialize a <copyOfAttributes/> node
 298      *
 299      * @param  DOMElement $copyOfAttributes <copyOfAttributes/> node
 300      * @return string
 301      */
 302  	protected function serializeCopyOfAttributes(DOMElement $copyOfAttributes)
 303      {
 304          return 'foreach($node->attributes as $attribute)'
 305               . '{'
 306               . "\$this->out.=' ';"
 307               . "\$this->out.=\$attribute->name;"
 308               . "\$this->out.='=\"';"
 309               . "\$this->out.=htmlspecialchars(\$attribute->value," . ENT_COMPAT . ");"
 310               . "\$this->out.='\"';"
 311               . '}';
 312      }
 313  
 314      /**
 315      * Serialize an <element/> node
 316      *
 317      * @param  DOMElement $element <element/> node
 318      * @return string
 319      */
 320  	protected function serializeElement(DOMElement $element)
 321      {
 322          $php     = '';
 323          $elName  = $element->getAttribute('name');
 324          $id      = $element->getAttribute('id');
 325          $isVoid  = $element->getAttribute('void');
 326  
 327          // Test whether this element name is dynamic
 328          $isDynamic = (bool) (strpos($elName, '{') !== false);
 329  
 330          // PHP representation of this element's name
 331          $phpElName = $this->convertAttributeValueTemplate($elName);
 332  
 333          // NOTE: the element name is escaped by default to account for dynamically-generated names
 334          $phpElName = 'htmlspecialchars(' . $phpElName . ',' . ENT_QUOTES . ')';
 335  
 336          // If the element name is dynamic, we cache its name for convenience and performance
 337          if ($isDynamic)
 338          {
 339              $varName = '$e' . $id;
 340  
 341              // Add the var declaration to the source
 342              $php .= $varName . '=' . $phpElName . ';';
 343  
 344              // Replace the element name with the var
 345              $phpElName = $varName;
 346          }
 347  
 348          // Test whether this element is void if we need this information
 349          if ($isVoid === 'maybe')
 350          {
 351              $php .= '$v' . $id . '=preg_match(' . var_export(TemplateParser::$voidRegexp, true) . ',' . $phpElName . ');';
 352          }
 353  
 354          // Open the start tag
 355          $php .= "\$this->out.='<'." . $phpElName . ';';
 356  
 357          // Serialize this element's content
 358          $php .= $this->serializeChildren($element);
 359  
 360          // Close that element unless we know it's void
 361          if ($isVoid !== 'yes')
 362          {
 363              $php .= "\$this->out.='</'." . $phpElName . ".'>';";
 364          }
 365  
 366          // If this element was maybe void, serializeCloseTag() has put its content within an if
 367          // block. We need to close that block
 368          if ($isVoid === 'maybe')
 369          {
 370              $php .= '}';
 371          }
 372  
 373          return $php;
 374      }
 375  
 376      /**
 377      * Serialize a <switch/> node that has a branch-key attribute
 378      *
 379      * @param  DOMElement $switch <switch/> node
 380      * @return string
 381      */
 382  	protected function serializeHash(DOMElement $switch)
 383      {
 384          $statements = [];
 385          foreach ($this->xpath->query('case[@branch-values]', $switch) as $case)
 386          {
 387              foreach (unserialize($case->getAttribute('branch-values')) as $value)
 388              {
 389                  $statements[$value] = $this->serializeChildren($case);
 390              }
 391          }
 392          if (!isset($case))
 393          {
 394              throw new RuntimeException;
 395          }
 396  
 397          $defaultCase = $this->xpath->query('case[not(@branch-values)]', $switch)->item(0);
 398          $defaultCode = ($defaultCase instanceof DOMElement) ? $this->serializeChildren($defaultCase) : '';
 399          $expr        = $this->convertXPath($switch->getAttribute('branch-key'));
 400  
 401          return SwitchStatement::generate($expr, $statements, $defaultCode);
 402      }
 403  
 404      /**
 405      * Serialize an <output/> node
 406      *
 407      * @param  DOMElement $output <output/> node
 408      * @return string
 409      */
 410  	protected function serializeOutput(DOMElement $output)
 411      {
 412          $context = $output->getAttribute('escape');
 413  
 414          $php = '$this->out.=';
 415          if ($output->getAttribute('type') === 'xpath')
 416          {
 417              $php .= $this->escapePHPOutput($this->convertXPath($output->textContent), $context);
 418          }
 419          else
 420          {
 421              $php .= var_export($this->escapeLiteral($output->textContent, $context), true);
 422          }
 423          $php .= ';';
 424  
 425          return $php;
 426      }
 427  
 428      /**
 429      * Serialize a <switch/> node
 430      *
 431      * @param  DOMElement $switch <switch/> node
 432      * @return string
 433      */
 434  	protected function serializeSwitch(DOMElement $switch)
 435      {
 436          // Use a specialized branch table if the minimum number of branches is reached
 437          if ($switch->hasAttribute('branch-key') && $this->hasMultipleCases($switch))
 438          {
 439              return $this->serializeHash($switch);
 440          }
 441  
 442          $php   = '';
 443          $if    = 'if';
 444          foreach ($this->xpath->query('case', $switch) as $case)
 445          {
 446              if ($case->hasAttribute('test'))
 447              {
 448                  $php .= $if . '(' . $this->convertCondition($case->getAttribute('test')) . ')';
 449              }
 450              else
 451              {
 452                  $php .= 'else';
 453              }
 454  
 455              $php .= '{' . $this->serializeChildren($case) . '}';
 456              $if   = 'elseif';
 457          }
 458  
 459          return $php;
 460      }
 461  }


Generated: Sun Feb 14 20:08:31 2021 Cross-referenced by PHPXref 0.7.1