From 0434bce5af767629cf1bac005205d060fd3bc2c6 Mon Sep 17 00:00:00 2001 From: Marc Alexander Date: Sun, 12 Nov 2023 15:04:01 +0100 Subject: [PATCH] [ticket/16944] Generate iconify bundle as needed via icons & assets bag PHPBB3-16944 --- phpBB/adm/style/installer_footer.html | 1 + phpBB/adm/style/overall_footer.html | 1 + phpBB/adm/style/simple_footer.html | 1 + .../default/container/services_assets.yml | 10 +- .../default/container/services_twig.yml | 1 + phpBB/develop/create_iconify_bundle.php | 42 ---- phpBB/includes/acp/acp_extensions.php | 8 - phpBB/includes/acp/acp_styles.php | 9 +- phpBB/language/en/acp/common.php | 2 +- phpBB/phpbb/assets/iconify_bundler.php | 187 ++++-------------- phpBB/phpbb/template/assets_bag.php | 55 ++++++ phpBB/phpbb/template/twig/environment.php | 41 ++-- phpBB/phpbb/template/twig/extension/icon.php | 2 + .../prosilver/template/overall_footer.html | 2 +- .../prosilver/template/simple_footer.html | 2 +- 15 files changed, 139 insertions(+), 225 deletions(-) delete mode 100644 phpBB/develop/create_iconify_bundle.php diff --git a/phpBB/adm/style/installer_footer.html b/phpBB/adm/style/installer_footer.html index 24c80b69e5..41881d5ff6 100644 --- a/phpBB/adm/style/installer_footer.html +++ b/phpBB/adm/style/installer_footer.html @@ -26,6 +26,7 @@ installLang = { +{$ICONIFY_ICONS} {$SCRIPTS} diff --git a/phpBB/adm/style/overall_footer.html b/phpBB/adm/style/overall_footer.html index ed8b3b0d56..984a3d96ff 100644 --- a/phpBB/adm/style/overall_footer.html +++ b/phpBB/adm/style/overall_footer.html @@ -47,6 +47,7 @@ +{$ICONIFY_ICONS} {$SCRIPTS} {% EVENT acp_overall_footer_body_after %} diff --git a/phpBB/adm/style/simple_footer.html b/phpBB/adm/style/simple_footer.html index 50dba2f910..6ad9611bf6 100644 --- a/phpBB/adm/style/simple_footer.html +++ b/phpBB/adm/style/simple_footer.html @@ -21,6 +21,7 @@ +{$ICONIFY_ICONS} {$SCRIPTS} {% EVENT acp_simple_footer_body_after %} diff --git a/phpBB/config/default/container/services_assets.yml b/phpBB/config/default/container/services_assets.yml index 6ba3a7ea27..37c2691b78 100644 --- a/phpBB/config/default/container/services_assets.yml +++ b/phpBB/config/default/container/services_assets.yml @@ -1,8 +1,12 @@ services: + assets.bag: + class: phpbb\template\assets_bag + shared: false + arguments: + - '@assets.iconify_bundler' + assets.iconify_bundler: class: phpbb\assets\iconify_bundler + shared: false arguments: - - '@dbal.conn' - - '@ext.manager' - '@log' - - '%core.root_path%' diff --git a/phpBB/config/default/container/services_twig.yml b/phpBB/config/default/container/services_twig.yml index 7c4e114e8e..17ca9c7503 100644 --- a/phpBB/config/default/container/services_twig.yml +++ b/phpBB/config/default/container/services_twig.yml @@ -5,6 +5,7 @@ services: template.twig.environment: class: phpbb\template\twig\environment arguments: + - '@assets.bag' - '@config' - '@filesystem' - '@path_helper' diff --git a/phpBB/develop/create_iconify_bundle.php b/phpBB/develop/create_iconify_bundle.php deleted file mode 100644 index b71b2f30bd..0000000000 --- a/phpBB/develop/create_iconify_bundle.php +++ /dev/null @@ -1,42 +0,0 @@ - -* @license GNU General Public License, version 2 (GPL-2.0) -* -* For full copyright and license information, please see -* the docs/CREDITS.txt file. -* -*/ - -/** -* This file creates Iconify bundle JS file in assets/iconify directory. -* See https://docs.iconify.design/icon-components/bundles/examples/svg-framework-custom.html -* iconify/json-tools and iconify/json dev requirements should be installed for the script to work. -*/ - -define('IN_PHPBB', true); -$phpbb_root_path = dirname(__FILE__) . '/../'; -$phpEx = substr(strrchr(__FILE__, '.'), 1); - -include($phpbb_root_path . 'common.' . $phpEx); - -/** @var \phpbb\assets\iconify_bundler $iconify_bundler */ -$iconify_bundler = $phpbb_container->get('assets.iconify_bundler'); - -// JS file to save bundle to -$target = $phpbb_root_path . 'assets/iconify/iconify-bundle.js'; - -// Icons to bundle, the list of iconify icons used in phpBB -$iconify_bundler->find_icons([ - $phpbb_root_path . 'styles/', - $phpbb_root_path . 'adm/style/', -]); -$output = $iconify_bundler->get_bundle(); - -// Save to file -file_put_contents($target, $output); - -echo 'Saved ', $target, ' (', strlen($output), " bytes)\n"; diff --git a/phpBB/includes/acp/acp_extensions.php b/phpBB/includes/acp/acp_extensions.php index 4e6b143713..1a30d38d61 100644 --- a/phpBB/includes/acp/acp_extensions.php +++ b/phpBB/includes/acp/acp_extensions.php @@ -270,10 +270,6 @@ class acp_extensions ), array($this->phpbb_root_path . 'adm/style')); $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_ENABLE', time(), array($ext_name)); - - // Force rebuild of iconify bundle - $iconify_bundler = new \phpbb\assets\iconify_bundler($this->db, $this->ext_manager, $this->log, $this->phpbb_root_path); - $iconify_bundler->get_bundle(true); } catch (\phpbb\db\migration\exception $e) { @@ -320,10 +316,6 @@ class acp_extensions } $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_DISABLE', time(), array($ext_name)); - // Force rebuild of iconify bundle - $iconify_bundler = new \phpbb\assets\iconify_bundler($this->db, $this->ext_manager, $this->log, $this->phpbb_root_path); - $iconify_bundler->get_bundle(true); - $this->tpl_name = 'acp_ext_disable'; $this->template->assign_vars([ diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php index 6da638379c..5dfb05a463 100644 --- a/phpBB/includes/acp/acp_styles.php +++ b/phpBB/includes/acp/acp_styles.php @@ -65,9 +65,6 @@ class acp_styles /** @var \phpbb\event\dispatcher_interface */ protected $dispatcher; - /** @var \phpbb\assets\iconify_bundler */ - protected $iconify_bundler; - public function main($id, $mode) { global $db, $phpbb_admin_path, $phpbb_root_path, $phpEx, $template, $request, $cache, $auth, $config, $phpbb_dispatcher, $phpbb_container; @@ -83,7 +80,6 @@ class acp_styles $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $phpEx; $this->dispatcher = $phpbb_dispatcher; - $this->iconify_bundler = $phpbb_container->get('assets.iconify_bundler'); $this->default_style = $config['default_style']; $this->styles_path = $this->phpbb_root_path . $this->styles_path_absolute . '/'; @@ -244,9 +240,6 @@ class acp_styles $this->text_formatter_cache->invalidate(); } - // Force rebuild of iconify bundle - $this->iconify_bundler->get_bundle(true); - // Show message if (!count($messages)) { @@ -375,7 +368,7 @@ class acp_styles $this->cache->purge(); // Force rebuild of iconify bundle - $this->iconify_bundler->get_bundle(true); + //$this->iconify_bundler->get_bundle(true); // Show message trigger_error(implode('
', $messages) . adm_back_link($this->u_action), E_USER_NOTICE); diff --git a/phpBB/language/en/acp/common.php b/phpBB/language/en/acp/common.php index bbe8b7fafa..833f6086f7 100644 --- a/phpBB/language/en/acp/common.php +++ b/phpBB/language/en/acp/common.php @@ -671,7 +671,7 @@ $lang = array_merge($lang, array( 'LOG_USERS_APPROVED' => 'Users approved in usergroup %1$s
» %2$s', 'LOG_USERS_PENDING' => 'Users requested to join group “%1$s” and need to be approved
» %2$s', - 'LOG_ICON_INVALID' => 'Invalid icon supplied: Icon %1$s:%2$s does not seem to exist.', + 'LOG_ICON_INVALID' => 'Invalid icon supplied: Icon %1$s does not seem to exist.', 'LOG_ICON_COLLECTION_INVALID' => 'Invalid icon collection supplied: Icon collection with prefix %1$s does not seem to exist.', 'LOG_IMAGE_GENERATION_ERROR' => 'Error while creating image
» Error in %1$s on line %2$s: %3$s', diff --git a/phpBB/phpbb/assets/iconify_bundler.php b/phpBB/phpbb/assets/iconify_bundler.php index 9897ba2fea..202f824124 100644 --- a/phpBB/phpbb/assets/iconify_bundler.php +++ b/phpBB/phpbb/assets/iconify_bundler.php @@ -13,41 +13,32 @@ namespace phpbb\assets; -use phpbb\exception\runtime_exception; use Iconify\JSONTools\Collection; -use Symfony\Component\Finder\Finder; class iconify_bundler { - protected const BUNDLE_PATH = 'assets/iconify/iconify-bundle.js'; - - protected $db; - - protected $ext_manager; - /** @var \phpbb\log\log_interface */ protected $log; - /** @var \phpbb\filesystem\filesystem_interface */ - protected $filesystem; - - protected $root_path = ''; - - protected $bundle_path = ''; + /** @var string[] Icons list */ protected $icons_list = []; - public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\extension\manager $ext_manager, \phpbb\log\log_interface $log, string $root_path) + /** + * Constructor for iconify bundler + * + * @param \phpbb\log\log_interface $log Logger + */ + public function __construct(\phpbb\log\log_interface $log) { - $this->db = $db; - $this->ext_manager = $ext_manager; - $this->filesystem = new \phpbb\filesystem\filesystem(); $this->log = $log; - $this->root_path = $root_path; - - $this->bundle_path = $root_path . self::BUNDLE_PATH; } - protected function run() + /** + * Run iconify bundler + * + * @return string Iconify bundle + */ + public function run() { // Sort icons first sort($this->icons_list, SORT_NATURAL); @@ -76,127 +67,12 @@ class iconify_bundler return $output; } - public function get_bundle(bool $force_rebuild = false): string - { - if (!$force_rebuild && $this->is_dumped()) - { - return file_get_contents($this->bundle_path); - } - - return $this->create_bundle(); - } - - public function create_bundle(): string - { - $iconify_bundle = $this->with_extensions() - ->with_styles() - ->run(); - - $this->filesystem->dump_file($this->bundle_path, $iconify_bundle); - - return $iconify_bundle; - } - /** - * @param array $paths Icon paths + * Add icon to icons list * + * @param string $icon_name * @return void */ - public function find_icons(array $paths): void - { - if (!count($paths)) - { - return; - } - - $finder = new Finder(); - $finder->files(); - - foreach ($paths as $cur_path) - { - $finder->in($cur_path); - } - - $finder->name('*.html') - ->name('*.twig') - ->contains("Icon('iconify',"); - - foreach ($finder as $file) - { - $contents = $file->getContents(); - $matches = []; - preg_match_all("/Icon\('iconify', *(?:'(?[^']+(?' ~ S_CONTENT_FLOW_(?:BEGIN|END))?)|(?{[^}]+}))/m", $contents, $matches, PREG_SET_ORDER); - foreach ($matches as $match_data) - { - if (!empty($match_data['content_flow'])) - { - $base_icon_name = str_replace($match_data['content_flow'], '', $match_data['text']); - $this->add_icon($base_icon_name . 'left'); - $this->add_icon($base_icon_name . 'right'); - } - else if (!empty($match_data['json'])) - { - preg_match_all("/\s'(?[^']+)'/", $match_data['json'], $icons_array, PREG_SET_ORDER); - foreach ($icons_array as $icon) - { - $this->add_icon($icon['text']); - } - } - else if (!empty($match_data['text'])) - { - $this->add_icon($match_data['text']); - } - else - { - throw new runtime_exception('Found unexpected icon name `%1$s` in `%2$s`', [$match_data[0], $file->getPath()]); - } - } - } - } - - public function with_extensions(): iconify_bundler - { - $extensions = $this->ext_manager->all_enabled(); - - $search_paths = []; - - foreach ($extensions as $path) - { - if (file_exists($path)) - { - $search_paths[] = $path; - } - } - - $this->find_icons($search_paths); - - return $this; - } - - public function with_styles(): iconify_bundler - { - $sql = 'SELECT * - FROM ' . STYLES_TABLE; - $result = $this->db->sql_query($sql); - - $style_paths = []; - - while ($row = $this->db->sql_fetchrow($result)) - { - $style_paths[] = $this->root_path . 'styles/' . $row['style_path']; - } - $this->db->sql_freeresult($result); - - $this->find_icons($style_paths); - - return $this; - } - - public function is_dumped(): bool - { - return $this->filesystem->exists($this->bundle_path) && $this->filesystem->is_readable($this->bundle_path); - } - protected function add_icon(string $icon_name): void { if (!in_array($icon_name, $this->icons_list)) @@ -205,6 +81,20 @@ class iconify_bundler } } + /** + * Add multiple icons to icons list + * + * @param array $icons + * @return void + */ + public function add_icons(array $icons): void + { + foreach ($icons as $icon) + { + $this->add_icon($icon); + } + } + /** * Organize icons list by prefix * @@ -222,9 +112,9 @@ class iconify_bundler $icon = $this->name_to_icon($icon_name); if ($icon === null || $icon['provider'] !== '') { - // Invalid name or icon name has provider. - // All icons in this example are from Iconify, so providers are not supported. - throw new \Error('Invalid icon name: ' . $icon_name); + // Invalid name or icon name does not have provider + $this->log->add('critical', ANONYMOUS, '', 'LOG_ICON_INVALID', false, [$icon_name]); + continue; } $prefix = $icon['prefix']; @@ -308,7 +198,13 @@ class iconify_bundler return null; } - protected function load_icons_data($icons): string + /** + * Load icons date for supplied icons array + * + * @param array $icons + * @return string + */ + protected function load_icons_data(array $icons): string { // Load icons data $output = ''; @@ -322,10 +218,11 @@ class iconify_bundler } // Make sure all icons exist - foreach ($iconsList as $name) { + foreach ($iconsList as $name) + { if (!$collection->iconExists($name)) { - $this->log->add('critical', ANONYMOUS, '', 'LOG_ICON_INVALID', false, [$prefix, $name]); + $this->log->add('critical', ANONYMOUS, '', 'LOG_ICON_INVALID', false, [$prefix . ':' . $name]); } } diff --git a/phpBB/phpbb/template/assets_bag.php b/phpBB/phpbb/template/assets_bag.php index 012e8bbcbe..e5bfec9db8 100644 --- a/phpBB/phpbb/template/assets_bag.php +++ b/phpBB/phpbb/template/assets_bag.php @@ -13,6 +13,8 @@ namespace phpbb\template; +use phpbb\assets\iconify_bundler; + class assets_bag { /** @var asset[] */ @@ -21,6 +23,17 @@ class assets_bag /** @var asset[] */ protected $scripts = []; + /** @var string[] */ + protected $iconify_icons = []; + + /** + * Constructor for assets bag + * + * @param iconify_bundler $iconify_bundler + */ + public function __construct(protected iconify_bundler $iconify_bundler) + {} + /** * Add a css asset to the bag * @@ -41,6 +54,30 @@ class assets_bag $this->scripts[] = $asset; } + public function add_iconify_icon(string $icon): void + { + $this->iconify_icons[] = $icon; + } + + /** + * Inject iconify icons into template + * + * @param string $output Output before injection + * @param string $variable_name Variable name for injection + * @param bool $use_cdn Flag whether to use CDN or local data + * + * @return string Output after injection + */ + public function inject_iconify_icons(string $output, string $variable_name, bool $use_cdn): string + { + if (str_contains($output, $variable_name)) + { + $output = str_replace($variable_name, $use_cdn ? '' : $this->get_iconify_content(), $output); + } + + return $output; + } + /** * Returns all css assets * @@ -92,4 +129,22 @@ class assets_bag return $output; } + + /** + * Gets the HTML code to include all iconify icons + * + * @return string HTML code for iconify bundle + */ + public function get_iconify_content(): string + { + $output = ''; + if (count($this->iconify_icons)) + { + $output .= ''; + } + return $output; + } } diff --git a/phpBB/phpbb/template/twig/environment.php b/phpBB/phpbb/template/twig/environment.php index 7def175146..a46d4982f1 100644 --- a/phpBB/phpbb/template/twig/environment.php +++ b/phpBB/phpbb/template/twig/environment.php @@ -13,26 +13,32 @@ namespace phpbb\template\twig; +use phpbb\config\config; +use phpbb\event\dispatcher_interface; +use phpbb\extension\manager; +use phpbb\filesystem\filesystem; +use phpbb\path_helper; use phpbb\template\assets_bag; +use Twig\Loader\LoaderInterface; class environment extends \Twig\Environment { - /** @var \phpbb\config\config */ + /** @var config */ protected $phpbb_config; - /** @var \phpbb\filesystem\filesystem */ + /** @var filesystem */ protected $filesystem; - /** @var \phpbb\path_helper */ + /** @var path_helper */ protected $phpbb_path_helper; /** @var \Symfony\Component\DependencyInjection\ContainerInterface */ protected $container; - /** @var \phpbb\extension\manager */ + /** @var manager */ protected $extension_manager; - /** @var \phpbb\event\dispatcher_interface */ + /** @var dispatcher_interface */ protected $phpbb_dispatcher; /** @var string */ @@ -50,16 +56,17 @@ class environment extends \Twig\Environment /** * Constructor * - * @param \phpbb\config\config $phpbb_config The phpBB configuration - * @param \phpbb\filesystem\filesystem $filesystem - * @param \phpbb\path_helper $path_helper phpBB path helper + * @param assets_bag $assets_bag Assets bag + * @param config $phpbb_config The phpBB configuration + * @param filesystem $filesystem + * @param path_helper $path_helper phpBB path helper * @param string $cache_path The path to the cache directory - * @param \phpbb\extension\manager|null $extension_manager phpBB extension manager - * @param \Twig\Loader\LoaderInterface|null $loader Twig loader interface - * @param \phpbb\event\dispatcher_interface|null $phpbb_dispatcher Event dispatcher object + * @param manager|null $extension_manager phpBB extension manager + * @param LoaderInterface|null $loader Twig loader interface + * @param dispatcher_interface|null $phpbb_dispatcher Event dispatcher object * @param array $options Array of options to pass to Twig */ - public function __construct(\phpbb\config\config $phpbb_config, \phpbb\filesystem\filesystem $filesystem, \phpbb\path_helper $path_helper, $cache_path, \phpbb\extension\manager $extension_manager = null, \Twig\Loader\LoaderInterface $loader = null, \phpbb\event\dispatcher_interface $phpbb_dispatcher = null, $options = array()) + public function __construct(assets_bag $assets_bag, config $phpbb_config, filesystem $filesystem, path_helper $path_helper, $cache_path, manager $extension_manager = null, LoaderInterface $loader = null, dispatcher_interface $phpbb_dispatcher = null, $options = array()) { $this->phpbb_config = $phpbb_config; @@ -70,7 +77,7 @@ class environment extends \Twig\Environment $this->phpbb_root_path = $this->phpbb_path_helper->get_phpbb_root_path(); - $this->assets_bag = new assets_bag(); + $this->assets_bag = $assets_bag; $options = array_merge(array( 'cache' => (defined('IN_INSTALL')) ? false : $cache_path, @@ -97,7 +104,7 @@ class environment extends \Twig\Environment /** * Get phpBB config * - * @return \phpbb\config\config + * @return config */ public function get_phpbb_config() { @@ -117,7 +124,7 @@ class environment extends \Twig\Environment /** * Get the filesystem object * - * @return \phpbb\filesystem\filesystem + * @return filesystem */ public function get_filesystem() { @@ -137,7 +144,7 @@ class environment extends \Twig\Environment /** * Get the phpbb path helper object * - * @return \phpbb\path_helper + * @return path_helper */ public function get_path_helper() { @@ -204,6 +211,7 @@ class environment extends \Twig\Environment { $context['definition']->set('SCRIPTS', '__SCRIPTS_' . $placeholder_salt . '__'); $context['definition']->set('STYLESHEETS', '__STYLESHEETS_' . $placeholder_salt . '__'); + $context['definition']->set('ICONIFY_ICONS', '__ICONIFY_ICONS_' . $placeholder_salt . '__'); } /** @@ -251,6 +259,7 @@ class environment extends \Twig\Environment { $output = str_replace('__STYLESHEETS_' . $placeholder_salt . '__', $this->assets_bag->get_stylesheets_content(), $output); $output = str_replace('__SCRIPTS_' . $placeholder_salt . '__', $this->assets_bag->get_scripts_content(), $output); + $output = $this->assets_bag->inject_iconify_icons($output, '__ICONIFY_ICONS_' . $placeholder_salt . '__', $this->phpbb_config['allow_cdn']); return $output; } diff --git a/phpBB/phpbb/template/twig/extension/icon.php b/phpBB/phpbb/template/twig/extension/icon.php index 550a049795..cea96b1992 100644 --- a/phpBB/phpbb/template/twig/extension/icon.php +++ b/phpBB/phpbb/template/twig/extension/icon.php @@ -89,6 +89,8 @@ class icon extends AbstractExtension case 'iconify': $source = explode(':', $icon); $source = $source[0]; + $environment->get_assets_bag()->add_iconify_icon($icon); + break; case 'png': diff --git a/phpBB/styles/prosilver/template/overall_footer.html b/phpBB/styles/prosilver/template/overall_footer.html index 7b64537ced..72df38141a 100644 --- a/phpBB/styles/prosilver/template/overall_footer.html +++ b/phpBB/styles/prosilver/template/overall_footer.html @@ -76,7 +76,6 @@ -{% INCLUDEJS T_ASSETS_PATH ~ '/iconify/iconify-bundle.js' %} {% INCLUDEJS T_ASSETS_PATH ~ '/iconify/iconify.min.js' %} @@ -109,6 +108,7 @@ +{$ICONIFY_ICONS} {$SCRIPTS} diff --git a/phpBB/styles/prosilver/template/simple_footer.html b/phpBB/styles/prosilver/template/simple_footer.html index 550d71367b..38c1677831 100644 --- a/phpBB/styles/prosilver/template/simple_footer.html +++ b/phpBB/styles/prosilver/template/simple_footer.html @@ -49,7 +49,7 @@ - +{$ICONIFY_ICONS} {$SCRIPTS} {% EVENT simple_footer_body_after %}