[ Index ]

PHP Cross Reference of phpBB-3.1.12-deutsch

title

Body

[close]

/phpbb/event/ -> md_exporter.php (source)

   1  <?php
   2  /**
   3  *
   4  * This file is part of the phpBB Forum Software package.
   5  *
   6  * @copyright (c) phpBB Limited <https://www.phpbb.com>
   7  * @license GNU General Public License, version 2 (GPL-2.0)
   8  *
   9  * For full copyright and license information, please see
  10  * the docs/CREDITS.txt file.
  11  *
  12  */
  13  
  14  namespace phpbb\event;
  15  
  16  /**
  17  * Crawls through a markdown file and grabs all events
  18  */
  19  class md_exporter
  20  {
  21      /** @var string Path where we look for files*/
  22      protected $path;
  23  
  24      /** @var string phpBB Root Path */
  25      protected $root_path;
  26  
  27      /** @var string The minimum version for the events to return */
  28      protected $min_version;
  29  
  30      /** @var string The maximum version for the events to return */
  31      protected $max_version;
  32  
  33      /** @var string */
  34      protected $filter;
  35  
  36      /** @var string */
  37      protected $current_event;
  38  
  39      /** @var array */
  40      protected $events;
  41  
  42      /**
  43      * @param string $phpbb_root_path
  44      * @param mixed $extension    String 'vendor/ext' to filter, null for phpBB core
  45      * @param string $min_version
  46      * @param string $max_version
  47      */
  48  	public function __construct($phpbb_root_path, $extension = null, $min_version = null, $max_version = null)
  49      {
  50          $this->root_path = $phpbb_root_path;
  51          $this->path = $this->root_path;
  52          if ($extension)
  53          {
  54              $this->path .= 'ext/' . $extension . '/';
  55          }
  56  
  57          $this->events = array();
  58          $this->events_by_file = array();
  59          $this->filter = $this->current_event = '';
  60          $this->min_version = $min_version;
  61          $this->max_version = $max_version;
  62      }
  63  
  64      /**
  65      * Get the list of all events
  66      *
  67      * @return array        Array with events: name => details
  68      */
  69  	public function get_events()
  70      {
  71          return $this->events;
  72      }
  73  
  74      /**
  75      * @param string $md_file    Relative from phpBB root
  76      * @return int        Number of events found
  77      * @throws \LogicException
  78      */
  79  	public function crawl_phpbb_directory_adm($md_file)
  80      {
  81          $this->crawl_eventsmd($md_file, 'adm');
  82  
  83          $file_list = $this->get_recursive_file_list($this->path  . 'adm/style/');
  84          foreach ($file_list as $file)
  85          {
  86              $file_name = 'adm/style/' . $file;
  87              $this->validate_events_from_file($file_name, $this->crawl_file_for_events($file_name));
  88          }
  89  
  90          return sizeof($this->events);
  91      }
  92  
  93      /**
  94      * @param string $md_file    Relative from phpBB root
  95      * @return int        Number of events found
  96      * @throws \LogicException
  97      */
  98  	public function crawl_phpbb_directory_styles($md_file)
  99      {
 100          $this->crawl_eventsmd($md_file, 'styles');
 101  
 102          $styles = array('prosilver', 'subsilver2');
 103          foreach ($styles as $style)
 104          {
 105              $file_list = $this->get_recursive_file_list(
 106                  $this->path . 'styles/' . $style . '/template/'
 107              );
 108  
 109              foreach ($file_list as $file)
 110              {
 111                  $file_name = 'styles/' . $style . '/template/' . $file;
 112                  $this->validate_events_from_file($file_name, $this->crawl_file_for_events($file_name));
 113              }
 114          }
 115  
 116          return sizeof($this->events);
 117      }
 118  
 119      /**
 120      * @param string $md_file    Relative from phpBB root
 121      * @param string $filter        Should be 'styles' or 'adm'
 122      * @return int        Number of events found
 123      * @throws \LogicException
 124      */
 125  	public function crawl_eventsmd($md_file, $filter)
 126      {
 127          if (!file_exists($this->path . $md_file))
 128          {
 129              throw new \LogicException("The event docs file '{$md_file}' could not be found");
 130          }
 131  
 132          $file_content = file_get_contents($this->path . $md_file);
 133          $this->filter = $filter;
 134  
 135          $events = explode("\n\n", $file_content);
 136          foreach ($events as $event)
 137          {
 138              // Last row of the file
 139              if (strpos($event, "\n===\n") === false)
 140              {
 141                  continue;
 142              }
 143  
 144              list($event_name, $details) = explode("\n===\n", $event, 2);
 145              $this->validate_event_name($event_name);
 146              $this->current_event = $event_name;
 147  
 148              if (isset($this->events[$this->current_event]))
 149              {
 150                  throw new \LogicException("The event '{$this->current_event}' is defined multiple times");
 151              }
 152  
 153              if (($this->filter == 'adm' && strpos($this->current_event, 'acp_') !== 0)
 154                  || ($this->filter == 'styles' && strpos($this->current_event, 'acp_') === 0))
 155              {
 156                  continue;
 157              }
 158  
 159              list($file_details, $details) = explode("\n* Since: ", $details, 2);
 160  
 161              $changed_versions = array();
 162              if (strpos($details, "\n* Changed: ") !== false)
 163              {
 164                  list($since, $details) = explode("\n* Changed: ", $details, 2);
 165                  while (strpos($details, "\n* Changed: ") !== false)
 166                  {
 167                      list($changed, $details) = explode("\n* Changed: ", $details, 2);
 168                      $changed_versions[] = $changed;
 169                  }
 170                  list($changed, $description) = explode("\n* Purpose: ", $details, 2);
 171                  $changed_versions[] = $changed;
 172              }
 173              else
 174              {
 175                  list($since, $description) = explode("\n* Purpose: ", $details, 2);
 176                  $changed_versions = array();
 177              }
 178  
 179              $files = $this->validate_file_list($file_details);
 180              $since = $this->validate_since($since);
 181              $changes = array();
 182              foreach ($changed_versions as $changed)
 183              {
 184                  list($changed_version, $changed_description) = $this->validate_changed($changed);
 185  
 186                  if (isset($changes[$changed_version]))
 187                  {
 188                      throw new \LogicException("Duplicate change information found for event '{$this->current_event}'");
 189                  }
 190  
 191                  $changes[$changed_version] = $changed_description;
 192              }
 193              $description = trim($description, "\n") . "\n";
 194  
 195              if (!$this->version_is_filtered($since))
 196              {
 197                  $is_filtered = false;
 198                  foreach ($changes as $version => $null)
 199                  {
 200                      if ($this->version_is_filtered($version))
 201                      {
 202                          $is_filtered = true;
 203                          break;
 204                      }
 205                  }
 206  
 207                  if (!$is_filtered)
 208                  {
 209                      continue;
 210                  }
 211              }
 212  
 213              $this->events[$event_name] = array(
 214                  'event'            => $this->current_event,
 215                  'files'            => $files,
 216                  'since'            => $since,
 217                  'changed'        => $changes,
 218                  'description'    => $description,
 219              );
 220          }
 221  
 222          return sizeof($this->events);
 223      }
 224  
 225      /**
 226       * The version to check
 227       *
 228       * @param string $version
 229       * @return bool
 230       */
 231  	protected function version_is_filtered($version)
 232      {
 233          return (!$this->min_version || phpbb_version_compare($this->min_version, $version, '<='))
 234          && (!$this->max_version || phpbb_version_compare($this->max_version, $version, '>='));
 235      }
 236  
 237      /**
 238      * Format the php events as a wiki table
 239      *
 240      * @param string $action
 241      * @return string        Number of events found
 242      */
 243  	public function export_events_for_wiki($action = '')
 244      {
 245          if ($this->filter === 'adm')
 246          {
 247              if ($action === 'diff')
 248              {
 249                  $wiki_page = '=== ACP Template Events ===' . "\n";
 250              }
 251              else
 252              {
 253                  $wiki_page = '= ACP Template Events =' . "\n";
 254              }
 255              $wiki_page .= '{| class="zebra sortable" cellspacing="0" cellpadding="5"' . "\n";
 256              $wiki_page .= '! Identifier !! Placement !! Added in Release !! Explanation' . "\n";
 257          }
 258          else
 259          {
 260              if ($action === 'diff')
 261              {
 262                  $wiki_page = '=== Template Events ===' . "\n";
 263              }
 264              else
 265              {
 266                  $wiki_page = '= Template Events =' . "\n";
 267              }
 268              $wiki_page .= '{| class="zebra sortable" cellspacing="0" cellpadding="5"' . "\n";
 269              $wiki_page .= '! Identifier !! Prosilver Placement (If applicable) !! Subsilver Placement (If applicable) !! Added in Release !! Explanation' . "\n";
 270          }
 271  
 272          foreach ($this->events as $event_name => $event)
 273          {
 274              $wiki_page .= "|- id=\"{$event_name}\"\n";
 275              $wiki_page .= "| [[#{$event_name}|{$event_name}]] || ";
 276  
 277              if ($this->filter === 'adm')
 278              {
 279                  $wiki_page .= implode(', ', $event['files']['adm']);
 280              }
 281              else
 282              {
 283                  $wiki_page .= implode(', ', $event['files']['prosilver']) . ' || ' . implode(', ', $event['files']['subsilver2']);
 284              }
 285  
 286              $wiki_page .= " || {$event['since']} || " . str_replace("\n", ' ', $event['description']) . "\n";
 287          }
 288          $wiki_page .= '|}' . "\n";
 289  
 290          return $wiki_page;
 291      }
 292  
 293      /**
 294      * Validates a template event name
 295      *
 296      * @param $event_name
 297      * @return null
 298      * @throws \LogicException
 299      */
 300  	public function validate_event_name($event_name)
 301      {
 302          if (!preg_match('#^([a-z][a-z0-9]*(?:_[a-z][a-z0-9]*)+)$#', $event_name))
 303          {
 304              throw new \LogicException("Invalid event name '{$event_name}'");
 305          }
 306      }
 307  
 308      /**
 309      * Validate "Since" Information
 310      *
 311      * @param string $since
 312      * @return string
 313      * @throws \LogicException
 314      */
 315  	public function validate_since($since)
 316      {
 317          if (!$this->validate_version($since))
 318          {
 319              throw new \LogicException("Invalid since information found for event '{$this->current_event}'");
 320          }
 321  
 322          return $since;
 323      }
 324  
 325      /**
 326      * Validate "Changed" Information
 327      *
 328      * @param string $changed
 329      * @return string
 330      * @throws \LogicException
 331      */
 332  	public function validate_changed($changed)
 333      {
 334          if (strpos($changed, ' ') !== false)
 335          {
 336              list($version, $description) = explode(' ', $changed, 2);
 337          }
 338          else
 339          {
 340              $version = $changed;
 341              $description = '';
 342          }
 343  
 344          if (!$this->validate_version($version))
 345          {
 346              throw new \LogicException("Invalid changed information found for event '{$this->current_event}'");
 347          }
 348  
 349          return array($version, $description);
 350      }
 351  
 352      /**
 353      * Validate "version" Information
 354      *
 355      * @param string $version
 356      * @return bool True if valid, false otherwise
 357      */
 358  	public function validate_version($version)
 359      {
 360          return preg_match('#^\d+\.\d+\.\d+(?:-(?:a|b|RC|pl)\d+)?$#', $version);
 361      }
 362  
 363      /**
 364      * Validate the files list
 365      *
 366      * @param string $file_details
 367      * @return array
 368      * @throws \LogicException
 369      */
 370  	public function validate_file_list($file_details)
 371      {
 372          $files_list = array(
 373              'prosilver'        => array(),
 374              'subsilver2'    => array(),
 375              'adm'            => array(),
 376          );
 377  
 378          // Multi file list
 379          if (strpos($file_details, "* Locations:\n    + ") === 0)
 380          {
 381              $file_details = substr($file_details, strlen("* Locations:\n    + "));
 382              $files = explode("\n    + ", $file_details);
 383              foreach ($files as $file)
 384              {
 385                  if (!file_exists($this->path . $file) || substr($file, -5) !== '.html')
 386                  {
 387                      throw new \LogicException("Invalid file '{$file}' not found for event '{$this->current_event}'", 1);
 388                  }
 389  
 390                  if (($this->filter !== 'adm') && strpos($file, 'styles/prosilver/template/') === 0)
 391                  {
 392                      $files_list['prosilver'][] = substr($file, strlen('styles/prosilver/template/'));
 393                  }
 394                  else if (($this->filter !== 'adm') && strpos($file, 'styles/subsilver2/template/') === 0)
 395                  {
 396                      $files_list['subsilver2'][] = substr($file, strlen('styles/subsilver2/template/'));
 397                  }
 398                  else if (($this->filter === 'adm') && strpos($file, 'adm/style/') === 0)
 399                  {
 400                      $files_list['adm'][] = substr($file, strlen('adm/style/'));
 401                  }
 402                  else
 403                  {
 404                      throw new \LogicException("Invalid file '{$file}' not found for event '{$this->current_event}'", 2);
 405                  }
 406  
 407                  $this->events_by_file[$file][] = $this->current_event;
 408              }
 409          }
 410          else if ($this->filter == 'adm')
 411          {
 412              $file = substr($file_details, strlen('* Location: '));
 413              if (!file_exists($this->path . $file) || substr($file, -5) !== '.html')
 414              {
 415                  throw new \LogicException("Invalid file '{$file}' not found for event '{$this->current_event}'", 1);
 416              }
 417  
 418              $files_list['adm'][] =  substr($file, strlen('adm/style/'));
 419  
 420              $this->events_by_file[$file][] = $this->current_event;
 421          }
 422          else
 423          {
 424              throw new \LogicException("Invalid file list found for event '{$this->current_event}'", 2);
 425          }
 426  
 427          return $files_list;
 428      }
 429  
 430      /**
 431      * Get all template events in a template file
 432      *
 433      * @param string $file
 434      * @return array
 435      * @throws \LogicException
 436      */
 437  	public function crawl_file_for_events($file)
 438      {
 439          if (!file_exists($this->path . $file))
 440          {
 441              throw new \LogicException("File '{$file}' does not exist", 1);
 442          }
 443  
 444          $event_list = array();
 445          $file_content = file_get_contents($this->path . $file);
 446  
 447          $events = explode('<!-- EVENT ', $file_content);
 448          // Remove the code before the first event
 449          array_shift($events);
 450          foreach ($events as $event)
 451          {
 452              $event = explode(' -->', $event, 2);
 453              $event_list[] = array_shift($event);
 454          }
 455  
 456          return $event_list;
 457      }
 458  
 459      /**
 460      * Validates whether all events from $file are in the md file and vice-versa
 461      *
 462      * @param string $file
 463      * @param array $events
 464      * @return true
 465      * @throws \LogicException
 466      */
 467  	public function validate_events_from_file($file, array $events)
 468      {
 469          if (empty($this->events_by_file[$file]) && empty($events))
 470          {
 471              return true;
 472          }
 473          else if (empty($this->events_by_file[$file]))
 474          {
 475              $event_list = implode("', '", $events);
 476              throw new \LogicException("File '{$file}' should not contain events, but contains: "
 477                  . "'{$event_list}'", 1);
 478          }
 479          else if (empty($events))
 480          {
 481              $event_list = implode("', '", $this->events_by_file[$file]);
 482              throw new \LogicException("File '{$file}' contains no events, but should contain: "
 483                  . "'{$event_list}'", 1);
 484          }
 485  
 486          $missing_events_from_file = array();
 487          foreach ($this->events_by_file[$file] as $event)
 488          {
 489              if (!in_array($event, $events))
 490              {
 491                  $missing_events_from_file[] = $event;
 492              }
 493          }
 494  
 495          if (!empty($missing_events_from_file))
 496          {
 497              $event_list = implode("', '", $missing_events_from_file);
 498              throw new \LogicException("File '{$file}' does not contain events: '{$event_list}'", 2);
 499          }
 500  
 501          $missing_events_from_md = array();
 502          foreach ($events as $event)
 503          {
 504              if (!in_array($event, $this->events_by_file[$file]))
 505              {
 506                  $missing_events_from_md[] = $event;
 507              }
 508          }
 509  
 510          if (!empty($missing_events_from_md))
 511          {
 512              $event_list = implode("', '", $missing_events_from_md);
 513              throw new \LogicException("File '{$file}' contains additional events: '{$event_list}'", 3);
 514          }
 515  
 516          return true;
 517      }
 518  
 519      /**
 520      * Returns a list of files in $dir
 521      *
 522      * Works recursive with any depth
 523      *
 524      * @param    string    $dir    Directory to go through
 525      * @return    array    List of files (including directories)
 526      */
 527  	public function get_recursive_file_list($dir)
 528      {
 529          try
 530          {
 531              $iterator = new \RecursiveIteratorIterator(
 532                  new \phpbb\recursive_dot_prefix_filter_iterator(
 533                      new \RecursiveDirectoryIterator(
 534                          $dir,
 535                          \FilesystemIterator::SKIP_DOTS
 536                      )
 537                  ),
 538                  \RecursiveIteratorIterator::SELF_FIRST
 539              );
 540          }
 541          catch (\Exception $e)
 542          {
 543              return array();
 544          }
 545  
 546          $files = array();
 547          foreach ($iterator as $file_info)
 548          {
 549              /** @var \RecursiveDirectoryIterator $file_info */
 550              if ($file_info->isDir())
 551              {
 552                  continue;
 553              }
 554  
 555              $relative_path = $iterator->getInnerIterator()->getSubPathname();
 556  
 557              if (substr($relative_path, -5) == '.html')
 558              {
 559                  $files[] = str_replace(DIRECTORY_SEPARATOR, '/', $relative_path);
 560              }
 561          }
 562  
 563          return $files;
 564      }
 565  }


Generated: Thu Jan 11 00:25:41 2018 Cross-referenced by PHPXref 0.7.1