Release of v4.1.1-beta2

Adds new JCB package engine. Fix issue with loading the Component Builder Wiki. Adds advanced version update notice to the Component Builder Dashboard. Completely refactors the class that builds the Component Dashboard. #1134. Adds Initialize, Reset, and Push functionality to the Repository entities. Completely refactors the SQL teaks and SQL dump classes. Changes J4 fields to allow NULL. Fix a bug in Dynamic Get JavaScript that causes table columns to not load.
This commit is contained in:
2025-06-27 10:36:15 +00:00
parent d11860ae1a
commit 64bc4327eb
883 changed files with 63212 additions and 27462 deletions

View File

@ -38,6 +38,233 @@ use VDM\Joomla\Utilities\StringHelper;
*/
class ComponentbuilderModel extends ListModel
{
/**
* Represents the current user object.
*
* @var User The user object representing the current user.
* @since 3.2.0
*/
protected User $user;
/**
* View groups of this component
*
* @var array<string, string>
* @since 5.1.1
*/
protected array $viewGroups = [
'main' => ['png.compiler', 'png.joomla_components', 'png.joomla_modules', 'png.joomla_plugins', 'png.powers', 'png.search', 'png.admin_views', 'png.custom_admin_views', 'png.site_views', 'png.template.add', 'png.templates', 'png.layouts', 'png.dynamic_get.add', 'png.dynamic_gets', 'png.custom_codes', 'png.placeholders', 'png.libraries', 'png.snippets', 'png.validation_rules', 'png.field.add', 'png.fields', 'png.fields.catid_qpo0O0oqp_com_componentbuilder_po0O0oq_field', 'png.fieldtypes', 'png.fieldtypes.catid_qpo0O0oqp_com_componentbuilder_po0O0oq_fieldtype', 'png.language_translations', 'png.languages', 'png.servers', 'png.repositories', 'png.help_documents'],
];
/**
* View access array.
*
* @var array<string, string>
* @since 5.1.1
*/
protected array $viewAccess = [
'compiler.submenu' => 'compiler.submenu',
'compiler.dashboard_list' => 'compiler.dashboard_list',
'search.access' => 'search.access',
'search.submenu' => 'search.submenu',
'search.dashboard_list' => 'search.dashboard_list',
'joomla_component.create' => 'joomla_component.create',
'joomla_components.access' => 'joomla_component.access',
'joomla_component.access' => 'joomla_component.access',
'joomla_components.submenu' => 'joomla_component.submenu',
'joomla_components.dashboard_list' => 'joomla_component.dashboard_list',
'joomla_module.create' => 'joomla_module.create',
'joomla_modules.access' => 'joomla_module.access',
'joomla_module.access' => 'joomla_module.access',
'joomla_modules.submenu' => 'joomla_module.submenu',
'joomla_modules.dashboard_list' => 'joomla_module.dashboard_list',
'joomla_plugin.create' => 'joomla_plugin.create',
'joomla_plugins.access' => 'joomla_plugin.access',
'joomla_plugin.access' => 'joomla_plugin.access',
'joomla_plugins.submenu' => 'joomla_plugin.submenu',
'joomla_plugins.dashboard_list' => 'joomla_plugin.dashboard_list',
'joomla_power.create' => 'joomla_power.create',
'joomla_powers.access' => 'joomla_power.access',
'joomla_power.access' => 'joomla_power.access',
'joomla_powers.submenu' => 'joomla_power.submenu',
'power.create' => 'power.create',
'powers.access' => 'power.access',
'power.access' => 'power.access',
'powers.submenu' => 'power.submenu',
'powers.dashboard_list' => 'power.dashboard_list',
'admin_view.create' => 'admin_view.create',
'admin_views.access' => 'admin_view.access',
'admin_view.access' => 'admin_view.access',
'admin_views.submenu' => 'admin_view.submenu',
'admin_views.dashboard_list' => 'admin_view.dashboard_list',
'custom_admin_views.access' => 'custom_admin_view.access',
'custom_admin_view.access' => 'custom_admin_view.access',
'custom_admin_views.submenu' => 'custom_admin_view.submenu',
'custom_admin_views.dashboard_list' => 'custom_admin_view.dashboard_list',
'site_views.access' => 'site_view.access',
'site_view.access' => 'site_view.access',
'site_views.submenu' => 'site_view.submenu',
'site_views.dashboard_list' => 'site_view.dashboard_list',
'templates.access' => 'template.access',
'template.access' => 'template.access',
'templates.submenu' => 'template.submenu',
'templates.dashboard_list' => 'template.dashboard_list',
'template.dashboard_add' => 'template.dashboard_add',
'layouts.access' => 'layout.access',
'layout.access' => 'layout.access',
'layouts.submenu' => 'layout.submenu',
'layouts.dashboard_list' => 'layout.dashboard_list',
'dynamic_get.create' => 'dynamic_get.create',
'dynamic_gets.access' => 'dynamic_get.access',
'dynamic_get.access' => 'dynamic_get.access',
'dynamic_gets.submenu' => 'dynamic_get.submenu',
'dynamic_gets.dashboard_list' => 'dynamic_get.dashboard_list',
'dynamic_get.dashboard_add' => 'dynamic_get.dashboard_add',
'custom_code.create' => 'custom_code.create',
'custom_codes.access' => 'custom_code.access',
'custom_code.access' => 'custom_code.access',
'custom_codes.submenu' => 'custom_code.submenu',
'custom_codes.dashboard_list' => 'custom_code.dashboard_list',
'class_extends.create' => 'class_extends.create',
'class_extendings.access' => 'class_extends.access',
'class_extends.access' => 'class_extends.access',
'class_property.create' => 'class_property.create',
'class_properties.access' => 'class_property.access',
'class_property.access' => 'class_property.access',
'class_method.create' => 'class_method.create',
'class_methods.access' => 'class_method.access',
'class_method.access' => 'class_method.access',
'placeholder.create' => 'placeholder.create',
'placeholders.access' => 'placeholder.access',
'placeholder.access' => 'placeholder.access',
'placeholders.submenu' => 'placeholder.submenu',
'placeholders.dashboard_list' => 'placeholder.dashboard_list',
'library.create' => 'library.create',
'libraries.access' => 'library.access',
'library.access' => 'library.access',
'libraries.submenu' => 'library.submenu',
'libraries.dashboard_list' => 'library.dashboard_list',
'snippets.access' => 'snippet.access',
'snippet.access' => 'snippet.access',
'snippets.submenu' => 'snippet.submenu',
'snippets.dashboard_list' => 'snippet.dashboard_list',
'validation_rule.create' => 'validation_rule.create',
'validation_rules.access' => 'validation_rule.access',
'validation_rule.access' => 'validation_rule.access',
'validation_rules.submenu' => 'validation_rule.submenu',
'validation_rules.dashboard_list' => 'validation_rule.dashboard_list',
'field.create' => 'field.create',
'fields.access' => 'field.access',
'field.access' => 'field.access',
'fields.submenu' => 'field.submenu',
'fields.dashboard_list' => 'field.dashboard_list',
'field.dashboard_add' => 'field.dashboard_add',
'fieldtype.create' => 'fieldtype.create',
'fieldtypes.access' => 'fieldtype.access',
'fieldtype.access' => 'fieldtype.access',
'fieldtypes.submenu' => 'fieldtype.submenu',
'fieldtypes.dashboard_list' => 'fieldtype.dashboard_list',
'language_translation.create' => 'language_translation.create',
'language_translations.access' => 'language_translation.access',
'language_translation.access' => 'language_translation.access',
'language_translations.submenu' => 'language_translation.submenu',
'language_translations.dashboard_list' => 'language_translation.dashboard_list',
'language.create' => 'language.create',
'languages.access' => 'language.access',
'language.access' => 'language.access',
'languages.submenu' => 'language.submenu',
'languages.dashboard_list' => 'language.dashboard_list',
'server.create' => 'server.create',
'servers.access' => 'server.access',
'server.access' => 'server.access',
'servers.submenu' => 'server.submenu',
'servers.dashboard_list' => 'server.dashboard_list',
'repository.create' => 'repository.create',
'repositories.access' => 'repository.access',
'repository.access' => 'repository.access',
'repositories.submenu' => 'repository.submenu',
'repositories.dashboard_list' => 'repository.dashboard_list',
'help_document.create' => 'help_document.create',
'help_documents.access' => 'help_document.access',
'help_document.access' => 'help_document.access',
'help_documents.submenu' => 'help_document.submenu',
'help_documents.dashboard_list' => 'help_document.dashboard_list',
'admin_fields.create' => 'admin_fields.create',
'admins_fields.access' => 'admin_fields.access',
'admin_fields.access' => 'admin_fields.access',
'admin_fields_conditions.create' => 'admin_fields_conditions.create',
'admins_fields_conditions.access' => 'admin_fields_conditions.access',
'admin_fields_conditions.access' => 'admin_fields_conditions.access',
'admin_fields_relations.create' => 'admin_fields_relations.create',
'admins_fields_relations.access' => 'admin_fields_relations.access',
'admin_fields_relations.access' => 'admin_fields_relations.access',
'admin_custom_tabs.create' => 'admin_custom_tabs.create',
'admins_custom_tabs.access' => 'admin_custom_tabs.access',
'admin_custom_tabs.access' => 'admin_custom_tabs.access',
'component_admin_views.create' => 'component_admin_views.create',
'components_admin_views.access' => 'component_admin_views.access',
'component_admin_views.access' => 'component_admin_views.access',
'component_site_views.create' => 'component_site_views.create',
'components_site_views.access' => 'component_site_views.access',
'component_site_views.access' => 'component_site_views.access',
'component_custom_admin_views.create' => 'component_custom_admin_views.create',
'components_custom_admin_views.access' => 'component_custom_admin_views.access',
'component_custom_admin_views.access' => 'component_custom_admin_views.access',
'component_updates.create' => 'component_updates.create',
'components_updates.access' => 'component_updates.access',
'component_updates.access' => 'component_updates.access',
'component_mysql_tweaks.create' => 'component_mysql_tweaks.create',
'components_mysql_tweaks.access' => 'component_mysql_tweaks.access',
'component_mysql_tweaks.access' => 'component_mysql_tweaks.access',
'component_custom_admin_menus.create' => 'component_custom_admin_menus.create',
'components_custom_admin_menus.access' => 'component_custom_admin_menus.access',
'component_custom_admin_menus.access' => 'component_custom_admin_menus.access',
'component_router.create' => 'component_router.create',
'components_routers.access' => 'component_router.access',
'component_router.access' => 'component_router.access',
'component_config.create' => 'component_config.create',
'components_config.access' => 'component_config.access',
'component_config.access' => 'component_config.access',
'component_dashboard.create' => 'component_dashboard.create',
'components_dashboard.access' => 'component_dashboard.access',
'component_dashboard.access' => 'component_dashboard.access',
'component_files_folders.create' => 'component_files_folders.create',
'components_files_folders.access' => 'component_files_folders.access',
'component_files_folders.access' => 'component_files_folders.access',
'component_placeholders.create' => 'component_placeholders.create',
'components_placeholders.access' => 'component_placeholders.access',
'component_placeholders.access' => 'component_placeholders.access',
'component_plugins.create' => 'component_plugins.create',
'components_plugins.access' => 'component_plugins.access',
'component_plugins.access' => 'component_plugins.access',
'component_modules.create' => 'component_modules.create',
'components_modules.access' => 'component_modules.access',
'component_modules.access' => 'component_modules.access',
'snippet_type.create' => 'snippet_type.create',
'snippet_types.access' => 'snippet_type.access',
'snippet_type.access' => 'snippet_type.access',
'library_config.create' => 'library_config.create',
'libraries_config.access' => 'library_config.access',
'library_config.access' => 'library_config.access',
'library_files_folders_urls.create' => 'library_files_folders_urls.create',
'libraries_files_folders_urls.access' => 'library_files_folders_urls.access',
'library_files_folders_urls.access' => 'library_files_folders_urls.access',
'joomla_module_updates.create' => 'joomla_module_updates.create',
'joomla_modules_updates.access' => 'joomla_module_updates.access',
'joomla_module_updates.access' => 'joomla_module_updates.access',
'joomla_module_files_folders_urls.create' => 'joomla_module_files_folders_urls.create',
'joomla_modules_files_folders_urls.access' => 'joomla_module_files_folders_urls.access',
'joomla_module_files_folders_urls.access' => 'joomla_module_files_folders_urls.access',
'joomla_plugin_groups.access' => 'joomla_plugin_group.access',
'joomla_plugin_group.access' => 'joomla_plugin_group.access',
'joomla_plugin_updates.create' => 'joomla_plugin_updates.create',
'joomla_plugins_updates.access' => 'joomla_plugin_updates.access',
'joomla_plugin_updates.access' => 'joomla_plugin_updates.access',
'joomla_plugin_files_folders_urls.create' => 'joomla_plugin_files_folders_urls.create',
'joomla_plugins_files_folders_urls.access' => 'joomla_plugin_files_folders_urls.access',
'joomla_plugin_files_folders_urls.access' => 'joomla_plugin_files_folders_urls.access',
];
/**
* The styles array.
*
@ -59,402 +286,50 @@ class ComponentbuilderModel extends ListModel
'administrator/components/com_componentbuilder/assets/js/admin.js'
];
public function getIcons()
/**
* Constructor
*
* @param array $config An array of configuration options (name, state, dbo, table_path, ignore_request).
* @param ?MVCFactoryInterface $factory The factory.
*
* @since 1.6
* @throws \Exception
*/
public function __construct($config = [], MVCFactoryInterface $factory = null)
{
// load user for access menus
$user = Factory::getApplication()->getIdentity();
// reset icon array
$icons = [];
// view groups array
$viewGroups = array(
'main' => array('png.compiler', 'png.joomla_components', 'png.joomla_modules', 'png.joomla_plugins', 'png.powers', 'png.search', 'png.admin_views', 'png.custom_admin_views', 'png.site_views', 'png.template.add', 'png.templates', 'png.layouts', 'png.dynamic_get.add', 'png.dynamic_gets', 'png.custom_codes', 'png.placeholders', 'png.libraries', 'png.snippets', 'png.validation_rules', 'png.field.add', 'png.fields', 'png.fields.catid_qpo0O0oqp_com_componentbuilder_po0O0oq_field', 'png.fieldtypes', 'png.fieldtypes.catid_qpo0O0oqp_com_componentbuilder_po0O0oq_fieldtype', 'png.language_translations', 'png.languages', 'png.servers', 'png.repositories', 'png.help_documents')
);
// view access array
$viewAccess = [
'compiler.submenu' => 'compiler.submenu',
'compiler.dashboard_list' => 'compiler.dashboard_list',
'search.access' => 'search.access',
'search.submenu' => 'search.submenu',
'search.dashboard_list' => 'search.dashboard_list',
'joomla_component.create' => 'joomla_component.create',
'joomla_components.access' => 'joomla_component.access',
'joomla_component.access' => 'joomla_component.access',
'joomla_components.submenu' => 'joomla_component.submenu',
'joomla_components.dashboard_list' => 'joomla_component.dashboard_list',
'joomla_module.create' => 'joomla_module.create',
'joomla_modules.access' => 'joomla_module.access',
'joomla_module.access' => 'joomla_module.access',
'joomla_modules.submenu' => 'joomla_module.submenu',
'joomla_modules.dashboard_list' => 'joomla_module.dashboard_list',
'joomla_plugin.create' => 'joomla_plugin.create',
'joomla_plugins.access' => 'joomla_plugin.access',
'joomla_plugin.access' => 'joomla_plugin.access',
'joomla_plugins.submenu' => 'joomla_plugin.submenu',
'joomla_plugins.dashboard_list' => 'joomla_plugin.dashboard_list',
'joomla_power.create' => 'joomla_power.create',
'joomla_powers.access' => 'joomla_power.access',
'joomla_power.access' => 'joomla_power.access',
'joomla_powers.submenu' => 'joomla_power.submenu',
'power.create' => 'power.create',
'powers.access' => 'power.access',
'power.access' => 'power.access',
'powers.submenu' => 'power.submenu',
'powers.dashboard_list' => 'power.dashboard_list',
'admin_view.create' => 'admin_view.create',
'admin_views.access' => 'admin_view.access',
'admin_view.access' => 'admin_view.access',
'admin_views.submenu' => 'admin_view.submenu',
'admin_views.dashboard_list' => 'admin_view.dashboard_list',
'custom_admin_views.access' => 'custom_admin_view.access',
'custom_admin_view.access' => 'custom_admin_view.access',
'custom_admin_views.submenu' => 'custom_admin_view.submenu',
'custom_admin_views.dashboard_list' => 'custom_admin_view.dashboard_list',
'site_views.access' => 'site_view.access',
'site_view.access' => 'site_view.access',
'site_views.submenu' => 'site_view.submenu',
'site_views.dashboard_list' => 'site_view.dashboard_list',
'templates.access' => 'template.access',
'template.access' => 'template.access',
'templates.submenu' => 'template.submenu',
'templates.dashboard_list' => 'template.dashboard_list',
'template.dashboard_add' => 'template.dashboard_add',
'layouts.access' => 'layout.access',
'layout.access' => 'layout.access',
'layouts.submenu' => 'layout.submenu',
'layouts.dashboard_list' => 'layout.dashboard_list',
'dynamic_get.create' => 'dynamic_get.create',
'dynamic_gets.access' => 'dynamic_get.access',
'dynamic_get.access' => 'dynamic_get.access',
'dynamic_gets.submenu' => 'dynamic_get.submenu',
'dynamic_gets.dashboard_list' => 'dynamic_get.dashboard_list',
'dynamic_get.dashboard_add' => 'dynamic_get.dashboard_add',
'custom_code.create' => 'custom_code.create',
'custom_codes.access' => 'custom_code.access',
'custom_code.access' => 'custom_code.access',
'custom_codes.submenu' => 'custom_code.submenu',
'custom_codes.dashboard_list' => 'custom_code.dashboard_list',
'class_property.create' => 'class_property.create',
'class_properties.access' => 'class_property.access',
'class_property.access' => 'class_property.access',
'class_method.create' => 'class_method.create',
'class_methods.access' => 'class_method.access',
'class_method.access' => 'class_method.access',
'placeholder.create' => 'placeholder.create',
'placeholders.access' => 'placeholder.access',
'placeholder.access' => 'placeholder.access',
'placeholders.submenu' => 'placeholder.submenu',
'placeholders.dashboard_list' => 'placeholder.dashboard_list',
'library.create' => 'library.create',
'libraries.access' => 'library.access',
'library.access' => 'library.access',
'libraries.submenu' => 'library.submenu',
'libraries.dashboard_list' => 'library.dashboard_list',
'snippets.access' => 'snippet.access',
'snippet.access' => 'snippet.access',
'snippets.submenu' => 'snippet.submenu',
'snippets.dashboard_list' => 'snippet.dashboard_list',
'validation_rule.create' => 'validation_rule.create',
'validation_rules.access' => 'validation_rule.access',
'validation_rule.access' => 'validation_rule.access',
'validation_rules.submenu' => 'validation_rule.submenu',
'validation_rules.dashboard_list' => 'validation_rule.dashboard_list',
'field.create' => 'field.create',
'fields.access' => 'field.access',
'field.access' => 'field.access',
'fields.submenu' => 'field.submenu',
'fields.dashboard_list' => 'field.dashboard_list',
'field.dashboard_add' => 'field.dashboard_add',
'fieldtype.create' => 'fieldtype.create',
'fieldtypes.access' => 'fieldtype.access',
'fieldtype.access' => 'fieldtype.access',
'fieldtypes.submenu' => 'fieldtype.submenu',
'fieldtypes.dashboard_list' => 'fieldtype.dashboard_list',
'language_translation.create' => 'language_translation.create',
'language_translations.access' => 'language_translation.access',
'language_translation.access' => 'language_translation.access',
'language_translations.submenu' => 'language_translation.submenu',
'language_translations.dashboard_list' => 'language_translation.dashboard_list',
'language.create' => 'language.create',
'languages.access' => 'language.access',
'language.access' => 'language.access',
'languages.submenu' => 'language.submenu',
'languages.dashboard_list' => 'language.dashboard_list',
'server.create' => 'server.create',
'servers.access' => 'server.access',
'server.access' => 'server.access',
'servers.submenu' => 'server.submenu',
'servers.dashboard_list' => 'server.dashboard_list',
'repository.create' => 'repository.create',
'repositories.access' => 'repository.access',
'repository.access' => 'repository.access',
'repositories.submenu' => 'repository.submenu',
'repositories.dashboard_list' => 'repository.dashboard_list',
'help_document.create' => 'help_document.create',
'help_documents.access' => 'help_document.access',
'help_document.access' => 'help_document.access',
'help_documents.submenu' => 'help_document.submenu',
'help_documents.dashboard_list' => 'help_document.dashboard_list',
'admin_fields.create' => 'admin_fields.create',
'admins_fields.access' => 'admin_fields.access',
'admin_fields.access' => 'admin_fields.access',
'admin_fields_conditions.create' => 'admin_fields_conditions.create',
'admins_fields_conditions.access' => 'admin_fields_conditions.access',
'admin_fields_conditions.access' => 'admin_fields_conditions.access',
'admin_fields_relations.create' => 'admin_fields_relations.create',
'admins_fields_relations.access' => 'admin_fields_relations.access',
'admin_fields_relations.access' => 'admin_fields_relations.access',
'admin_custom_tabs.create' => 'admin_custom_tabs.create',
'admins_custom_tabs.access' => 'admin_custom_tabs.access',
'admin_custom_tabs.access' => 'admin_custom_tabs.access',
'component_admin_views.create' => 'component_admin_views.create',
'components_admin_views.access' => 'component_admin_views.access',
'component_admin_views.access' => 'component_admin_views.access',
'component_site_views.create' => 'component_site_views.create',
'components_site_views.access' => 'component_site_views.access',
'component_site_views.access' => 'component_site_views.access',
'component_custom_admin_views.create' => 'component_custom_admin_views.create',
'components_custom_admin_views.access' => 'component_custom_admin_views.access',
'component_custom_admin_views.access' => 'component_custom_admin_views.access',
'component_updates.create' => 'component_updates.create',
'components_updates.access' => 'component_updates.access',
'component_updates.access' => 'component_updates.access',
'component_mysql_tweaks.create' => 'component_mysql_tweaks.create',
'components_mysql_tweaks.access' => 'component_mysql_tweaks.access',
'component_mysql_tweaks.access' => 'component_mysql_tweaks.access',
'component_custom_admin_menus.create' => 'component_custom_admin_menus.create',
'components_custom_admin_menus.access' => 'component_custom_admin_menus.access',
'component_custom_admin_menus.access' => 'component_custom_admin_menus.access',
'component_router.create' => 'component_router.create',
'components_routers.access' => 'component_router.access',
'component_router.access' => 'component_router.access',
'component_config.create' => 'component_config.create',
'components_config.access' => 'component_config.access',
'component_config.access' => 'component_config.access',
'component_dashboard.create' => 'component_dashboard.create',
'components_dashboard.access' => 'component_dashboard.access',
'component_dashboard.access' => 'component_dashboard.access',
'component_files_folders.create' => 'component_files_folders.create',
'components_files_folders.access' => 'component_files_folders.access',
'component_files_folders.access' => 'component_files_folders.access',
'component_placeholders.create' => 'component_placeholders.create',
'components_placeholders.access' => 'component_placeholders.access',
'component_placeholders.access' => 'component_placeholders.access',
'component_plugins.create' => 'component_plugins.create',
'components_plugins.access' => 'component_plugins.access',
'component_plugins.access' => 'component_plugins.access',
'component_modules.create' => 'component_modules.create',
'components_modules.access' => 'component_modules.access',
'component_modules.access' => 'component_modules.access',
'snippet_type.create' => 'snippet_type.create',
'snippet_types.access' => 'snippet_type.access',
'snippet_type.access' => 'snippet_type.access',
'library_config.create' => 'library_config.create',
'libraries_config.access' => 'library_config.access',
'library_config.access' => 'library_config.access',
'library_files_folders_urls.create' => 'library_files_folders_urls.create',
'libraries_files_folders_urls.access' => 'library_files_folders_urls.access',
'library_files_folders_urls.access' => 'library_files_folders_urls.access',
'class_extends.create' => 'class_extends.create',
'class_extendings.access' => 'class_extends.access',
'class_extends.access' => 'class_extends.access',
'joomla_module_updates.create' => 'joomla_module_updates.create',
'joomla_modules_updates.access' => 'joomla_module_updates.access',
'joomla_module_updates.access' => 'joomla_module_updates.access',
'joomla_module_files_folders_urls.create' => 'joomla_module_files_folders_urls.create',
'joomla_modules_files_folders_urls.access' => 'joomla_module_files_folders_urls.access',
'joomla_module_files_folders_urls.access' => 'joomla_module_files_folders_urls.access',
'joomla_plugin_groups.access' => 'joomla_plugin_group.access',
'joomla_plugin_group.access' => 'joomla_plugin_group.access',
'joomla_plugin_updates.create' => 'joomla_plugin_updates.create',
'joomla_plugins_updates.access' => 'joomla_plugin_updates.access',
'joomla_plugin_updates.access' => 'joomla_plugin_updates.access',
'joomla_plugin_files_folders_urls.create' => 'joomla_plugin_files_folders_urls.create',
'joomla_plugins_files_folders_urls.access' => 'joomla_plugin_files_folders_urls.access',
'joomla_plugin_files_folders_urls.access' => 'joomla_plugin_files_folders_urls.access',
];
// loop over the $views
foreach($viewGroups as $group => $views)
parent::__construct($config, $factory);
$this->user ??= $this->getCurrentUser();
}
/**
* Get dashboard icons, grouped by view sections.
*
* @return array<string, array<int, \stdClass|false>>
* @since 5.1.1
*/
public function getIcons(): array
{
$icons = [];
foreach ($this->viewGroups as $group => $views)
{
$i = 0;
if (UtilitiesArrayHelper::check($views))
if (!UtilitiesArrayHelper::check($views))
{
foreach($views as $view)
$icons[$group][] = false;
continue;
}
foreach ($views as $view)
{
$icon = $this->buildIconObject($view);
if ($icon !== null)
{
$add = false;
// external views (links)
if (strpos($view,'||') !== false)
{
$dwd = explode('||', $view);
if (count($dwd) == 3)
{
list($type, $name, $url) = $dwd;
$viewName = $name;
$alt = $name;
$url = $url;
$image = $name . '.' . $type;
$name = 'COM_COMPONENTBUILDER_DASHBOARD_' . StringHelper::safe($name,'U');
}
}
// internal views
elseif (strpos($view,'.') !== false)
{
$dwd = explode('.', $view);
if (count($dwd) == 3)
{
list($type, $name, $action) = $dwd;
}
elseif (count($dwd) == 2)
{
list($type, $name) = $dwd;
$action = false;
}
if ($action)
{
$viewName = $name;
switch($action)
{
case 'add':
$url = 'index.php?option=com_componentbuilder&view=' . $name . '&layout=edit';
$image = $name . '_' . $action. '.' . $type;
$alt = $name . '&nbsp;' . $action;
$name = 'COM_COMPONENTBUILDER_DASHBOARD_'.StringHelper::safe($name,'U').'_ADD';
$add = true;
break;
default:
// check for new convention (more stable)
if (strpos($action, '_qpo0O0oqp_') !== false)
{
list($action, $extension) = (array) explode('_qpo0O0oqp_', $action);
$extension = str_replace('_po0O0oq_', '.', $extension);
}
else
{
$extension = 'com_componentbuilder.' . $name;
}
$url = 'index.php?option=com_categories&view=categories&extension=' . $extension;
$image = $name . '_' . $action . '.' . $type;
$alt = $viewName . '&nbsp;' . $action;
$name = 'COM_COMPONENTBUILDER_DASHBOARD_' . StringHelper::safe($name,'U') . '_' . StringHelper::safe($action,'U');
break;
}
}
else
{
$viewName = $name;
$alt = $name;
$url = 'index.php?option=com_componentbuilder&view=' . $name;
$image = $name . '.' . $type;
$name = 'COM_COMPONENTBUILDER_DASHBOARD_' . StringHelper::safe($name,'U');
$hover = false;
}
}
else
{
$viewName = $view;
$alt = $view;
$url = 'index.php?option=com_componentbuilder&view=' . $view;
$image = $view . '.png';
$name = ucwords($view).'<br /><br />';
$hover = false;
}
// first make sure the view access is set
if (UtilitiesArrayHelper::check($viewAccess))
{
// setup some defaults
$dashboard_add = false;
$dashboard_list = false;
$accessTo = '';
$accessAdd = '';
// access checking start
$accessCreate = (isset($viewAccess[$viewName.'.create'])) ? StringHelper::check($viewAccess[$viewName.'.create']):false;
$accessAccess = (isset($viewAccess[$viewName.'.access'])) ? StringHelper::check($viewAccess[$viewName.'.access']):false;
// set main controllers
$accessDashboard_add = (isset($viewAccess[$viewName.'.dashboard_add'])) ? StringHelper::check($viewAccess[$viewName.'.dashboard_add']):false;
$accessDashboard_list = (isset($viewAccess[$viewName.'.dashboard_list'])) ? StringHelper::check($viewAccess[$viewName.'.dashboard_list']):false;
// check for adding access
if ($add && $accessCreate)
{
$accessAdd = $viewAccess[$viewName.'.create'];
}
elseif ($add)
{
$accessAdd = 'core.create';
}
// check if access to view is set
if ($accessAccess)
{
$accessTo = $viewAccess[$viewName.'.access'];
}
// set main access controllers
if ($accessDashboard_add)
{
$dashboard_add = $user->authorise($viewAccess[$viewName.'.dashboard_add'], 'com_componentbuilder');
}
if ($accessDashboard_list)
{
$dashboard_list = $user->authorise($viewAccess[$viewName.'.dashboard_list'], 'com_componentbuilder');
}
if (StringHelper::check($accessAdd) && StringHelper::check($accessTo))
{
// check access
if($user->authorise($accessAdd, 'com_componentbuilder') && $user->authorise($accessTo, 'com_componentbuilder') && $dashboard_add)
{
$icons[$group][$i] = new \StdClass;
$icons[$group][$i]->url = $url;
$icons[$group][$i]->name = $name;
$icons[$group][$i]->image = $image;
$icons[$group][$i]->alt = $alt;
}
}
elseif (StringHelper::check($accessTo))
{
// check access
if($user->authorise($accessTo, 'com_componentbuilder') && $dashboard_list)
{
$icons[$group][$i] = new \StdClass;
$icons[$group][$i]->url = $url;
$icons[$group][$i]->name = $name;
$icons[$group][$i]->image = $image;
$icons[$group][$i]->alt = $alt;
}
}
elseif (StringHelper::check($accessAdd))
{
// check access
if($user->authorise($accessAdd, 'com_componentbuilder') && $dashboard_add)
{
$icons[$group][$i] = new \StdClass;
$icons[$group][$i]->url = $url;
$icons[$group][$i]->name = $name;
$icons[$group][$i]->image = $image;
$icons[$group][$i]->alt = $alt;
}
}
else
{
$icons[$group][$i] = new \StdClass;
$icons[$group][$i]->url = $url;
$icons[$group][$i]->name = $name;
$icons[$group][$i]->image = $image;
$icons[$group][$i]->alt = $alt;
}
}
else
{
$icons[$group][$i] = new \StdClass;
$icons[$group][$i]->url = $url;
$icons[$group][$i]->name = $name;
$icons[$group][$i]->image = $image;
$icons[$group][$i]->alt = $alt;
}
$i++;
$icons[$group][] = $icon;
}
}
else
{
$icons[$group][$i] = false;
}
}
return $icons;
}
@ -502,13 +377,208 @@ class ComponentbuilderModel extends ListModel
$this->scripts[] = $path;
}
/**
* Build a single dashboard icon if access is granted.
*
* @param string $view The view string to parse.
*
* @return \stdClass|null The icon object or null if access denied.
* @since 5.1.1
*/
protected function buildIconObject(string $view): ?\stdClass
{
$parsed = $this->parseViewDefinition($view);
if (!$parsed)
{
return null;
}
[
'type' => $type,
'name' => $name,
'url' => $url,
'image' => $image,
'alt' => $alt,
'viewName' => $viewName,
'add' => $add,
] = $parsed;
if (!$this->hasAccessToView($viewName, $add))
{
return null;
}
return $this->createIconObject($url, $name, $image, $alt);
}
/**
* Parse a view string into structured components.
*
* @param string $view The view definition string.
*
* @return array<string, mixed>|null Parsed values or null on failure.
* @since 5.1.1
*/
protected function parseViewDefinition(string $view): ?array
{
$add = false;
if (strpos($view, '||') !== false)
{
$parts = explode('||', $view);
if (count($parts) === 3)
{
[$type, $name, $url] = $parts;
return [
'type' => $type,
'name' => 'COM_COMPONENTBUILDER_DASHBOARD_' . StringHelper::safe($name, 'U'),
'url' => $url,
'image' => "{$name}.{$type}",
'alt' => $name,
'viewName' => $name,
'add' => false,
];
}
}
if (strpos($view, '.') !== false)
{
$parts = explode('.', $view);
$type = $parts[0] ?? '';
$name = $parts[1] ?? '';
$action = $parts[2] ?? null;
$viewName = $name;
if ($action)
{
if ($action === 'add')
{
$url = "index.php?option=com_componentbuilder&view={$name}&layout=edit";
$image = "{$name}_{$action}.{$type}";
$alt = "{$name}&nbsp;{$action}";
$name = 'COM_COMPONENTBUILDER_DASHBOARD_' .
StringHelper::safe($name, 'U') . '_ADD';
$add = true;
}
else
{
if (strpos($action, '_qpo0O0oqp_') !== false)
{
[$action, $ext] = explode('_qpo0O0oqp_', $action);
$extension = str_replace('_po0O0oq_', '.', $ext);
}
else
{
$extension = "com_componentbuilder.{$name}";
}
$url = "index.php?option=com_categories&view=categories&extension={$extension}";
$image = "{$name}_{$action}.{$type}";
$alt = "{$name}&nbsp;{$action}";
$name = 'COM_COMPONENTBUILDER_DASHBOARD_' .
StringHelper::safe($name, 'U') . '_' .
StringHelper::safe($action, 'U');
}
}
else
{
$url = "index.php?option=com_componentbuilder&view={$name}";
$image = "{$name}.{$type}";
$alt = $name;
$name = 'COM_COMPONENTBUILDER_DASHBOARD_' .
StringHelper::safe($name, 'U');
}
return compact('type', 'name', 'url', 'image', 'alt', 'viewName', 'add');
}
return [
'type' => 'png',
'name' => ucwords($view) . '<br /><br />',
'url' => "index.php?option=com_componentbuilder&view={$view}",
'image' => "{$view}.png",
'alt' => $view,
'viewName' => $view,
'add' => false,
];
}
/**
* Determine if the user has access to view or create the item.
*
* @param string $viewName The base name of the view.
* @param bool $add If this is an add-action.
*
* @return bool
* @since 5.1.1
*/
protected function hasAccessToView(string $viewName, bool $add): bool
{
$viewAccess = $this->viewAccess;
$accessAdd = $add && isset($viewAccess["{$viewName}.create"])
? $viewAccess["{$viewName}.create"]
: ($add ? 'core.create' : '');
$accessTo = $viewAccess["{$viewName}.access"] ?? '';
$dashboardAdd = isset($viewAccess["{$viewName}.dashboard_add"]) &&
$this->user->authorise($viewAccess["{$viewName}.dashboard_add"], 'com_componentbuilder');
$dashboardList = isset($viewAccess["{$viewName}.dashboard_list"]) &&
$this->user->authorise($viewAccess["{$viewName}.dashboard_list"], 'com_componentbuilder');
if ($add && StringHelper::check($accessAdd))
{
return $this->user->authorise($accessAdd, 'com_componentbuilder') && $dashboardAdd;
}
if (StringHelper::check($accessTo))
{
return $this->user->authorise($accessTo, 'com_componentbuilder') && $dashboardList;
}
return !$accessTo && !$accessAdd;
}
/**
* Create a \stdClass icon object.
*
* @param string $url Icon URL.
* @param string $name Language string or label.
* @param string $image Image filename.
* @param string $alt Alt text.
*
* @return \stdClass
* @since 5.1.1
*/
protected function createIconObject(string $url, string $name, string $image, string $alt): \stdClass
{
$icon = new \stdClass;
$icon->url = $url;
$icon->name = $name;
$icon->image = $image;
$icon->alt = $alt;
return $icon;
}
/**
* Load and display the wiki page content using an AJAX call to the component endpoint.
*
* This method injects an inline JavaScript script that asynchronously fetches the wiki page content
* via a JSON API endpoint in the component. It uses the `marked` library to render markdown content
* and inserts the result into the `wiki-md` container. Errors are displayed in a separate element.
*
* @return string HTML markup including a container for the wiki content and an error message area.
* @since 3.9.0
*/
public function getWiki()
{
// the call URL
// call the ajax get wiki endpoint
$call_url = Uri::base() . 'index.php?option=com_componentbuilder&task=ajax.getWiki&format=json&raw=true&' . Session::getFormToken() . '=1&name=Home';
$document = Factory::getDocument();
$document->addScriptDeclaration('
/** \Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->addInlineScript('
function getWikiPage(){
fetch("' . $call_url . '").then((response) => {
if (response.ok) {
@ -528,13 +598,27 @@ class ComponentbuilderModel extends ListModel
}
/**
* Load and display the component's README file using JavaScript fetch and markdown rendering.
*
* This method injects an inline script into the document that, once the DOM is fully loaded,
* fetches the README.txt file located in the administrator component directory, parses it using
* the `marked` JavaScript library, and inserts the HTML into the `readme-md` div.
*
* @return string HTML markup including a container for the README content and a loading message.
* @since 3.9.0
*/
public function getReadme()
{
$document = Factory::getDocument();
$document->addScriptDeclaration('
var getreadme = "'. Uri::root() . 'administrator/components/com_componentbuilder/README.txt";
// get readme text path
$call_url = Uri::root() . 'administrator/components/com_componentbuilder/README.txt';
/** \Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->addInlineScript('
document.addEventListener("DOMContentLoaded", function () {
fetch(getreadme)
fetch("'. $call_url . '")
.then(response => {
if (!response.ok) {
throw new Error("Network response was not ok");
@ -554,31 +638,45 @@ class ComponentbuilderModel extends ListModel
}
/**
* get Current Version Bay adding JavaScript to the Page
* Inject JavaScript that fetches and displays the current component version status.
*
* @return void
* @since 2.3.0
* This method adds an inline script to the page which asynchronously calls the component's
* AJAX endpoint to check the latest version. It updates the `#component-update-notice` element
* with the fetched version notice or error message.
*
* @return void
* @since 2.3.0
*/
public function getVersion()
{
// the call URL
$call_url = Uri::base() . 'index.php?option=com_componentbuilder&task=ajax.getVersion&format=json&raw=true&' . Session::getFormToken() . '=1&version=1';
$document = Factory::getDocument();
$document->addScriptDeclaration('
function getComponentVersionStatus() {
fetch("' . $call_url . '").then((response) => {
if (response.ok) {
return response.json();
}
}).then((result) => {
if (typeof result.notice !== "undefined") {
document.getElementById("component-update-notice").innerHTML = result.notice;
} else if (typeof result.error !== "undefined") {
document.getElementById("component-update-notice").innerHTML = result.error;
}
});
// call the ajax get version endpoint
$call_url = Uri::base()
. 'index.php?option=com_componentbuilder&task=ajax.getVersion&format=json&raw=true&'
. Session::getFormToken() . '=1&version=1.0.0';
try {
/** \Joomla\CMS\WebAsset\WebAssetManager $wa */
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->addInlineScript('
function getComponentVersionStatus() {
fetch("' . $call_url . '").then((response) => {
if (response.ok) {
return response.json();
}
}).then((result) => {
const target = document.getElementById("component-update-notice");
if (!target) return;
if (typeof result.notice !== "undefined") {
target.innerHTML = result.notice;
} else if (typeof result.error !== "undefined") {
target.innerHTML = result.error;
}
});
}
setTimeout(getComponentVersionStatus, 800);');
} catch (\Throwable $e) {
// we do nothing....
}
setTimeout(getComponentVersionStatus, 800);');
}
}
}