diff --git a/phpBB/develop/export_events_for_rst.php b/phpBB/develop/export_events_for_rst.php new file mode 100644 index 0000000000..d8cef7bf9f --- /dev/null +++ b/phpBB/develop/export_events_for_rst.php @@ -0,0 +1,140 @@ + +* @license GNU General Public License, version 2 (GPL-2.0) +* +* For full copyright and license information, please see +* the docs/CREDITS.txt file. +* +*/ + +if (php_sapi_name() != 'cli') +{ + die("This program must be run from the command line.\n"); +} + +$phpEx = substr(strrchr(__FILE__, '.'), 1); +$phpbb_root_path = __DIR__ . '/../'; +define('IN_PHPBB', true); + +function usage() +{ + echo "Usage: export_events_for_rst.php COMMAND [VERSION] [EXTENSION]\n"; + echo "\n"; + echo "COMMAND:\n"; + echo " all:\n"; + echo " Generate the complete rst for the Event List\n"; + echo "\n"; + echo " diff:\n"; + echo " Generate the Event Diff for the release highlights\n"; + echo "\n"; + echo " php:\n"; + echo " Generate the PHP event section of Event_List\n"; + echo "\n"; + echo " adm:\n"; + echo " Generate the ACP Template event section of Event_List\n"; + echo "\n"; + echo " styles:\n"; + echo " Generate the Styles Template event section of Event_List\n"; + echo "\n"; + echo "VERSION (diff only):\n"; + echo " Filter events (minimum version)\n"; + echo "\n"; + echo "EXTENSION (Optional):\n"; + echo " If not given, only core events will be exported.\n"; + echo " Otherwise only events from the extension will be exported.\n"; + echo "\n"; + exit(2); +} + +function validate_argument_count($arguments, $count) +{ + if ($arguments <= $count) + { + usage(); + } +} + +validate_argument_count($argc, 1); + +$action = $argv[1]; +$extension = isset($argv[2]) ? $argv[2] : null; +$min_version = null; +require __DIR__ . '/../phpbb/event/php_exporter.' . $phpEx; +require __DIR__ . '/../phpbb/event/md_exporter.' . $phpEx; +require __DIR__ . '/../phpbb/event/rst_exporter.' . $phpEx; +require __DIR__ . '/../includes/functions.' . $phpEx; +require __DIR__ . '/../phpbb/event/recursive_event_filter_iterator.' . $phpEx; +require __DIR__ . '/../phpbb/recursive_dot_prefix_filter_iterator.' . $phpEx; + +switch ($action) +{ + + case 'diff': + echo '== Event changes ==' . "\n"; + echo "Event changes\n"; + echo "=============\n\n"; + $min_version = $extension; + $extension = isset($argv[3]) ? $argv[3] : null; + + case 'all': + if ($action === 'all') + { + echo "==========================\n"; + echo "Events List\n"; + echo "==========================\n\n"; + } + + + case 'php': + $exporter = new \phpbb\event\php_exporter($phpbb_root_path, $extension, $min_version); + $exporter->crawl_phpbb_directory_php(); + echo $exporter->export_events_for_rst($action); + + if ($action === 'php') + { + break; + } + echo "\n\n"; + // no break; + + case 'styles': + $exporter = new \phpbb\event\md_exporter($phpbb_root_path, $extension, $min_version); + if ($min_version && $action === 'diff') + { + $exporter->crawl_eventsmd('docs/events.md', 'styles'); + } + else + { + $exporter->crawl_phpbb_directory_styles('docs/events.md'); + } + echo $exporter->export_events_for_rst($action); + + if ($action === 'styles') + { + break; + } + echo "\n\n"; + // no break; + + case 'adm': + $exporter = new \phpbb\event\md_exporter($phpbb_root_path, $extension, $min_version); + if ($min_version && $action === 'diff') + { + $exporter->crawl_eventsmd('docs/events.md', 'adm'); + } + else + { + $exporter->crawl_phpbb_directory_adm('docs/events.md'); + } + echo $exporter->export_events_for_rst($action); + + echo "\n"; + break; + + default: + usage(); +} diff --git a/phpBB/phpbb/event/md_exporter.php b/phpBB/phpbb/event/md_exporter.php index e2d3458ae3..6d3685c7b7 100644 --- a/phpBB/phpbb/event/md_exporter.php +++ b/phpBB/phpbb/event/md_exporter.php @@ -246,10 +246,11 @@ class md_exporter } /** - * Format the php events as a wiki table + * Format the md events as a wiki table * * @param string $action - * @return string Number of events found + * @return string Number of events found * @deprecated since 3.2 + * @deprecated 3.3.5-RC1 (To be removed: 4.0.0-a1) */ public function export_events_for_wiki($action = '') { @@ -301,6 +302,71 @@ class md_exporter return $wiki_page; } + /** + * Format the md events as a rst table + * + * @param string $action + * @return string Number of events found + */ + public function export_events_for_rst(string $action = ''): string + { + $rst_exporter = new rst_exporter(); + + if ($this->filter === 'adm') + { + if ($action === 'diff') + { + $rst_exporter->add_section_header('h3', 'ACP Template Events'); + } + else + { + $rst_exporter->add_section_header('h2', 'ACP Template Events'); + } + + $rst_exporter->set_columns([ + 'event' => 'Identifier', + 'files' => 'Placement', + 'since' => 'Added in Release', + 'description' => 'Explanation', + ]); + } + else + { + if ($action === 'diff') + { + $rst_exporter->add_section_header('h3', 'Template Events'); + } + else + { + $rst_exporter->add_section_header('h2', 'Template Events'); + } + + $rst_exporter->set_columns([ + 'event' => 'Identifier', + 'files' => 'Prosilver Placement (If applicable)', + 'since' => 'Added in Release', + 'description' => 'Explanation', + ]); + } + + $events = []; + foreach ($this->events as $event_name => $event) + { + $files = $this->filter === 'adm' ? implode(', ', $event['files']['adm']) : implode(', ', $event['files']['prosilver']); + + $events[] = [ + 'event' => $event_name, + 'files' => $files, + 'since' => $event['since'], + 'description' => str_replace("\n", '
', rtrim($event['description'])), + ]; + } + + $rst_exporter->generate_events_table($events); + + return $rst_exporter->get_rst_output(); + } + /** * Validates a template event name * diff --git a/phpBB/phpbb/event/php_exporter.php b/phpBB/phpbb/event/php_exporter.php index a68618d434..5917cbaf98 100644 --- a/phpBB/phpbb/event/php_exporter.php +++ b/phpBB/phpbb/event/php_exporter.php @@ -161,6 +161,7 @@ class php_exporter * * @param string $action * @return string + * @deprecated 3.3.5-RC1 (To be removed: 4.0.0-a1) */ public function export_events_for_wiki($action = '') { @@ -184,6 +185,28 @@ class php_exporter return $wiki_page; } + /** + * Format the PHP events as a rst table + * + * @param string $action + * @return string + */ + public function export_events_for_rst(string $action = ''): string + { + $rst_exporter = new rst_exporter(); + $rst_exporter->add_section_header($action === 'diff' ? 'h3' : 'h2', 'PHP Events'); + $rst_exporter->set_columns([ + 'event' => 'Identifier', + 'file' => 'Placement', + 'arguments' => 'Arguments', + 'since' => 'Added in Release', + 'description' => 'Explanation', + ]); + $rst_exporter->generate_events_table($this->events); + + return $rst_exporter->get_rst_output(); + } + /** * @param string $file * @return int Number of events found in this file @@ -291,24 +314,32 @@ class php_exporter array_pop($description_lines); } - $description = trim(implode('
', $description_lines)); + $description = trim(implode('
', $description_lines)); + sort($arguments); if (isset($this->events[$this->current_event])) { - throw new \LogicException("The event '{$this->current_event}' from file " - . "'{$this->current_file}:{$event_line_num}' already exists in file " - . "'{$this->events[$this->current_event]['file']}'", 10); - } + if ($this->events[$this->current_event]['arguments'] != $arguments || + $this->events[$this->current_event]['since'] != $since) + { + throw new \LogicException("The event '{$this->current_event}' from file " + . "'{$this->current_file}:{$event_line_num}' already exists in file " + . "'{$this->events[$this->current_event]['file']}'", 10); + } - sort($arguments); - $this->events[$this->current_event] = array( - 'event' => $this->current_event, - 'file' => $this->current_file, - 'arguments' => $arguments, - 'since' => $since, - 'description' => $description, - ); - $num_events_found++; + $this->events[$this->current_event]['file'] .= '
' . $this->current_file; + } + else + { + $this->events[$this->current_event] = array( + 'event' => $this->current_event, + 'file' => $this->current_file, + 'arguments' => $arguments, + 'since' => $since, + 'description' => $description, + ); + $num_events_found++; + } } } } diff --git a/phpBB/phpbb/event/rst_exporter.php b/phpBB/phpbb/event/rst_exporter.php new file mode 100644 index 0000000000..90a79e932d --- /dev/null +++ b/phpBB/phpbb/event/rst_exporter.php @@ -0,0 +1,184 @@ + + * @license GNU General Public License, version 2 (GPL-2.0) + * + * For full copyright and license information, please see + * the docs/CREDITS.txt file. + * + */ + +namespace phpbb\event; + +class rst_exporter +{ + /** @var array Column keys */ + private $columns = []; + + /** @var array Column headers map */ + private $column_headers = []; + + /** @var array Maximum lengths of columns */ + private $max_lengths = []; + + /** @var string rst data */ + private $rst_data = ''; + + /** + * Set columns with array where key is column name and value is title of column in table + * + * @param array $column_data + */ + public function set_columns(array $column_data): void + { + foreach ($column_data as $column_key => $column_header) + { + $this->columns[] = $column_key; + $this->column_headers[$column_key] = $column_header; + } + } + + /** + * Add header to rst page + * + * @param string $type Type of header; allowed are h2, h3, h4 corresponding to HTML + * @param string $header_text Text of header + */ + public function add_section_header(string $type, string $header_text): void + { + $this->rst_data .= $header_text . "\n"; + + switch ($type) + { + case 'h2': + $header_character = '='; + break; + + default: + case 'h3': + $header_character = '-'; + break; + + case 'h4': + $header_character = '~'; + break; + } + + $this->rst_data .= str_repeat($header_character, strlen($header_text)) . "\n\n"; + } + + /** + * Fill table with event data + * + * @param array $event_data + */ + public function generate_events_table(array $event_data): void + { + $this->rst_data .= ".. table::\n"; + $this->rst_data .= " :class: events-list\n\n"; + + $this->set_max_lengths($event_data); + + // Create table header + $this->rst_data .= $this->get_separator_line(); + $this->rst_data .= " |"; + foreach ($this->columns as $column) + { + $this->rst_data .= $this->get_column($column, $this->column_headers[$column]); + } + + $this->rst_data .= "\n" . $this->get_separator_line('='); + + foreach ($event_data as $event) + { + $event_data = []; + $max_column_rows = 1; + foreach ($event as $key => $value) + { + $column_rows = !is_array($value) ? substr_count($value, '
') + 1 : 1; + $max_column_rows = max($max_column_rows, $column_rows); + $event_data[$key] = $column_rows > 1 ? explode('
', $value) : [is_array($value) ? implode(', ', $value) : $value]; + } + + for ($i = 0; $i < $max_column_rows; $i++) + { + $this->rst_data .= ' |'; + + foreach ($this->columns as $column) + { + $this->rst_data .= $this->get_column($column, $event_data[$column][$i] ?? ''); + } + $this->rst_data .= "\n"; + } + $this->rst_data .= $this->get_separator_line(); + } + } + + /** + * Get rst output + * + * @return string + */ + public function get_rst_output(): string + { + return $this->rst_data; + } + + /** + * Set maximum lengths array + * + * @param array $event_data + */ + private function set_max_lengths(array $event_data): void + { + $this->max_lengths = []; + + foreach ($this->columns as $column) + { + $this->max_lengths[$column] = strlen($this->column_headers[$column]); + } + + foreach ($event_data as $event) + { + foreach ($this->columns as $column) + { + $event_column = is_array($event[$column]) ? implode(', ', $event[$column]) : $event[$column]; + $this->max_lengths[$column] = max($this->max_lengths[$column], strlen($event_column)); + } + } + } + + /** + * Get separator line + * + * @param string $separator_character + * @return string + */ + private function get_separator_line(string $separator_character = '-'): string + { + $line = " +"; + + foreach ($this->columns as $column) + { + $line .= str_repeat($separator_character, $this->max_lengths[$column] + 2) . '+'; + } + + return $line . "\n"; + } + + /** + * Get table data column + * + * @param string $type Column type + * @param string $content Column content + * @return string + */ + private function get_column(string $type, string $content): string + { + $content = rtrim($content); + return ' ' . $content . str_repeat(' ' , $this->max_lengths[$type] - strlen($content) + 1) . '|'; + } +} diff --git a/tests/event/php_exporter_test.php b/tests/event/php_exporter_test.php index 0effa9d181..3911f46ddd 100644 --- a/tests/event/php_exporter_test.php +++ b/tests/event/php_exporter_test.php @@ -57,7 +57,7 @@ class phpbb_event_php_exporter_test extends phpbb_test_case 'file' => 'extra_description.test', 'arguments' => array(), 'since' => '3.1.0-b2', - 'description' => 'Description

NOTE: This will also be exported', + 'description' => 'Description

NOTE: This will also be exported', ), ), ),