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

Optimizer.php

Zuletzt modifiziert: 02.04.2025, 15:04 - Dateigröße: 5.97 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\TemplateParser;
009   
010  use DOMDocument;
011  use DOMElement;
012  use DOMNode;
013   
014  class Optimizer extends IRProcessor
015  {
016      /**
017      * Optimize an IR
018      *
019      * @param  DOMDocument $ir
020      * @return void
021      */
022      public function optimize(DOMDocument $ir)
023      {
024          $this->createXPath($ir);
025   
026          // Get a snapshot of current internal representation
027          $xml = $ir->saveXML();
028   
029          // Set a maximum number of loops to ward against infinite loops
030          $remainingLoops = 10;
031   
032          // From now on, keep looping until no further modifications are applied
033          do
034          {
035              $old = $xml;
036              $this->optimizeCloseTagElements();
037              $xml = $ir->saveXML();
038          }
039          while (--$remainingLoops > 0 && $xml !== $old);
040   
041          $this->removeCloseTagSiblings();
042          $this->removeContentFromVoidElements();
043          $this->mergeConsecutiveLiteralOutputElements();
044          $this->removeEmptyDefaultCases();
045      }
046   
047      /**
048      * Clone closeTag elements that follow a switch into said switch
049      *
050      * If there's a <closeTag/> right after a <switch/>, clone the <closeTag/> at the end of
051      * the every <case/> that does not end with a <closeTag/>
052      *
053      * @return void
054      */
055      protected function cloneCloseTagElementsIntoSwitch()
056      {
057          $query = '//switch[name(following-sibling::*[1]) = "closeTag"]';
058          foreach ($this->query($query) as $switch)
059          {
060              $closeTag = $switch->nextSibling;
061              foreach ($this->query('case', $switch) as $case)
062              {
063                  if (!$case->lastChild || $case->lastChild->nodeName !== 'closeTag')
064                  {
065                      $case->appendChild($closeTag->cloneNode());
066                  }
067              }
068          }
069      }
070   
071      /**
072      * Clone closeTag elements from the head of a switch's cases before said switch
073      *
074      * If there's a <closeTag/> at the beginning of every <case/>, clone it and insert it
075      * right before the <switch/> unless there's already one
076      *
077      * @return void
078      */
079      protected function cloneCloseTagElementsOutOfSwitch()
080      {
081          $query = '//switch[case/closeTag][not(case[name(*[1]) != "closeTag"])]';
082          foreach ($this->query($query) as $switch)
083          {
084              $case = $this->query('case/closeTag', $switch)->item(0);
085              $switch->parentNode->insertBefore($case->cloneNode(), $switch);
086          }
087      }
088   
089      /**
090      * Merge consecutive literal outputs
091      *
092      * @return void
093      */
094      protected function mergeConsecutiveLiteralOutputElements()
095      {
096          foreach ($this->query('//output[@type="literal"]') as $output)
097          {
098              $disableOutputEscaping = $output->getAttribute('disable-output-escaping');
099              while ($this->nextSiblingIsLiteralOutput($output, $disableOutputEscaping))
100              {
101                  $output->nodeValue = htmlspecialchars($output->nodeValue . $output->nextSibling->nodeValue, ENT_COMPAT);
102                  $output->parentNode->removeChild($output->nextSibling);
103              }
104          }
105      }
106   
107      /**
108      * Test whether the next sibling of an element is a literal output element with matching escaping
109      *
110      * @param  DOMElement $node
111      * @param  string     $disableOutputEscaping
112      * @return bool
113      */
114      protected function nextSiblingIsLiteralOutput(DOMElement $node, $disableOutputEscaping)
115      {
116          return isset($node->nextSibling) && $node->nextSibling->nodeName === 'output' && $node->nextSibling->getAttribute('type') === 'literal' && $node->nextSibling->getAttribute('disable-output-escaping') === $disableOutputEscaping;
117      }
118   
119      /**
120      * Optimize closeTags elements
121      *
122      * @return void
123      */
124      protected function optimizeCloseTagElements()
125      {
126          $this->cloneCloseTagElementsIntoSwitch();
127          $this->cloneCloseTagElementsOutOfSwitch();
128          $this->removeRedundantCloseTagElementsInSwitch();
129          $this->removeRedundantCloseTagElements();
130      }
131   
132      /**
133      * Remove redundant closeTag siblings after a switch
134      *
135      * If all branches of a switch have a closeTag we can remove any closeTag siblings of the switch
136      *
137      * @return void
138      */
139      protected function removeCloseTagSiblings()
140      {
141          $query = '//switch[not(case[not(closeTag)])]/following-sibling::closeTag';
142          $this->removeNodes($query);
143      }
144   
145      /**
146      * Remove content from void elements
147      *
148      * For each void element, we find whichever <closeTag/> elements close it and remove everything
149      * after
150      *
151      * @return void
152      */
153      protected function removeContentFromVoidElements()
154      {
155          foreach ($this->query('//element[@void="yes"]') as $element)
156          {
157              $id    = $element->getAttribute('id');
158              $query = './/closeTag[@id="' . $id . '"]/following-sibling::*';
159   
160              $this->removeNodes($query, $element);
161          }
162      }
163   
164      /**
165      * Remove empty default cases (no test and no descendants)
166      *
167      * @return void
168      */
169      protected function removeEmptyDefaultCases()
170      {
171          $query = '//case[not(@test)][not(*)][. = ""]';
172          $this->removeNodes($query);
173      }
174   
175      /**
176      * Remove all nodes that match given XPath query
177      *
178      * @param  string  $query
179      * @param  DOMNode $contextNode
180      * @return void
181      */
182      protected function removeNodes($query, DOMNode $contextNode = null)
183      {
184          foreach ($this->query($query, $contextNode) as $node)
185          {
186              if ($node->parentNode instanceof DOMElement)
187              {
188                  $node->parentNode->removeChild($node);
189              }
190          }
191      }
192   
193      /**
194      * Remove redundant closeTag elements from the tail of a switch's cases
195      *
196      * For each <closeTag/> remove duplicate <closeTag/> nodes that are either siblings or
197      * descendants of a sibling
198      *
199      * @return void
200      */
201      protected function removeRedundantCloseTagElements()
202      {
203          foreach ($this->query('//closeTag') as $closeTag)
204          {
205              $id    = $closeTag->getAttribute('id');
206              $query = 'following-sibling::*/descendant-or-self::closeTag[@id="' . $id . '"]';
207   
208              $this->removeNodes($query, $closeTag);
209          }
210      }
211   
212      /**
213      * Remove redundant closeTag elements from the tail of a switch's cases
214      *
215      * If there's a <closeTag/> right after a <switch/>, remove all <closeTag/> nodes at the
216      * end of every <case/>
217      *
218      * @return void
219      */
220      protected function removeRedundantCloseTagElementsInSwitch()
221      {
222          $query = '//switch[name(following-sibling::*[1]) = "closeTag"]';
223          foreach ($this->query($query) as $switch)
224          {
225              foreach ($this->query('case', $switch) as $case)
226              {
227                  while ($case->lastChild && $case->lastChild->nodeName === 'closeTag')
228                  {
229                      $case->removeChild($case->lastChild);
230                  }
231              }
232          }
233      }
234  }