Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

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

md_exporter.php

Zuletzt modifiziert: 09.10.2024, 12:51 - Dateigröße: 10.79 KiB


001  <?php
002  /**
003  *
004  * This file is part of the phpBB Forum Software package.
005  *
006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
007  * @license GNU General Public License, version 2 (GPL-2.0)
008  *
009  * For full copyright and license information, please see
010  * the docs/CREDITS.txt file.
011  *
012  */
013   
014  namespace phpbb\event;
015   
016  /**
017  * Crawls through a markdown file and grabs all events
018  */
019  class md_exporter
020  {
021      /** @var string Path where we look for files*/
022      protected $path;
023   
024      /** @var string phpBB Root Path */
025      protected $root_path;
026   
027      /** @var string */
028      protected $filter;
029   
030      /** @var string */
031      protected $current_event;
032   
033      /** @var array */
034      protected $events;
035   
036      /**
037      * @param string $phpbb_root_path
038      * @param mixed $extension    String 'vendor/ext' to filter, null for phpBB core
039      */
040      public function __construct($phpbb_root_path, $extension = null)
041      {
042          $this->root_path = $phpbb_root_path;
043          $this->path = $this->root_path;
044          if ($extension)
045          {
046              $this->path .= 'ext/' . $extension . '/';
047          }
048   
049          $this->events = array();
050          $this->events_by_file = array();
051          $this->filter = $this->current_event = '';
052      }
053   
054      /**
055      * Get the list of all events
056      *
057      * @return array        Array with events: name => details
058      */
059      public function get_events()
060      {
061          return $this->events;
062      }
063   
064      /**
065      * @param string $md_file    Relative from phpBB root
066      * @return int        Number of events found
067      * @throws \LogicException
068      */
069      public function crawl_phpbb_directory_adm($md_file)
070      {
071          $this->crawl_eventsmd($md_file, 'adm');
072   
073          $file_list = $this->get_recursive_file_list($this->path  . 'adm/style/');
074          foreach ($file_list as $file)
075          {
076              $file_name = 'adm/style/' . $file;
077              $this->validate_events_from_file($file_name, $this->crawl_file_for_events($file_name));
078          }
079   
080          return sizeof($this->events);
081      }
082   
083      /**
084      * @param string $md_file    Relative from phpBB root
085      * @return int        Number of events found
086      * @throws \LogicException
087      */
088      public function crawl_phpbb_directory_styles($md_file)
089      {
090          $this->crawl_eventsmd($md_file, 'styles');
091   
092          $styles = array('prosilver', 'subsilver2');
093          foreach ($styles as $style)
094          {
095              $file_list = $this->get_recursive_file_list(
096                  $this->path . 'styles/' . $style . '/template/'
097              );
098   
099              foreach ($file_list as $file)
100              {
101                  $file_name = 'styles/' . $style . '/template/' . $file;
102                  $this->validate_events_from_file($file_name, $this->crawl_file_for_events($file_name));
103              }
104          }
105   
106          return sizeof($this->events);
107      }
108   
109      /**
110      * @param string $md_file    Relative from phpBB root
111      * @param string $filter        Should be 'styles' or 'adm'
112      * @return int        Number of events found
113      * @throws \LogicException
114      */
115      public function crawl_eventsmd($md_file, $filter)
116      {
117          if (!file_exists($this->path . $md_file))
118          {
119              throw new \LogicException("The event docs file '{$md_file}' could not be found");
120          }
121   
122          $file_content = file_get_contents($this->path . $md_file);
123          $this->filter = $filter;
124   
125          $events = explode("\n\n", $file_content);
126          foreach ($events as $event)
127          {
128              // Last row of the file
129              if (strpos($event, "\n===\n") === false)
130              {
131                  continue;
132              }
133   
134              list($event_name, $details) = explode("\n===\n", $event, 2);
135              $this->validate_event_name($event_name);
136              $this->current_event = $event_name;
137   
138              if (isset($this->events[$this->current_event]))
139              {
140                  throw new \LogicException("The event '{$this->current_event}' is defined multiple times");
141              }
142   
143              if (($this->filter == 'adm' && strpos($this->current_event, 'acp_') !== 0)
144                  || ($this->filter == 'styles' && strpos($this->current_event, 'acp_') === 0))
145              {
146                  continue;
147              }
148   
149              list($file_details, $details) = explode("\n* Since: ", $details, 2);
150              list($since, $description) = explode("\n* Purpose: ", $details, 2);
151   
152              $files = $this->validate_file_list($file_details);
153              $since = $this->validate_since($since);
154   
155              $this->events[$event_name] = array(
156                  'event'            => $this->current_event,
157                  'files'            => $files,
158                  'since'            => $since,
159                  'description'    => $description,
160              );
161          }
162   
163          return sizeof($this->events);
164      }
165   
166      /**
167      * Format the php events as a wiki table
168      * @return string        Number of events found
169      */
170      public function export_events_for_wiki()
171      {
172          if ($this->filter === 'adm')
173          {
174              $wiki_page = '= ACP Template Events =' . "\n";
175              $wiki_page .= '{| class="zebra sortable" cellspacing="0" cellpadding="5"' . "\n";
176              $wiki_page .= '! Identifier !! Placement !! Added in Release !! Explanation' . "\n";
177          }
178          else
179          {
180              $wiki_page = '= Template Events =' . "\n";
181              $wiki_page .= '{| class="zebra sortable" cellspacing="0" cellpadding="5"' . "\n";
182              $wiki_page .= '! Identifier !! Prosilver Placement (If applicable) !! Subsilver Placement (If applicable) !! Added in Release !! Explanation' . "\n";
183          }
184   
185          foreach ($this->events as $event_name => $event)
186          {
187              $wiki_page .= "|- id=\"{$event_name}\"\n";
188              $wiki_page .= "| [[#{$event_name}|{$event_name}]] || ";
189   
190              if ($this->filter === 'adm')
191              {
192                  $wiki_page .= implode(', ', $event['files']['adm']);
193              }
194              else
195              {
196                  $wiki_page .= implode(', ', $event['files']['prosilver']) . ' || ' . implode(', ', $event['files']['subsilver2']);
197              }
198   
199              $wiki_page .= " || {$event['since']} || " . str_replace("\n", ' ', $event['description']) . "\n";
200          }
201          $wiki_page .= '|}' . "\n";
202   
203          return $wiki_page;
204      }
205   
206      /**
207      * Validates a template event name
208      *
209      * @param $event_name
210      * @return null
211      * @throws \LogicException
212      */
213      public function validate_event_name($event_name)
214      {
215          if (!preg_match('#^([a-z][a-z0-9]*(?:_[a-z][a-z0-9]*)+)$#', $event_name))
216          {
217              throw new \LogicException("Invalid event name '{$event_name}'");
218          }
219      }
220   
221      /**
222      * Validate "Since" Information
223      *
224      * @param string $since
225      * @return string
226      * @throws \LogicException
227      */
228      public function validate_since($since)
229      {
230          if (!preg_match('#^\d+\.\d+\.\d+(?:-(?:a|b|RC|pl)\d+)?$#', $since))
231          {
232              throw new \LogicException("Invalid since information found for event '{$this->current_event}'");
233          }
234   
235          return $since;
236      }
237   
238      /**
239      * Validate the files list
240      *
241      * @param string $file_details
242      * @return array
243      * @throws \LogicException
244      */
245      public function validate_file_list($file_details)
246      {
247          $files_list = array(
248              'prosilver'        => array(),
249              'subsilver2'    => array(),
250              'adm'            => array(),
251          );
252   
253          // Multi file list
254          if (strpos($file_details, "* Locations:\n    + ") === 0)
255          {
256              $file_details = substr($file_details, strlen("* Locations:\n    + "));
257              $files = explode("\n    + ", $file_details);
258              foreach ($files as $file)
259              {
260                  if (!file_exists($this->path . $file) || substr($file, -5) !== '.html')
261                  {
262                      throw new \LogicException("Invalid file '{$file}' not found for event '{$this->current_event}'", 1);
263                  }
264   
265                  if (($this->filter !== 'adm') && strpos($file, 'styles/prosilver/template/') === 0)
266                  {
267                      $files_list['prosilver'][] = substr($file, strlen('styles/prosilver/template/'));
268                  }
269                  else if (($this->filter !== 'adm') && strpos($file, 'styles/subsilver2/template/') === 0)
270                  {
271                      $files_list['subsilver2'][] = substr($file, strlen('styles/subsilver2/template/'));
272                  }
273                  else if (($this->filter === 'adm') && strpos($file, 'adm/style/') === 0)
274                  {
275                      $files_list['adm'][] = substr($file, strlen('adm/style/'));
276                  }
277                  else
278                  {
279                      throw new \LogicException("Invalid file '{$file}' not found for event '{$this->current_event}'", 2);
280                  }
281   
282                  $this->events_by_file[$file][] = $this->current_event;
283              }
284          }
285          else if ($this->filter == 'adm')
286          {
287              $file = substr($file_details, strlen('* Location: '));
288              if (!file_exists($this->path . $file) || substr($file, -5) !== '.html')
289              {
290                  throw new \LogicException("Invalid file '{$file}' not found for event '{$this->current_event}'", 1);
291              }
292   
293              $files_list['adm'][] =  substr($file, strlen('adm/style/'));
294   
295              $this->events_by_file[$file][] = $this->current_event;
296          }
297          else
298          {
299              throw new \LogicException("Invalid file list found for event '{$this->current_event}'", 2);
300          }
301   
302          return $files_list;
303      }
304   
305      /**
306      * Get all template events in a template file
307      *
308      * @param string $file
309      * @return array
310      * @throws \LogicException
311      */
312      public function crawl_file_for_events($file)
313      {
314          if (!file_exists($this->path . $file))
315          {
316              throw new \LogicException("File '{$file}' does not exist", 1);
317          }
318   
319          $event_list = array();
320          $file_content = file_get_contents($this->path . $file);
321   
322          $events = explode('<!-- EVENT ', $file_content);
323          // Remove the code before the first event
324          array_shift($events);
325          foreach ($events as $event)
326          {
327              $event = explode(' -->', $event, 2);
328              $event_list[] = array_shift($event);
329          }
330   
331          return $event_list;
332      }
333   
334      /**
335      * Validates whether all events from $file are in the md file and vice-versa
336      *
337      * @param string $file
338      * @param array $events
339      * @return true
340      * @throws \LogicException
341      */
342      public function validate_events_from_file($file, array $events)
343      {
344          if (empty($this->events_by_file[$file]) && empty($events))
345          {
346              return true;
347          }
348          else if (empty($this->events_by_file[$file]))
349          {
350              $event_list = implode("', '", $events);
351              throw new \LogicException("File '{$file}' should not contain events, but contains: "
352                  . "'{$event_list}'", 1);
353          }
354          else if (empty($events))
355          {
356              $event_list = implode("', '", $this->events_by_file[$file]);
357              throw new \LogicException("File '{$file}' contains no events, but should contain: "
358                  . "'{$event_list}'", 1);
359          }
360   
361          $missing_events_from_file = array();
362          foreach ($this->events_by_file[$file] as $event)
363          {
364              if (!in_array($event, $events))
365              {
366                  $missing_events_from_file[] = $event;
367              }
368          }
369   
370          if (!empty($missing_events_from_file))
371          {
372              $event_list = implode("', '", $missing_events_from_file);
373              throw new \LogicException("File '{$file}' does not contain events: '{$event_list}'", 2);
374          }
375   
376          $missing_events_from_md = array();
377          foreach ($events as $event)
378          {
379              if (!in_array($event, $this->events_by_file[$file]))
380              {
381                  $missing_events_from_md[] = $event;
382              }
383          }
384   
385          if (!empty($missing_events_from_md))
386          {
387              $event_list = implode("', '", $missing_events_from_md);
388              throw new \LogicException("File '{$file}' contains additional events: '{$event_list}'", 3);
389          }
390   
391          return true;
392      }
393   
394      /**
395      * Returns a list of files in $dir
396      *
397      * Works recursive with any depth
398      *
399      * @param    string    $dir    Directory to go through
400      * @return    array    List of files (including directories)
401      */
402      public function get_recursive_file_list($dir)
403      {
404          try
405          {
406              $iterator = new \RecursiveIteratorIterator(
407                  new \phpbb\recursive_dot_prefix_filter_iterator(
408                      new \RecursiveDirectoryIterator(
409                          $dir,
410                          \FilesystemIterator::SKIP_DOTS
411                      )
412                  ),
413                  \RecursiveIteratorIterator::SELF_FIRST
414              );
415          }
416          catch (\Exception $e)
417          {
418              return array();
419          }
420   
421          $files = array();
422          foreach ($iterator as $file_info)
423          {
424              /** @var \RecursiveDirectoryIterator $file_info */
425              if ($file_info->isDir())
426              {
427                  continue;
428              }
429   
430              $relative_path = $iterator->getInnerIterator()->getSubPathname();
431   
432              if (substr($relative_path, -5) == '.html')
433              {
434                  $files[] = str_replace(DIRECTORY_SEPARATOR, '/', $relative_path);
435              }
436          }
437   
438          return $files;
439      }
440  }
441