[ Index ]

PHP Cross Reference of phpBB-3.3.14-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-2022 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      * Convert a dynamic xsl:attribute/xsl:element name into PHP
 120      *
 121      * @param  string $attrValue Attribute value template
 122      * @return string
 123      */
 124  	protected function convertDynamicNodeName(string $attrValue): string
 125      {
 126          if (strpos($attrValue, '{') === false)
 127          {
 128              return var_export(htmlspecialchars($attrValue, ENT_QUOTES), true);
 129          }
 130  
 131          return 'htmlspecialchars(' . $this->convertAttributeValueTemplate($attrValue) . ',' . ENT_QUOTES . ')';
 132      }
 133  
 134      /**
 135      * Escape given literal
 136      *
 137      * @param  string $text    Literal
 138      * @param  string $context Either "raw", "text" or "attribute"
 139      * @return string          Escaped literal
 140      */
 141  	protected function escapeLiteral($text, $context)
 142      {
 143          if ($context === 'raw')
 144          {
 145              return $text;
 146          }
 147  
 148          $escapeMode = ($context === 'attribute') ? ENT_COMPAT : ENT_NOQUOTES;
 149  
 150          return htmlspecialchars($text, $escapeMode);
 151      }
 152  
 153      /**
 154      * Escape the output of given PHP expression
 155      *
 156      * @param  string $php     PHP expression
 157      * @param  string $context Either "raw", "text" or "attribute"
 158      * @return string          PHP expression, including escaping mechanism
 159      */
 160  	protected function escapePHPOutput($php, $context)
 161      {
 162          if ($context === 'raw')
 163          {
 164              return $php;
 165          }
 166  
 167          $escapeMode = ($context === 'attribute') ? ENT_COMPAT : ENT_NOQUOTES;
 168  
 169          return 'htmlspecialchars(' . $php . ',' . $escapeMode . ')';
 170      }
 171  
 172      /**
 173      * Test whether given switch has more than one non-default case
 174      *
 175      * @param  DOMElement $switch <switch/> node
 176      * @return bool
 177      */
 178  	protected function hasMultipleCases(DOMElement $switch)
 179      {
 180          return $this->xpath->evaluate('count(case[@test]) > 1', $switch);
 181      }
 182  
 183      /**
 184      * Test whether given attribute declaration is a minimizable boolean attribute
 185      *
 186      * @param  DOMElement $attribute <attribute/> node
 187      * @param  string     $php       Attribute content, in PHP
 188      * @return boolean
 189      */
 190  	protected function isBooleanAttribute(DOMElement $attribute, string $php): bool
 191      {
 192          if ($attribute->getAttribute('boolean') !== 'yes')
 193          {
 194              return false;
 195          }
 196  
 197          return ($php === '' || $php === "\$this->out.='" . $attribute->getAttribute('name') . "';");
 198      }
 199  
 200      /**
 201      * Serialize an <applyTemplates/> node
 202      *
 203      * @param  DOMElement $applyTemplates <applyTemplates/> node
 204      * @return string
 205      */
 206  	protected function serializeApplyTemplates(DOMElement $applyTemplates)
 207      {
 208          $php = '$this->at($node';
 209          if ($applyTemplates->hasAttribute('select'))
 210          {
 211              $php .= ',' . var_export($applyTemplates->getAttribute('select'), true);
 212          }
 213          $php .= ');';
 214  
 215          return $php;
 216      }
 217  
 218      /**
 219      * Serialize an <attribute/> node
 220      *
 221      * @param  DOMElement $attribute <attribute/> node
 222      * @return string
 223      */
 224  	protected function serializeAttribute(DOMElement $attribute)
 225      {
 226          $attrName = $attribute->getAttribute('name');
 227  
 228          // PHP representation of this attribute's name
 229          $phpAttrName = $this->convertDynamicNodeName($attrName);
 230  
 231          $php     = "\$this->out.=' '." . $phpAttrName;
 232          $content = $this->serializeChildren($attribute);
 233          if (!$this->isBooleanAttribute($attribute, $content))
 234          {
 235              $php .= ".'=\"';" . $content . "\$this->out.='\"'";
 236          }
 237          $php .= ';';
 238  
 239          return $php;
 240      }
 241  
 242      /**
 243      * Serialize all the children of given node into PHP
 244      *
 245      * @param  DOMElement $ir Internal representation
 246      * @return string
 247      */
 248  	protected function serializeChildren(DOMElement $ir)
 249      {
 250          $php = '';
 251          foreach ($ir->childNodes as $node)
 252          {
 253              if ($node instanceof DOMElement)
 254              {
 255                  $methodName = 'serialize' . ucfirst($node->localName);
 256                  $php .= $this->$methodName($node);
 257              }
 258          }
 259  
 260          return $php;
 261      }
 262  
 263      /**
 264      * Serialize a <closeTag/> node
 265      *
 266      * @param  DOMElement $closeTag <closeTag/> node
 267      * @return string
 268      */
 269  	protected function serializeCloseTag(DOMElement $closeTag)
 270      {
 271          $php = "\$this->out.='>';";
 272          $id  = $closeTag->getAttribute('id');
 273  
 274          if ($closeTag->hasAttribute('set'))
 275          {
 276              $php .= '$t' . $id . '=1;';
 277          }
 278  
 279          if ($closeTag->hasAttribute('check'))
 280          {
 281              $php = 'if(!isset($t' . $id . ')){' . $php . '}';
 282          }
 283  
 284          if ($this->isVoid[$id] === 'maybe')
 285          {
 286              // Check at runtime whether this element is not void
 287              $php .= 'if(!$v' . $id . '){';
 288          }
 289  
 290          return $php;
 291      }
 292  
 293      /**
 294      * Serialize a <comment/> node
 295      *
 296      * @param  DOMElement $comment <comment/> node
 297      * @return string
 298      */
 299  	protected function serializeComment(DOMElement $comment)
 300      {
 301          return "\$this->out.='<!--';"
 302               . $this->serializeChildren($comment)
 303               . "\$this->out.='-->';";
 304      }
 305  
 306      /**
 307      * Serialize a <copyOfAttributes/> node
 308      *
 309      * @param  DOMElement $copyOfAttributes <copyOfAttributes/> node
 310      * @return string
 311      */
 312  	protected function serializeCopyOfAttributes(DOMElement $copyOfAttributes)
 313      {
 314          return 'foreach($node->attributes as $attribute)'
 315               . '{'
 316               . "\$this->out.=' ';"
 317               . "\$this->out.=\$attribute->name;"
 318               . "\$this->out.='=\"';"
 319               . "\$this->out.=htmlspecialchars(\$attribute->value," . ENT_COMPAT . ");"
 320               . "\$this->out.='\"';"
 321               . '}';
 322      }
 323  
 324      /**
 325      * Serialize an <element/> node
 326      *
 327      * @param  DOMElement $element <element/> node
 328      * @return string
 329      */
 330  	protected function serializeElement(DOMElement $element)
 331      {
 332          $php     = '';
 333          $elName  = $element->getAttribute('name');
 334          $id      = $element->getAttribute('id');
 335          $isVoid  = $element->getAttribute('void');
 336  
 337          // Test whether this element name is dynamic
 338          $isDynamic = (bool) (strpos($elName, '{') !== false);
 339  
 340          // PHP representation of this element's name
 341          $phpElName = $this->convertDynamicNodeName($elName);
 342  
 343          // If the element name is dynamic, we cache its name for convenience and performance
 344          if ($isDynamic)
 345          {
 346              $varName = '$e' . $id;
 347  
 348              // Add the var declaration to the source
 349              $php .= $varName . '=' . $phpElName . ';';
 350  
 351              // Replace the element name with the var
 352              $phpElName = $varName;
 353          }
 354  
 355          // Test whether this element is void if we need this information
 356          if ($isVoid === 'maybe')
 357          {
 358              $php .= '$v' . $id . '=preg_match(' . var_export(TemplateParser::$voidRegexp, true) . ',' . $phpElName . ');';
 359          }
 360  
 361          // Open the start tag
 362          $php .= "\$this->out.='<'." . $phpElName . ';';
 363  
 364          // Serialize this element's content
 365          $php .= $this->serializeChildren($element);
 366  
 367          // Close that element unless we know it's void
 368          if ($isVoid !== 'yes')
 369          {
 370              $php .= "\$this->out.='</'." . $phpElName . ".'>';";
 371          }
 372  
 373          // If this element was maybe void, serializeCloseTag() has put its content within an if
 374          // block. We need to close that block
 375          if ($isVoid === 'maybe')
 376          {
 377              $php .= '}';
 378          }
 379  
 380          return $php;
 381      }
 382  
 383      /**
 384      * Serialize a <switch/> node that has a branch-key attribute
 385      *
 386      * @param  DOMElement $switch <switch/> node
 387      * @return string
 388      */
 389  	protected function serializeHash(DOMElement $switch)
 390      {
 391          $statements = [];
 392          foreach ($this->xpath->query('case[@branch-values]', $switch) as $case)
 393          {
 394              foreach (unserialize($case->getAttribute('branch-values')) as $value)
 395              {
 396                  $statements[$value] = $this->serializeChildren($case);
 397              }
 398          }
 399          if (!isset($case))
 400          {
 401              throw new RuntimeException;
 402          }
 403  
 404          $defaultCase = $this->xpath->query('case[not(@branch-values)]', $switch)->item(0);
 405          $defaultCode = ($defaultCase instanceof DOMElement) ? $this->serializeChildren($defaultCase) : '';
 406          $expr        = $this->convertXPath($switch->getAttribute('branch-key'));
 407  
 408          return SwitchStatement::generate($expr, $statements, $defaultCode);
 409      }
 410  
 411      /**
 412      * Serialize an <output/> node
 413      *
 414      * @param  DOMElement $output <output/> node
 415      * @return string
 416      */
 417  	protected function serializeOutput(DOMElement $output)
 418      {
 419          $context = $output->getAttribute('escape');
 420  
 421          $php = '$this->out.=';
 422          if ($output->getAttribute('type') === 'xpath')
 423          {
 424              $php .= $this->escapePHPOutput($this->convertXPath($output->textContent), $context);
 425          }
 426          else
 427          {
 428              $php .= var_export($this->escapeLiteral($output->textContent, $context), true);
 429          }
 430          $php .= ';';
 431  
 432          return $php;
 433      }
 434  
 435      /**
 436      * Serialize a <switch/> node
 437      *
 438      * @param  DOMElement $switch <switch/> node
 439      * @return string
 440      */
 441  	protected function serializeSwitch(DOMElement $switch)
 442      {
 443          // Use a specialized branch table if the minimum number of branches is reached
 444          if ($switch->hasAttribute('branch-key') && $this->hasMultipleCases($switch))
 445          {
 446              return $this->serializeHash($switch);
 447          }
 448  
 449          $php   = '';
 450          $if    = 'if';
 451          foreach ($this->xpath->query('case', $switch) as $case)
 452          {
 453              if ($case->hasAttribute('test'))
 454              {
 455                  $php .= $if . '(' . $this->convertCondition($case->getAttribute('test')) . ')';
 456              }
 457              else
 458              {
 459                  $php .= 'else';
 460              }
 461  
 462              $php .= '{' . $this->serializeChildren($case) . '}';
 463              $if   = 'elseif';
 464          }
 465  
 466          return $php;
 467      }
 468  }


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