From 2a40a5462250b78a1732e025ca3d65c579e40c73 Mon Sep 17 00:00:00 2001 From: tommaso Date: Tue, 22 Jul 2025 15:41:16 +0200 Subject: [PATCH] first commit --- administrator/access.xml | 13 + administrator/assets/css/circolari.css | 18 ++ administrator/assets/css/index.html | 1 + administrator/assets/images/index.html | 1 + administrator/assets/index.html | 1 + .../com_circolari/services/provider.php | 44 +++ administrator/config.xml | 115 +++++++ administrator/forms/circolare.xml | 30 ++ administrator/forms/filter_circolares.xml | 46 +++ administrator/forms/filter_firmetipi.xml | 43 +++ administrator/forms/firmatipo.xml | 22 ++ administrator/forms/firmetipi.xml | 8 + .../languages/en-GB/com_circolari.ini | 43 +++ .../languages/en-GB/com_circolari.sys.ini | 4 + .../languages/it-IT/com_circolari.ini | 43 +++ .../languages/it-IT/com_circolari.sys.ini | 4 + administrator/presets/content.xml | 101 ++++++ administrator/services/provider.php | 66 ++++ administrator/sql/index.html | 1 + administrator/sql/install.mysql.utf8.sql | 48 +++ administrator/sql/uninstall.mysql.utf8.sql | 1 + administrator/sql/updates/1.0.0.sql | 1 + administrator/sql/xml/mysql.xml | 15 + .../src/Controller/CircolareController.php | 24 ++ .../src/Controller/CircolaresController.php | 116 +++++++ .../src/Controller/DisplayController.php | 48 +++ .../src/Controller/FirmatipoController.php | 24 ++ .../src/Controller/FirmetipiController.php | 116 +++++++ .../src/Extension/CircolariComponent.php | 77 +++++ administrator/src/Field/CreatedbyField.php | 67 ++++ administrator/src/Field/ForeignkeyField.php | 297 ++++++++++++++++++ administrator/src/Field/ModifiedbyField.php | 52 +++ administrator/src/Field/NestedparentField.php | 83 +++++ administrator/src/Field/TimecreatedField.php | 69 ++++ administrator/src/Field/TimeupdatedField.php | 69 ++++ administrator/src/Field/index.html | 1 + administrator/src/Helper/CircolariHelper.php | 77 +++++ administrator/src/Model/CircolareModel.php | 277 ++++++++++++++++ administrator/src/Model/CircolaresModel.php | 208 ++++++++++++ administrator/src/Model/FirmatipoModel.php | 277 ++++++++++++++++ administrator/src/Model/FirmetipiModel.php | 195 ++++++++++++ administrator/src/Service/Html/CIRCOLARI.php | 53 ++++ administrator/src/Table/CircolareTable.php | 279 ++++++++++++++++ administrator/src/Table/FirmatipoTable.php | 279 ++++++++++++++++ administrator/src/View/Circolare/HtmlView.php | 114 +++++++ .../src/View/Circolares/HtmlView.php | 183 +++++++++++ administrator/src/View/Firmatipo/HtmlView.php | 114 +++++++ administrator/src/View/Firmetipi/HtmlView.php | 177 +++++++++++ administrator/tmpl/circolare/default.php | 32 ++ administrator/tmpl/circolare/edit.php | 52 +++ administrator/tmpl/circolares/default.php | 148 +++++++++ administrator/tmpl/firmatipo/default.php | 32 ++ administrator/tmpl/firmatipo/edit.php | 55 ++++ administrator/tmpl/firmetipi/default.php | 47 +++ administrator/tmpl/firmetipi/edit.php | 30 ++ administrator/tmpl/index.html | 1 + circolari.xml | 91 ++++++ installer/index.html | 1 + media/css/admin.css | 11 + media/css/list.css | 7 + media/joomla.asset.json | 29 ++ media/js/admin.js | 32 ++ site/forms/index.html | 1 + site/languages/en-GB/com_circolari.ini | 43 +++ site/languages/it-IT/com_circolari.ini | 43 +++ site/src/Controller/DisplayController.php | 64 ++++ site/src/Field/CreatedbyField.php | 67 ++++ site/src/Field/ForeignkeyField.php | 296 +++++++++++++++++ site/src/Field/ModifiedbyField.php | 53 ++++ site/src/Field/NestedparentField.php | 83 +++++ site/src/Field/SubmitField.php | 49 +++ site/src/Field/TimecreatedField.php | 65 ++++ site/src/Field/TimeupdatedField.php | 68 ++++ site/src/Field/index.html | 1 + site/src/Helper/CircolariHelper.php | 71 +++++ site/src/Helper/index.html | 1 + site/src/Service/Category.php | 21 ++ site/src/Service/Router.php | 95 ++++++ site/tmpl/index.html | 1 + .../src/Controller/INTERNAL_NAME_list.php | 37 +++ .../View/INTERNAL_NAME_list/JsonapiView.php | 42 +++ 81 files changed, 5614 insertions(+) create mode 100644 administrator/access.xml create mode 100644 administrator/assets/css/circolari.css create mode 100644 administrator/assets/css/index.html create mode 100644 administrator/assets/images/index.html create mode 100644 administrator/assets/index.html create mode 100644 administrator/components/com_circolari/services/provider.php create mode 100644 administrator/config.xml create mode 100644 administrator/forms/circolare.xml create mode 100644 administrator/forms/filter_circolares.xml create mode 100644 administrator/forms/filter_firmetipi.xml create mode 100644 administrator/forms/firmatipo.xml create mode 100644 administrator/forms/firmetipi.xml create mode 100644 administrator/languages/en-GB/com_circolari.ini create mode 100644 administrator/languages/en-GB/com_circolari.sys.ini create mode 100644 administrator/languages/it-IT/com_circolari.ini create mode 100644 administrator/languages/it-IT/com_circolari.sys.ini create mode 100644 administrator/presets/content.xml create mode 100644 administrator/services/provider.php create mode 100644 administrator/sql/index.html create mode 100644 administrator/sql/install.mysql.utf8.sql create mode 100644 administrator/sql/uninstall.mysql.utf8.sql create mode 100644 administrator/sql/updates/1.0.0.sql create mode 100644 administrator/sql/xml/mysql.xml create mode 100644 administrator/src/Controller/CircolareController.php create mode 100644 administrator/src/Controller/CircolaresController.php create mode 100644 administrator/src/Controller/DisplayController.php create mode 100644 administrator/src/Controller/FirmatipoController.php create mode 100644 administrator/src/Controller/FirmetipiController.php create mode 100644 administrator/src/Extension/CircolariComponent.php create mode 100644 administrator/src/Field/CreatedbyField.php create mode 100644 administrator/src/Field/ForeignkeyField.php create mode 100644 administrator/src/Field/ModifiedbyField.php create mode 100644 administrator/src/Field/NestedparentField.php create mode 100644 administrator/src/Field/TimecreatedField.php create mode 100644 administrator/src/Field/TimeupdatedField.php create mode 100644 administrator/src/Field/index.html create mode 100644 administrator/src/Helper/CircolariHelper.php create mode 100644 administrator/src/Model/CircolareModel.php create mode 100644 administrator/src/Model/CircolaresModel.php create mode 100644 administrator/src/Model/FirmatipoModel.php create mode 100644 administrator/src/Model/FirmetipiModel.php create mode 100644 administrator/src/Service/Html/CIRCOLARI.php create mode 100644 administrator/src/Table/CircolareTable.php create mode 100644 administrator/src/Table/FirmatipoTable.php create mode 100644 administrator/src/View/Circolare/HtmlView.php create mode 100644 administrator/src/View/Circolares/HtmlView.php create mode 100644 administrator/src/View/Firmatipo/HtmlView.php create mode 100644 administrator/src/View/Firmetipi/HtmlView.php create mode 100644 administrator/tmpl/circolare/default.php create mode 100644 administrator/tmpl/circolare/edit.php create mode 100644 administrator/tmpl/circolares/default.php create mode 100644 administrator/tmpl/firmatipo/default.php create mode 100644 administrator/tmpl/firmatipo/edit.php create mode 100644 administrator/tmpl/firmetipi/default.php create mode 100644 administrator/tmpl/firmetipi/edit.php create mode 100644 administrator/tmpl/index.html create mode 100644 circolari.xml create mode 100644 installer/index.html create mode 100644 media/css/admin.css create mode 100644 media/css/list.css create mode 100644 media/joomla.asset.json create mode 100644 media/js/admin.js create mode 100644 site/forms/index.html create mode 100644 site/languages/en-GB/com_circolari.ini create mode 100644 site/languages/it-IT/com_circolari.ini create mode 100644 site/src/Controller/DisplayController.php create mode 100644 site/src/Field/CreatedbyField.php create mode 100644 site/src/Field/ForeignkeyField.php create mode 100644 site/src/Field/ModifiedbyField.php create mode 100644 site/src/Field/NestedparentField.php create mode 100644 site/src/Field/SubmitField.php create mode 100644 site/src/Field/TimecreatedField.php create mode 100644 site/src/Field/TimeupdatedField.php create mode 100644 site/src/Field/index.html create mode 100644 site/src/Helper/CircolariHelper.php create mode 100644 site/src/Helper/index.html create mode 100644 site/src/Service/Category.php create mode 100644 site/src/Service/Router.php create mode 100644 site/tmpl/index.html create mode 100644 webservices/src/Controller/INTERNAL_NAME_list.php create mode 100644 webservices/src/View/INTERNAL_NAME_list/JsonapiView.php diff --git a/administrator/access.xml b/administrator/access.xml new file mode 100644 index 0000000..beb5b7a --- /dev/null +++ b/administrator/access.xml @@ -0,0 +1,13 @@ + + +
+ + + + + + + +
+ +
\ No newline at end of file diff --git a/administrator/assets/css/circolari.css b/administrator/assets/css/circolari.css new file mode 100644 index 0000000..5e8f5a9 --- /dev/null +++ b/administrator/assets/css/circolari.css @@ -0,0 +1,18 @@ +.icon-48-circolares { + background-image: url(../images/l_circolares.png); + padding-left:60px!important; +} + +.icon-48-circolare { + background-image: url(../images/l_circolares.png); + padding-left:60px!important; +} + +.color-box-circolares { + float: left; width: 15px; height: 15px; margin-right: 5px; border: 1px solid rgba(0, 0, 0, .2);} + + + +.other-filters{ + padding: 0 14px; +} \ No newline at end of file diff --git a/administrator/assets/css/index.html b/administrator/assets/css/index.html new file mode 100644 index 0000000..42682b4 --- /dev/null +++ b/administrator/assets/css/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/assets/images/index.html b/administrator/assets/images/index.html new file mode 100644 index 0000000..42682b4 --- /dev/null +++ b/administrator/assets/images/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/assets/index.html b/administrator/assets/index.html new file mode 100644 index 0000000..42682b4 --- /dev/null +++ b/administrator/assets/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/components/com_circolari/services/provider.php b/administrator/components/com_circolari/services/provider.php new file mode 100644 index 0000000..e79c5a2 --- /dev/null +++ b/administrator/components/com_circolari/services/provider.php @@ -0,0 +1,44 @@ + +get(ComponentDispatcherFactoryInterface::class) + ->createDispatcher('com_circolari') + ->registerView('circolares', \Pcrt\Component\Circolari\Administrator\View\Circolares\HtmlView::class) + ->registerView('firmetipi', \Pcrt\Component\Circolari\Administrator\View\Firmetipi\HtmlView::class); + } +} diff --git a/administrator/config.xml b/administrator/config.xml new file mode 100644 index 0000000..9fe1aca --- /dev/null +++ b/administrator/config.xml @@ -0,0 +1,115 @@ + + +
+ +
+ +
+ +
+ +
+ + + + + + + + + + + + + +
+
+ diff --git a/administrator/forms/circolare.xml b/administrator/forms/circolare.xml new file mode 100644 index 0000000..43ab7ef --- /dev/null +++ b/administrator/forms/circolare.xml @@ -0,0 +1,30 @@ + +
+
+ + + + + + + + + + +
+ +
+ + + + + +
+
diff --git a/administrator/forms/filter_circolares.xml b/administrator/forms/filter_circolares.xml new file mode 100644 index 0000000..bc0a638 --- /dev/null +++ b/administrator/forms/filter_circolares.xml @@ -0,0 +1,46 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/administrator/forms/filter_firmetipi.xml b/administrator/forms/filter_firmetipi.xml new file mode 100644 index 0000000..561a919 --- /dev/null +++ b/administrator/forms/filter_firmetipi.xml @@ -0,0 +1,43 @@ + +
+ + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/administrator/forms/firmatipo.xml b/administrator/forms/firmatipo.xml new file mode 100644 index 0000000..e6f65f5 --- /dev/null +++ b/administrator/forms/firmatipo.xml @@ -0,0 +1,22 @@ + +
+
+ + + + + + + + + + +
+
diff --git a/administrator/forms/firmetipi.xml b/administrator/forms/firmetipi.xml new file mode 100644 index 0000000..074463d --- /dev/null +++ b/administrator/forms/firmetipi.xml @@ -0,0 +1,8 @@ + + +
+
+ + +
+
diff --git a/administrator/languages/en-GB/com_circolari.ini b/administrator/languages/en-GB/com_circolari.ini new file mode 100644 index 0000000..793487c --- /dev/null +++ b/administrator/languages/en-GB/com_circolari.ini @@ -0,0 +1,43 @@ +COM_CIRCOLARI = "Circolari" +COM_CIRCOLARI_ITEM_SAVED_SUCCESSFULLY = "Item saved successfully" +COM_CIRCOLARI_ITEM_DELETED_SUCCESSFULLY = "Item deleted successfully" +COM_CIRCOLARI_ITEM_DELETED_UNSUCCESSFULLY = "Could not delete item" +COM_CIRCOLARI_ITEM_DOESNT_EXIST = "Item does not exist" +COM_CIRCOLARI_ITEM_NOT_LOADED = "Could not load the item" +COM_CIRCOLARI_VIEW_FILE = "[View File]" +COM_CIRCOLARI_ADD_ITEM = "Add" +COM_CIRCOLARI_EDIT_ITEM = "Edit" +COM_CIRCOLARI_DELETE_ITEM = "Delete" +COM_CIRCOLARI_DELETE_MESSAGE = "Are you sure that you want delete this item?" +COM_CIRCOLARI_DELETE_CONFIRM = "You're about to delete the item #%s. Are you sure?" +COM_CIRCOLARI_PUBLISH_ITEM = "Publish" +COM_CIRCOLARI_UNPUBLISH_ITEM = "Unpublish" +COM_CIRCOLARI_NO_ITEMS = "There are no items in the list" +COM_CIRCOLARI_SEARCH_TOOLS = "Search Tools" +COM_CIRCOLARI_SEARCH_TOOLS_DESC = "" +COM_CIRCOLARI_SEARCH_FILTER_SUBMIT = "Search" +COM_CIRCOLARI_SEARCH_FILTER_CLEAR = "Clear" +COM_CIRCOLARI_SEARCH_FILTER_DATE_FORMAT = "Dates should be in this format: \"YYYY-MM-DD\". Some filter fields have been ignored." + +COM_CIRCOLARI_ERROR_MESSAGE_NOT_AUTHORISED = "You don't have permission to access this. Please contact a website administrator if this is incorrect." + +COM_CIRCOLARI_ADD_ITEM_TITLE = "Add" +COM_CIRCOLARI_EDIT_ITEM_TITLE = "Edit %s" + +COM_CIRCOLARI_ACTION_PERMISSIONS_LABEL = "Permissions" +COM_CIRCOLARI_VALIDATION_FORM_FAILED = "Invalid form" +COM_CIRCOLARI_CHECKEDIN_SUCCESSFULLY = "Item successfully checked in" + + +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_ID="ID" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_STATE="State" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_ORDERING="Order" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_CHECKED_OUT="N/A" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_CHECKED_OUT_TIME="N/A" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_CREATED_BY="Created by" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_MODIFIED_BY="Modified by" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_TITLE="Title" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_DESCRIPTION="Description" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_ATTACHMENT="Attachment" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_IMAGE="Image" + diff --git a/administrator/languages/en-GB/com_circolari.sys.ini b/administrator/languages/en-GB/com_circolari.sys.ini new file mode 100644 index 0000000..fe75b51 --- /dev/null +++ b/administrator/languages/en-GB/com_circolari.sys.ini @@ -0,0 +1,4 @@ +COM_CIRCOLARI = "Circolari" +COM_CIRCOLARI_XML_DESCRIPTION = "" + +COM_CIRCOLARI_TITLE_CIRCOLARES="Circolari" diff --git a/administrator/languages/it-IT/com_circolari.ini b/administrator/languages/it-IT/com_circolari.ini new file mode 100644 index 0000000..793487c --- /dev/null +++ b/administrator/languages/it-IT/com_circolari.ini @@ -0,0 +1,43 @@ +COM_CIRCOLARI = "Circolari" +COM_CIRCOLARI_ITEM_SAVED_SUCCESSFULLY = "Item saved successfully" +COM_CIRCOLARI_ITEM_DELETED_SUCCESSFULLY = "Item deleted successfully" +COM_CIRCOLARI_ITEM_DELETED_UNSUCCESSFULLY = "Could not delete item" +COM_CIRCOLARI_ITEM_DOESNT_EXIST = "Item does not exist" +COM_CIRCOLARI_ITEM_NOT_LOADED = "Could not load the item" +COM_CIRCOLARI_VIEW_FILE = "[View File]" +COM_CIRCOLARI_ADD_ITEM = "Add" +COM_CIRCOLARI_EDIT_ITEM = "Edit" +COM_CIRCOLARI_DELETE_ITEM = "Delete" +COM_CIRCOLARI_DELETE_MESSAGE = "Are you sure that you want delete this item?" +COM_CIRCOLARI_DELETE_CONFIRM = "You're about to delete the item #%s. Are you sure?" +COM_CIRCOLARI_PUBLISH_ITEM = "Publish" +COM_CIRCOLARI_UNPUBLISH_ITEM = "Unpublish" +COM_CIRCOLARI_NO_ITEMS = "There are no items in the list" +COM_CIRCOLARI_SEARCH_TOOLS = "Search Tools" +COM_CIRCOLARI_SEARCH_TOOLS_DESC = "" +COM_CIRCOLARI_SEARCH_FILTER_SUBMIT = "Search" +COM_CIRCOLARI_SEARCH_FILTER_CLEAR = "Clear" +COM_CIRCOLARI_SEARCH_FILTER_DATE_FORMAT = "Dates should be in this format: \"YYYY-MM-DD\". Some filter fields have been ignored." + +COM_CIRCOLARI_ERROR_MESSAGE_NOT_AUTHORISED = "You don't have permission to access this. Please contact a website administrator if this is incorrect." + +COM_CIRCOLARI_ADD_ITEM_TITLE = "Add" +COM_CIRCOLARI_EDIT_ITEM_TITLE = "Edit %s" + +COM_CIRCOLARI_ACTION_PERMISSIONS_LABEL = "Permissions" +COM_CIRCOLARI_VALIDATION_FORM_FAILED = "Invalid form" +COM_CIRCOLARI_CHECKEDIN_SUCCESSFULLY = "Item successfully checked in" + + +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_ID="ID" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_STATE="State" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_ORDERING="Order" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_CHECKED_OUT="N/A" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_CHECKED_OUT_TIME="N/A" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_CREATED_BY="Created by" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_MODIFIED_BY="Modified by" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_TITLE="Title" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_DESCRIPTION="Description" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_ATTACHMENT="Attachment" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_IMAGE="Image" + diff --git a/administrator/languages/it-IT/com_circolari.sys.ini b/administrator/languages/it-IT/com_circolari.sys.ini new file mode 100644 index 0000000..fe75b51 --- /dev/null +++ b/administrator/languages/it-IT/com_circolari.sys.ini @@ -0,0 +1,4 @@ +COM_CIRCOLARI = "Circolari" +COM_CIRCOLARI_XML_DESCRIPTION = "" + +COM_CIRCOLARI_TITLE_CIRCOLARES="Circolari" diff --git a/administrator/presets/content.xml b/administrator/presets/content.xml new file mode 100644 index 0000000..214cf4c --- /dev/null +++ b/administrator/presets/content.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/administrator/services/provider.php b/administrator/services/provider.php new file mode 100644 index 0000000..5f48759 --- /dev/null +++ b/administrator/services/provider.php @@ -0,0 +1,66 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +defined('_JEXEC') or die; + +use Joomla\CMS\Categories\CategoryFactoryInterface; +use Joomla\CMS\Component\Router\RouterFactoryInterface; +use Joomla\CMS\Dispatcher\ComponentDispatcherFactoryInterface; +use Joomla\CMS\Extension\ComponentInterface; +use Joomla\CMS\Extension\Service\Provider\CategoryFactory; +use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory; +use Joomla\CMS\Extension\Service\Provider\MVCFactory; +use Joomla\CMS\Extension\Service\Provider\RouterFactory; +use Joomla\CMS\HTML\Registry; +use Joomla\CMS\MVC\Factory\MVCFactoryInterface; +use Pcrt\Component\Circolari\Administrator\Extension\CircolariComponent; +use Joomla\DI\Container; +use Joomla\DI\ServiceProviderInterface; + + +/** + * The Circolari service provider. + * + * @since 1.0.0 + */ +return new class implements ServiceProviderInterface +{ + /** + * Registers the service provider with a DI container. + * + * @param Container $container The DI container. + * + * @return void + * + * @since 1.0.0 + */ + public function register(Container $container) + { + + $container->registerServiceProvider(new CategoryFactory('\\Pcrt\\Component\\Circolari')); + $container->registerServiceProvider(new MVCFactory('\\Pcrt\\Component\\Circolari')); + $container->registerServiceProvider(new ComponentDispatcherFactory('\\Pcrt\\Component\\Circolari')); + $container->registerServiceProvider(new RouterFactory('\\Pcrt\\Component\\Circolari')); + + $container->set( + ComponentInterface::class, + function (Container $container) + { + $component = new CircolariComponent($container->get(ComponentDispatcherFactoryInterface::class)); + + $component->setRegistry($container->get(Registry::class)); + $component->setMVCFactory($container->get(MVCFactoryInterface::class)); + $component->setCategoryFactory($container->get(CategoryFactoryInterface::class)); + $component->setRouterFactory($container->get(RouterFactoryInterface::class)); + + return $component; + } + ); + } +}; diff --git a/administrator/sql/index.html b/administrator/sql/index.html new file mode 100644 index 0000000..42682b4 --- /dev/null +++ b/administrator/sql/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/sql/install.mysql.utf8.sql b/administrator/sql/install.mysql.utf8.sql new file mode 100644 index 0000000..f663eb9 --- /dev/null +++ b/administrator/sql/install.mysql.utf8.sql @@ -0,0 +1,48 @@ +CREATE TABLE IF NOT EXISTS `#__circolari` ( +`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, + +`state` TINYINT(1) NULL DEFAULT 1, +`ordering` INT(11) NULL DEFAULT 0, +`checked_out` INT(11) UNSIGNED, +`checked_out_time` DATETIME NULL DEFAULT NULL , +`created_by` INT(11) NULL DEFAULT 0, +`modified_by` INT(11) NULL DEFAULT 0, +`title` VARCHAR(255) NULL DEFAULT "", +`description` TEXT NULL , +`attachment` VARCHAR(255) NULL DEFAULT "", +`image` VARCHAR(255) NULL DEFAULT "", +PRIMARY KEY (`id`) +,KEY `idx_state` (`state`) +,KEY `idx_checked_out` (`checked_out`) +,KEY `idx_created_by` (`created_by`) +,KEY `idx_modified_by` (`modified_by`) +) DEFAULT COLLATE=utf8mb4_unicode_ci; + + + +-- Aggiunta campi extra alla tabella circolari +ALTER TABLE `#__circolari` +ADD COLUMN `tipologia_firma` ENUM('presa_visione','aderisco','non_aderisco','non_in_servizio') DEFAULT 'presa_visione', +ADD COLUMN `firma_obbligatoria` TINYINT(1) DEFAULT 0, +ADD COLUMN `scadenza` DATE DEFAULT NULL; + +-- Creazione tabella firme se non esiste +CREATE TABLE IF NOT EXISTS `#__circolari_firme` ( + `id` INT NOT NULL AUTO_INCREMENT, + `circolare_id` INT NOT NULL, + `user_id` INT NOT NULL, + `firma` ENUM('presa_visione','aderisco','non_aderisco','non_in_servizio') NOT NULL, + `data_firma` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `firma_unica` (`circolare_id`, `user_id`) +); + + +-- Tabella delle tipologie di firma (per gestione dinamica) +CREATE TABLE IF NOT EXISTS `#__circolari_firmetipi` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `nome` VARCHAR(100) NOT NULL, + `descrizione` TEXT DEFAULT NULL, + `state` TINYINT(1) DEFAULT 1, + PRIMARY KEY (`id`) +); diff --git a/administrator/sql/uninstall.mysql.utf8.sql b/administrator/sql/uninstall.mysql.utf8.sql new file mode 100644 index 0000000..914e2bb --- /dev/null +++ b/administrator/sql/uninstall.mysql.utf8.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS `#__circolari`; diff --git a/administrator/sql/updates/1.0.0.sql b/administrator/sql/updates/1.0.0.sql new file mode 100644 index 0000000..85ecc6e --- /dev/null +++ b/administrator/sql/updates/1.0.0.sql @@ -0,0 +1 @@ +/* Only premium users are allowed to update a component */ \ No newline at end of file diff --git a/administrator/sql/xml/mysql.xml b/administrator/sql/xml/mysql.xml new file mode 100644 index 0000000..b10de3f --- /dev/null +++ b/administrator/sql/xml/mysql.xml @@ -0,0 +1,15 @@ + + + + + + + mysql + mysqli + pdomysql + + + + + + \ No newline at end of file diff --git a/administrator/src/Controller/CircolareController.php b/administrator/src/Controller/CircolareController.php new file mode 100644 index 0000000..cb630e9 --- /dev/null +++ b/administrator/src/Controller/CircolareController.php @@ -0,0 +1,24 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Controller; + +\defined('_JEXEC') or die; + +use Joomla\CMS\MVC\Controller\FormController; + +/** + * Circolare controller class. + * + * @since 1.0.0 + */ +class CircolareController extends FormController +{ + protected $view_list = 'circolares'; +} diff --git a/administrator/src/Controller/CircolaresController.php b/administrator/src/Controller/CircolaresController.php new file mode 100644 index 0000000..e6ff80e --- /dev/null +++ b/administrator/src/Controller/CircolaresController.php @@ -0,0 +1,116 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Controller; + +\defined('_JEXEC') or die; + +use Joomla\CMS\Application\SiteApplication; +use Joomla\CMS\Factory; +use Joomla\CMS\Language\Multilanguage; +use Joomla\CMS\Language\Text; +use Joomla\CMS\MVC\Controller\AdminController; +use Joomla\CMS\Router\Route; +use Joomla\CMS\Uri\Uri; +use Joomla\Utilities\ArrayHelper; + +/** + * Circolares list controller class. + * + * @since 1.0.0 + */ +class CircolaresController extends AdminController +{ + /** + * Method to clone existing Circolares + * + * @return void + * + * @throws Exception + */ + public function duplicate() + { + // Check for request forgeries + $this->checkToken(); + + // Get id(s) + $pks = $this->input->post->get('cid', array(), 'array'); + + try + { + if (empty($pks)) + { + throw new \Exception(Text::_('COM_CIRCOLARI_NO_ELEMENT_SELECTED')); + } + + ArrayHelper::toInteger($pks); + $model = $this->getModel(); + $model->duplicate($pks); + $this->setMessage(Text::_('COM_CIRCOLARI_ITEMS_SUCCESS_DUPLICATED')); + } + catch (\Exception $e) + { + Factory::getApplication()->enqueueMessage($e->getMessage(), 'warning'); + } + + $this->setRedirect('index.php?option=com_circolari&view=circolares'); + } + + /** + * Proxy for getModel. + * + * @param string $name Optional. Model name + * @param string $prefix Optional. Class prefix + * @param array $config Optional. Configuration array for model + * + * @return object The Model + * + * @since 1.0.0 + */ + public function getModel($name = 'Circolare', $prefix = 'Administrator', $config = array()) + { + return parent::getModel($name, $prefix, array('ignore_request' => true)); + } + + + + /** + * Method to save the submitted ordering values for records via AJAX. + * + * @return void + * + * @since 1.0.0 + * + * @throws Exception + */ + public function saveOrderAjax() + { + // Get the input + $pks = $this->input->post->get('cid', array(), 'array'); + $order = $this->input->post->get('order', array(), 'array'); + + // Sanitize the input + ArrayHelper::toInteger($pks); + ArrayHelper::toInteger($order); + + // Get the model + $model = $this->getModel(); + + // Save the ordering + $return = $model->saveorder($pks, $order); + + if ($return) + { + echo "1"; + } + + // Close the application + Factory::getApplication()->close(); + } +} diff --git a/administrator/src/Controller/DisplayController.php b/administrator/src/Controller/DisplayController.php new file mode 100644 index 0000000..544de51 --- /dev/null +++ b/administrator/src/Controller/DisplayController.php @@ -0,0 +1,48 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Controller; + +\defined('_JEXEC') or die; + +use Joomla\CMS\Language\Text; +use Joomla\CMS\MVC\Controller\BaseController; +use Joomla\CMS\Router\Route; + +/** + * Circolari master display controller. + * + * @since 1.0.0 + */ +class DisplayController extends BaseController +{ + /** + * The default view. + * + * @var string + * @since 1.0.0 + */ + protected $default_view = 'circolari'; + + /** + * Method to display a view. + * + * @param boolean $cachable If true, the view output will be cached + * @param array $urlparams An array of safe URL parameters and their variable types, for valid values see {@link InputFilter::clean()}. + * + * @return BaseController|boolean This object to support chaining. + * + * @since 1.0.0 + */ + public function display($cachable = false, $urlparams = array()) + { + return parent::display(); + } +} \ No newline at end of file diff --git a/administrator/src/Controller/FirmatipoController.php b/administrator/src/Controller/FirmatipoController.php new file mode 100644 index 0000000..7c9548e --- /dev/null +++ b/administrator/src/Controller/FirmatipoController.php @@ -0,0 +1,24 @@ + + * @copyright 2024 Eddy Prosperi + * @license GNU General Public License versione 2 o successiva; vedi LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Controller; + +\defined('_JEXEC') or die; + +use Joomla\CMS\MVC\Controller\FormController; + +/** + * Etichetta Firmatipo controller class. + * + * @since 1.0.0 + */ +class FirmatipoController extends FormController +{ + protected $view_list = 'firmetipi'; +} diff --git a/administrator/src/Controller/FirmetipiController.php b/administrator/src/Controller/FirmetipiController.php new file mode 100644 index 0000000..21361ea --- /dev/null +++ b/administrator/src/Controller/FirmetipiController.php @@ -0,0 +1,116 @@ + + * @copyright 2024 Eddy Prosperi + * @license GNU General Public License versione 2 o successiva; vedi LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Controller; + +\defined('_JEXEC') or die; + +use Joomla\CMS\Application\SiteApplication; +use Joomla\CMS\Factory; +use Joomla\CMS\Language\Multilanguage; +use Joomla\CMS\Language\Text; +use Joomla\CMS\MVC\Controller\AdminController; +use Joomla\CMS\Router\Route; +use Joomla\CMS\Uri\Uri; +use Joomla\Utilities\ArrayHelper; + +/** + * Etichette list Firmetipi controller class. + * + * @since 1.0.0 + */ +class FirmetipiController extends AdminController +{ + /** + * Method to clone existing Etichette + * + * @return void + * + * @throws Exception + */ + public function duplicate() + { + // Check for request forgeries + $this->checkToken(); + + // Get id(s) + $pks = $this->input->post->get('cid', array(), 'array'); + + try + { + if (empty($pks)) + { + throw new \Exception(Text::_('COM_HIGHLIGHTS_NO_ELEMENT_SELECTED')); + } + + ArrayHelper::toInteger($pks); + $model = $this->getModel(); + $model->duplicate($pks); + $this->setMessage(Text::_('COM_HIGHLIGHTS_ITEMS_SUCCESS_DUPLICATED')); + } + catch (\Exception $e) + { + Factory::getApplication()->enqueueMessage($e->getMessage(), 'warning'); + } + + $this->setRedirect('index.php?option=com_circolari&view=firmetipi'); + } + + /** + * Proxy for getModel. + * + * @param string $name Optional. Model name + * @param string $prefix Optional. Class prefix + * @param array $config Optional. Configuration array for model + * + * @return object The Model + * + * @since 1.0.0 + */ + public function getModel($name = 'FirmaTipo', $prefix = 'Administrator', $config = array()) + { + return parent::getModel($name, $prefix, array('ignore_request' => true)); + } + + + + /** + * Method to save the submitted ordering values for records via AJAX. + * + * @return void + * + * @since 1.0.0 + * + * @throws Exception + */ + public function saveOrderAjax() + { + // Get the input + $pks = $this->input->post->get('cid', array(), 'array'); + $order = $this->input->post->get('order', array(), 'array'); + + // Sanitize the input + ArrayHelper::toInteger($pks); + ArrayHelper::toInteger($order); + + // Get the model + $model = $this->getModel(); + + // Save the ordering + $return = $model->saveorder($pks, $order); + + if ($return) + { + echo "1"; + } + + // Close the application + Factory::getApplication()->close(); + } +} diff --git a/administrator/src/Extension/CircolariComponent.php b/administrator/src/Extension/CircolariComponent.php new file mode 100644 index 0000000..8a78b7b --- /dev/null +++ b/administrator/src/Extension/CircolariComponent.php @@ -0,0 +1,77 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Extension; + +defined('JPATH_PLATFORM') or die; + +use Pcrt\Component\Circolari\Administrator\Service\Html\CIRCOLARI; +use Joomla\CMS\Application\SiteApplication; +use Joomla\CMS\Association\AssociationServiceInterface; +use Joomla\CMS\Association\AssociationServiceTrait; +use Joomla\CMS\Categories\CategoryServiceTrait; +use Joomla\CMS\Component\Router\RouterServiceInterface; +use Joomla\CMS\Component\Router\RouterServiceTrait; +use Joomla\CMS\Extension\BootableExtensionInterface; +use Joomla\CMS\Extension\MVCComponent; +use Joomla\CMS\HTML\HTMLRegistryAwareTrait; +use Joomla\CMS\Tag\TagServiceTrait; +use Psr\Container\ContainerInterface; +use Joomla\CMS\Categories\CategoryServiceInterface; + +/** + * Component class for Circolari + * + * @since 1.0.0 + */ +class CircolariComponent extends MVCComponent implements RouterServiceInterface, BootableExtensionInterface, CategoryServiceInterface +{ + use AssociationServiceTrait; + use RouterServiceTrait; + use HTMLRegistryAwareTrait; + use CategoryServiceTrait, TagServiceTrait { + CategoryServiceTrait::getTableNameForSection insteadof TagServiceTrait; + CategoryServiceTrait::getStateColumnForSection insteadof TagServiceTrait; + } + + /** @inheritdoc */ + public function boot(ContainerInterface $container) + { + $db = $container->get('DatabaseDriver'); + $this->getRegistry()->register('circolari', new CIRCOLARI($db)); + } + + +/** + * Returns the table for the count items functions for the given section. + * + * @param string The section + * + * * @return string|null + * + * @since 4.0.0 + */ + protected function getTableNameForSection(?string $section = null) + { + } + + /** + * Adds Count Items for Category Manager. + * + * @param \stdClass[] $items The category objects + * @param string $section The section + * + * @return void + * + * @since 4.0.0 + */ + public function countItems(array $items, string $section) + { + } +} \ No newline at end of file diff --git a/administrator/src/Field/CreatedbyField.php b/administrator/src/Field/CreatedbyField.php new file mode 100644 index 0000000..cb4e0f1 --- /dev/null +++ b/administrator/src/Field/CreatedbyField.php @@ -0,0 +1,67 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Field; + +defined('JPATH_BASE') or die; + +use \Joomla\CMS\Factory; +use \Joomla\CMS\Form\FormField; +use \Joomla\CMS\User\UserFactoryInterface; + +/** + * Supports an HTML select list of categories + * + * @since 1.0.0 + */ +class CreatedbyField extends FormField +{ + /** + * The form field type. + * + * @var tring + * @since 1.0.0 + */ + protected $type = 'createdby'; + + /** + * Method to get the field input markup. + * + * @return string The field input markup. + * + * @since 1.0.0 + */ + protected function getInput() + { + // Initialize variables. + $html = array(); + + // Load user + $user_id = $this->value; + + if ($user_id) + { + $container = \Joomla\CMS\Factory::getContainer(); + $userFactory = $container->get(UserFactoryInterface::class); + $user = $userFactory->loadUserById($user_id); + } + else + { + $user = Factory::getApplication()->getIdentity(); + $html[] = ''; + } + + if (!$this->hidden) + { + $html[] = "
" . $user->name . " (" . $user->username . ")
"; + } + + return implode($html); + } +} diff --git a/administrator/src/Field/ForeignkeyField.php b/administrator/src/Field/ForeignkeyField.php new file mode 100644 index 0000000..5014a2a --- /dev/null +++ b/administrator/src/Field/ForeignkeyField.php @@ -0,0 +1,297 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Field; + +defined('JPATH_BASE') or die; + +use \Joomla\CMS\Factory; +use \Joomla\CMS\HTML\HTMLHelper; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Form\Field\ListField; + +/** + * Supports a value from an external table + * + * @since 1.0.0 + */ +#[\AllowDynamicProperties] + class ForeignKeyField extends ListField +{ + /** + * The form field type. + * + * @var string + * @since 1.0.0 + */ + protected $type = 'foreignkey'; + + protected $layout = 'joomla.form.field.list-fancy-select'; + + /** + * The translate. + * + * @var boolean + * @since 1.0.0 + */ + protected $translate = true; + + protected $header = false; + + private $input_type; + + private $table; + + private $key_field; + + private $value_field; + + private $option_key_field; + + private $option_value_field; + + private $condition; + + /** + * Method to get the field input markup. + * + * @return string The field input markup. + * + * @since 1.0.0 + */ + protected function processQuery() + { + // Type of input the field shows + $this->input_type = $this->getAttribute('input_type'); + + // Database Table + $this->table = $this->getAttribute('table'); + + // The field that the field will save on the database + $this->key_field = (string) $this->getAttribute('key_field'); + + // The column that the field shows in the input + $this->value_field = (string) $this->getAttribute('value_field'); + + // The option field that the field will save on the database + $this->option_key_field = (string) $this->getAttribute('option_key_field'); + + // The option value that the field shows in the input + $this->option_value_field = (string) $this->getAttribute('option_value_field'); + + // Flag to identify if the fk_value is multiple + $this->value_multiple = (int) $this->getAttribute('value_multiple', 0); + + $this->required = (string) $this->getAttribute('required', 0); + + // Flag to identify if the fk_value hides the trashed items + $this->hideTrashed = (int) $this->getAttribute('hide_trashed', 0); + + // Flag to identify if the fk_value hides the unpublished items + $this->hideUnpublished = (int) $this->getAttribute('hide_unpublished', 0); + + // Flag to identify if the fk_value hides the published items + $this->hidePublished = (int) $this->getAttribute('hide_published', 0); + + // Flag to identify if the fk_value hides the archived items + $this->hideArchived = (int) $this->getAttribute('hide_archived', 0); + + // Flag to identify if the fk has default order + $this->fk_ordering = (string) $this->getAttribute('fk_ordering'); + + // The where SQL for foreignkey + $this->condition = (string) $this->getAttribute('condition'); + + // Flag for translate options + $this->translate = (bool) $this->getAttribute('translate'); + + // Initialize variables. + $html = ''; + $fk_value = ''; + + // Load all the field options + $db = Factory::getContainer()->get('DatabaseDriver'); + $query = $db->getQuery(true); + + // Support for multiple fields on fk_values + if ($this->value_multiple == 1) + { + // Get the fields for multiple value + $this->value_fields = (string) $this->getAttribute('value_field_multiple'); + $this->value_fields = explode(',', $this->value_fields); + $this->separator = (string) $this->getAttribute('separator'); + + $fk_value = ' CONCAT('; + + foreach ($this->value_fields as $field) + { + $fk_value .= $db->quoteName($field) . ', \'' . $this->separator . '\', '; + } + + $fk_value = substr($fk_value, 0, -(strlen($this->separator) + 6)); + $fk_value .= ') AS ' . $db->quoteName($this->value_field); + } + else + { + $fk_value = $db->quoteName($this->value_field); + } + + $query + ->select( + array( + $db->quoteName($this->key_field), + $fk_value + ) + ) + ->from($this->table); + + if ($this->hideTrashed) + { + $query->where($db->quoteName('state') . ' != -2'); + } + + if ($this->hideUnpublished) + { + $query->where($db->quoteName('state') . ' != 0'); + } + + if ($this->hidePublished) + { + $query->where($db->quoteName('state') . ' != 1'); + } + + if ($this->hideArchived) + { + $query->where($db->quoteName('state') . ' != 2'); + } + + if ($this->fk_ordering) + { + $query->order($this->fk_ordering); + } + + if($this->condition) + { + $query->where($this->condition); + } + + + + return $query; + } + + /** + * Method to get the field input for a foreignkey field. + * + * @return string The field input. + * + * @since 1.0.0 + */ + protected function getInput() + { + $data = $this->getLayoutData(); + + if (!\is_array($this->value) && !empty($this->value)) + { + if (\is_object($this->value)) + { + $this->value = get_object_vars($this->value); + } + + // String in format 2,5,4 + if (\is_string($this->value)) + { + $this->value = explode(',', $this->value); + } + + // Integer is given + if (\is_int($this->value)) + { + $this->value = array($this->value); + } + + $data['value'] = $this->value; + } + + $data['options'] = $this->getOptions(); + + return $this->getRenderer($this->layout)->render($data); + } + + /** + * Method to get the field options. + * + * @return array The field option objects. + * + * @since 1.0.0 + */ + protected function getOptions() + { + $options = array(); + $db = Factory::getContainer()->get('DatabaseDriver'); + try + { + $db->setQuery($this->processQuery()); + $results = $db->loadObjectList(); + } + catch (ExecutionFailureException $e) + { + Factory::getApplication()->enqueueMessage(Text::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error'); + } + + // Add header. + if (!empty($this->header)) + { + $options[] = (object) ["value" => '', "text" => Text::_($this->header)]; + } + + if(!empty($this->option_value_field) || !empty($this->option_key_field)) + { + $options[] = (object) ["value" => $this->option_key_field, "text" => Text::_($this->option_value_field)]; + } + + // Build the field options. + if (!empty($results)) + { + foreach ($results as $item) + { + $options[] = (object) [ + "value" => $item->{$this->key_field}, + "text" => $this->translate == true ? Text::_($item->{$this->value_field}) : $item->{$this->value_field} + ]; + } + } + + // Merge any additional options in the XML definition. + $options = array_merge(parent::getOptions(), $options); + + return $options; + } + + /** + * Wrapper method for getting attributes from the form element + * + * @param string $attr_name Attribute name + * @param mixed $default Optional value to return if attribute not found + * + * @return mixed The value of the attribute if it exists, null otherwise + */ + public function getAttribute($attr_name, $default = null) + { + if (!empty($this->element[$attr_name])) + { + return $this->element[$attr_name]; + } + else + { + return $default; + } + } +} diff --git a/administrator/src/Field/ModifiedbyField.php b/administrator/src/Field/ModifiedbyField.php new file mode 100644 index 0000000..0307e2f --- /dev/null +++ b/administrator/src/Field/ModifiedbyField.php @@ -0,0 +1,52 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Field; + +defined('JPATH_BASE') or die; + +use \Joomla\CMS\Form\FormField; +use \Joomla\CMS\Factory; + +/** + * Supports an HTML select list of categories + * + * @since 1.0.0 + */ +class ModifiedbyField extends \Joomla\CMS\Form\FormField +{ + /** + * The form field type. + * + * @var string + * @since 1.0.0 + */ + protected $type = 'modifiedby'; + + /** + * Method to get the field input markup. + * + * @return string The field input markup. + * + * @since 1.0.0 + */ + protected function getInput() + { + // Initialize variables. + $html = array(); + $user = Factory::getApplication()->getIdentity(); + $html[] = ''; + if (!$this->hidden) + { + $html[] = "
" . $user->name . " (" . $user->username . ")
"; + } + + return implode($html); + } +} diff --git a/administrator/src/Field/NestedparentField.php b/administrator/src/Field/NestedparentField.php new file mode 100644 index 0000000..18fc909 --- /dev/null +++ b/administrator/src/Field/NestedparentField.php @@ -0,0 +1,83 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Field; + +defined('JPATH_BASE') or die; + +use Joomla\CMS\Helper\UserGroupsHelper; +use \Joomla\CMS\Factory; +use Joomla\CMS\Form\Field\ListField; + +/** + * Supports an HTML select list of categories + * + * @since 1.0.0 + */ +class NestedparentField extends ListField +{ + /** + * The form field type. + * + * @var string + * @since 1.0.0 + */ + protected $type = 'nestedparent'; + + /** + * Method to get the field options. + * + * @return array The field option objects. + * + * @since 1.0.0 + */ + protected function getOptions() + { + $options = array(); + $table = $this->getAttribute('table'); + + $db = Factory::getContainer()->get('DatabaseDriver'); + $query = $db->getQuery(true) + ->select('DISTINCT(a.id) AS value, a.title AS text, a.level, a.lft') + ->from($table . ' AS a'); + + + // Prevent parenting to children of this item. + if ($id = $this->form->getValue('id')) + { + $query->join('LEFT', $db->quoteName($table) . ' AS p ON p.id = ' . (int) $id) + ->where('NOT(a.lft >= p.lft AND a.rgt <= p.rgt)'); + } + + $query->order('a.lft ASC'); + + // Get the options. + $db->setQuery($query); + + try + { + $options = $db->loadObjectList(); + } + catch (\RuntimeException $e) + { + throw new \Exception($e->getMessage(), 500); + } + + // Pad the option text with spaces using depth level as a multiplier. + for ($i = 0, $n = count($options); $i < $n; $i++) + { + $options[$i]->text = str_repeat('- ', $options[$i]->level) . $options[$i]->text; + } + + // Merge any additional options in the XML definition. + $options = array_merge(parent::getOptions(), $options); + + return $options; + } +} diff --git a/administrator/src/Field/TimecreatedField.php b/administrator/src/Field/TimecreatedField.php new file mode 100644 index 0000000..d744f7c --- /dev/null +++ b/administrator/src/Field/TimecreatedField.php @@ -0,0 +1,69 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Field; + +defined('JPATH_BASE') or die; + +use \Joomla\CMS\Factory; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Form\FormField; +use \Joomla\CMS\Date\Date; +use Joomla\CMS\HTML\HTMLHelper; + +/** + * Supports an HTML select list of categories + * + * @since 1.0.0 + */ +class TimecreatedField extends FormField +{ + /** + * The form field type. + * + * @var string + * @since 1.0.0 + */ + protected $type = 'timecreated'; + + /** + * Method to get the field input markup. + * + * @return string The field input markup. + * + * @since 1.0.0 + */ + protected function getInput() + { + // Initialize variables. + $html = array(); + + $time_created = $this->value; + + // If time is empty or invalid, use current time in UTC for saving + if (empty($time_created) || $time_created === '0000-00-00 00:00:00' || !strtotime($time_created)) { + $now = Factory::getDate(); // UTC + $time_created = $now->toSql(true); + } + + // Store raw UTC date in hidden input + $html[] = ''; + + + $hidden = (boolean) $this->element['hidden']; + + if ($hidden == null || !$hidden) + { + $pretty_date = HTMLHelper::_('date', $time_created, Text::_('DATE_FORMAT_LC2'), true); + $html[] = "
" . $pretty_date . "
"; + } + + return implode($html); + } +} diff --git a/administrator/src/Field/TimeupdatedField.php b/administrator/src/Field/TimeupdatedField.php new file mode 100644 index 0000000..c5e99bf --- /dev/null +++ b/administrator/src/Field/TimeupdatedField.php @@ -0,0 +1,69 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Field; + +defined('JPATH_BASE') or die; + +use \Joomla\CMS\Form\FormField; +use \Joomla\CMS\Factory; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Date\Date; +use Joomla\CMS\HTML\HTMLHelper; + + +/** + * Supports an HTML select list of categories + * + * @since 1.0.0 + */ +class TimeupdatedField extends FormField +{ + /** + * The form field type. + * + * @var string + * @since 1.0.0 + */ + protected $type = 'timeupdated'; + + /** + * Method to get the field input markup. + * + * @return string The field input markup. + * + * @since 1.0.0 + */ + protected function getInput() + { + // Initialize variables. + $html = array(); + + $old_time_updated = $this->value; + $hidden = (boolean) $this->element['hidden']; + + if ($hidden == null || !$hidden) + { + if (!strtotime($old_time_updated)) + { + $html[] = '-'; + } + else + { + $pretty_date = HTMLHelper::_('date', $old_time_updated, Text::_('DATE_FORMAT_LC2'), true); + $html[] = "
" . $pretty_date . "
"; + } + } + + $time_updated = Factory::getDate('now', Factory::getConfig()->get('offset'))->toSql(true); + $html[] = ''; + + return implode($html); + } +} diff --git a/administrator/src/Field/index.html b/administrator/src/Field/index.html new file mode 100644 index 0000000..42682b4 --- /dev/null +++ b/administrator/src/Field/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/administrator/src/Helper/CircolariHelper.php b/administrator/src/Helper/CircolariHelper.php new file mode 100644 index 0000000..8f9ec52 --- /dev/null +++ b/administrator/src/Helper/CircolariHelper.php @@ -0,0 +1,77 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Helper; +// No direct access +defined('_JEXEC') or die; + +use \Joomla\CMS\Factory; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Object\CMSObject; + +/** + * Circolari helper. + * + * @since 1.0.0 + */ +class CircolariHelper +{ + /** + * Gets the files attached to an item + * + * @param int $pk The item's id + * + * @param string $table The table's name + * + * @param string $field The field's name + * + * @return array The files + */ + public static function getFiles($pk, $table, $field) + { + $db = Factory::getContainer()->get('DatabaseDriver'); + $query = $db->getQuery(true); + + $query + ->select($field) + ->from($table) + ->where('id = ' . (int) $pk); + + $db->setQuery($query); + + return explode(',', $db->loadResult()); + } + + /** + * Gets a list of the actions that can be performed. + * + * @return CMSObject + * + * @since 1.0.0 + */ + public static function getActions() + { + $user = Factory::getApplication()->getIdentity(); + $result = new CMSObject; + + $assetName = 'com_circolari'; + + $actions = array( + 'core.admin', 'core.manage', 'core.create', 'core.edit', 'core.edit.own', 'core.edit.state', 'core.delete' + ); + + foreach ($actions as $action) + { + $result->set($action, $user->authorise($action, $assetName)); + } + + return $result; + } +} + diff --git a/administrator/src/Model/CircolareModel.php b/administrator/src/Model/CircolareModel.php new file mode 100644 index 0000000..9e7ccfc --- /dev/null +++ b/administrator/src/Model/CircolareModel.php @@ -0,0 +1,277 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Model; +// No direct access. +defined('_JEXEC') or die; + +use \Joomla\CMS\Table\Table; +use \Joomla\CMS\Factory; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Plugin\PluginHelper; +use \Joomla\CMS\MVC\Model\AdminModel; +use \Joomla\CMS\Helper\TagsHelper; +use \Joomla\CMS\Filter\OutputFilter; +use \Joomla\CMS\Event\Model; +use Joomla\CMS\Event\AbstractEvent; + + +/** + * Circolare model. + * + * @since 1.0.0 + */ +class CircolareModel extends AdminModel +{ + /** + * @var string The prefix to use with controller messages. + * + * @since 1.0.0 + */ + protected $text_prefix = 'COM_CIRCOLARI'; + + /** + * @var string Alias to manage history control + * + * @since 1.0.0 + */ + public $typeAlias = 'com_circolari.circolare'; + + /** + * @var null Item data + * + * @since 1.0.0 + */ + protected $item = null; + + + + + /** + * Returns a reference to the a Table object, always creating it. + * + * @param string $type The table type to instantiate + * @param string $prefix A prefix for the table class name. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return Table A database object + * + * @since 1.0.0 + */ + public function getTable($type = 'Circolare', $prefix = 'Administrator', $config = array()) + { + return parent::getTable($type, $prefix, $config); + } + + /** + * Method to get the record form. + * + * @param array $data An optional array of data for the form to interogate. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * + * @return \JForm|boolean A \JForm object on success, false on failure + * + * @since 1.0.0 + */ + public function getForm($data = array(), $loadData = true) + { + // Initialise variables. + $app = Factory::getApplication(); + + // Get the form. + $form = $this->loadForm( + 'com_circolari.circolare', + 'circolare', + array( + 'control' => 'jform', + 'load_data' => $loadData + ) + ); + + + + if (empty($form)) + { + return false; + } + + return $form; + } + + + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * + * @since 1.0.0 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = Factory::getApplication()->getUserState('com_circolari.edit.circolare.data', array()); + + if (empty($data)) + { + if ($this->item === null) + { + $this->item = $this->getItem(); + } + + $data = $this->item; + + } + + return $data; + } + + /** + * Method to get a single record. + * + * @param integer $pk The id of the primary key. + * + * @return mixed Object on success, false on failure. + * + * @since 1.0.0 + */ + public function getItem($pk = null) + { + + if ($item = parent::getItem($pk)) + { + if (isset($item->params)) + { + $item->params = json_encode($item->params); + } + + // Do any procesing on fields here if needed + } + + return $item; + + } + + /** + * Method to duplicate an Circolare + * + * @param array &$pks An array of primary key IDs. + * + * @return boolean True if successful. + * + * @throws Exception + */ + public function duplicate(&$pks) + { + $app = Factory::getApplication(); + $user = $app->getIdentity(); + $dispatcher = $this->getDispatcher(); + + // Access checks. + if (!$user->authorise('core.create', 'com_circolari')) + { + throw new \Exception(Text::_('JERROR_CORE_CREATE_NOT_PERMITTED')); + } + + $context = $this->option . '.' . $this->name; + + // Include the plugins for the save events. + PluginHelper::importPlugin($this->events_map['save']); + + $table = $this->getTable(); + + foreach ($pks as $pk) + { + + if ($table->load($pk, true)) + { + // Reset the id to create a new record. + $table->id = 0; + + if (!$table->check()) + { + throw new \Exception($table->getError()); + } + + + // Create the before save event. + $beforeSaveEvent = AbstractEvent::create( + $this->event_before_save, + [ + 'context' => $context, + 'subject' => $table, + 'isNew' => true, + 'data' => $table, + ] + ); + + // Trigger the before save event. + $dispatchResult = Factory::getApplication()->getDispatcher()->dispatch($this->event_before_save, $beforeSaveEvent); + + // Check if dispatch result is an array and handle accordingly + $result = isset($dispatchResult['result']) ? $dispatchResult['result'] : []; + + // Proceed with your logic + if (in_array(false, $result, true) || !$table->store()) { + throw new \Exception($table->getError()); + } + + // Trigger the after save event. + Factory::getApplication()->getDispatcher()->dispatch( + $this->event_after_save, + AbstractEvent::create( + $this->event_after_save, + [ + 'context' => $context, + 'subject' => $table, + 'isNew' => true, + 'data' => $table, + ] + ) + ); + } + else + { + throw new \Exception($table->getError()); + } + + } + + // Clean cache + $this->cleanCache(); + + return true; + } + + /** + * Prepare and sanitise the table prior to saving. + * + * @param Table $table Table Object + * + * @return void + * + * @since 1.0.0 + */ + protected function prepareTable($table) + { + jimport('joomla.filter.output'); + + if (empty($table->id)) + { + // Set ordering to the last item if not set + if (@$table->ordering === '') + { + $db = $this->getDbo(); + $db->setQuery('SELECT MAX(ordering) FROM #__circolari'); + $max = $db->loadResult(); + $table->ordering = $max + 1; + } + } + } +} diff --git a/administrator/src/Model/CircolaresModel.php b/administrator/src/Model/CircolaresModel.php new file mode 100644 index 0000000..e854bb6 --- /dev/null +++ b/administrator/src/Model/CircolaresModel.php @@ -0,0 +1,208 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Model; +// No direct access. +defined('_JEXEC') or die; + +use \Joomla\CMS\MVC\Model\ListModel; +use \Joomla\Component\Fields\Administrator\Helper\FieldsHelper; +use \Joomla\CMS\Factory; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Helper\TagsHelper; +use \Joomla\Database\ParameterType; +use \Joomla\Utilities\ArrayHelper; +use Pcrt\Component\Circolari\Administrator\Helper\CircolariHelper; + +/** + * Methods supporting a list of Circolares records. + * + * @since 1.0.0 + */ +class CircolaresModel extends ListModel +{ + /** + * Constructor. + * + * @param array $config An optional associative array of configuration settings. + * + * @see JController + * @since 1.6 + */ + public function __construct($config = array()) + { + if (empty($config['filter_fields'])) + { + $config['filter_fields'] = array( + 'id', 'a.id', + 'state', 'a.state', + 'ordering', 'a.ordering', + 'created_by', 'a.created_by', + 'modified_by', 'a.modified_by', + 'title', 'a.title', + 'description', 'a.description', + 'attachment', 'a.attachment', + 'image', 'a.image', + ); + } + + parent::__construct($config); + } + + + + + + + + + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @param string $ordering Elements order + * @param string $direction Order direction + * + * @return void + * + * @throws Exception + */ + protected function populateState($ordering = null, $direction = null) + { + // List state information. + parent::populateState('id', 'ASC'); + + $context = $this->getUserStateFromRequest($this->context.'.filter.search', 'filter_search'); + $this->setState('filter.search', $context); + + // Split context into component and optional section + if (!empty($context)) + { + $parts = FieldsHelper::extract($context); + + if ($parts) + { + $this->setState('filter.component', $parts[0]); + $this->setState('filter.section', $parts[1]); + } + } + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + * + * @since 1.0.0 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.state'); + + + return parent::getStoreId($id); + + } + + /** + * Build an SQL query to load the list data. + * + * @return DatabaseQuery + * + * @since 1.0.0 + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', 'DISTINCT a.*' + ) + ); + $query->from('`#__circolari` AS a'); + + // Join over the users for the checked out user + $query->select("uc.name AS uEditor"); + $query->join("LEFT", "#__users AS uc ON uc.id=a.checked_out"); + + // Join over the user field 'created_by' + $query->select('`created_by`.name AS `created_by`'); + $query->join('LEFT', '#__users AS `created_by` ON `created_by`.id = a.`created_by`'); + + // Join over the user field 'modified_by' + $query->select('`modified_by`.name AS `modified_by`'); + $query->join('LEFT', '#__users AS `modified_by` ON `modified_by`.id = a.`modified_by`'); + + + // Filter by published state + $published = $this->getState('filter.state'); + + if (is_numeric($published)) + { + $query->where('a.state = ' . (int) $published); + } + elseif (empty($published)) + { + $query->where('(a.state IN (0, 1))'); + } + + // Filter by search in title + $search = $this->getState('filter.search'); + + if (!empty($search)) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.id = ' . (int) substr($search, 3)); + } + else + { + $search = $db->Quote('%' . $db->escape($search, true) . '%'); + + } + } + + // Add the list ordering clause. + $orderCol = $this->state->get('list.ordering', 'id'); + $orderDirn = $this->state->get('list.direction', 'ASC'); + + if ($orderCol && $orderDirn) + { + $query->order($db->escape($orderCol . ' ' . $orderDirn)); + } + + return $query; + } + + /** + * Get an array of data items + * + * @return mixed Array of data items on success, false on failure. + */ + public function getItems() + { + $items = parent::getItems(); + + + return $items; + } +} diff --git a/administrator/src/Model/FirmatipoModel.php b/administrator/src/Model/FirmatipoModel.php new file mode 100644 index 0000000..970112f --- /dev/null +++ b/administrator/src/Model/FirmatipoModel.php @@ -0,0 +1,277 @@ + + * @copyright 2024 Eddy Prosperi + * @license GNU General Public License versione 2 o successiva; vedi LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Model; +// No direct access. +defined('_JEXEC') or die; + +use \Joomla\CMS\Table\Table; +use \Joomla\CMS\Factory; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Plugin\PluginHelper; +use \Joomla\CMS\MVC\Model\AdminModel; +use \Joomla\CMS\Helper\TagsHelper; +use \Joomla\CMS\Filter\OutputFilter; +use \Joomla\CMS\Event\Model; +use Joomla\CMS\Event\AbstractEvent; + + +/** + * Etichetta model. + * + * @since 1.0.0 + */ +class FirmatipoModel extends AdminModel +{ + /** + * @var string The prefix to use with controller messages. + * + * @since 1.0.0 + */ + protected $text_prefix = 'COM_CIRCOLARI'; + + /** + * @var string Alias to manage history control + * + * @since 1.0.0 + */ + public $typeAlias = 'com_circolari.firmaTipo'; + + /** + * @var null Item data + * + * @since 1.0.0 + */ + protected $item = null; + + + + + /** + * Returns a reference to the a Table object, always creating it. + * + * @param string $type The table type to instantiate + * @param string $prefix A prefix for the table class FirmatipoModel. Optional. + * @param array $config Configuration array for model. Optional. + * + * @return Table A database object + * + * @since 1.0.0 + */ + public function getTable($type = 'Firmatipo', $prefix = 'Administrator', $config = array()) + { + return parent::getTable($type, $prefix, $config); + } + + /** + * Method to get the record form. + * + * @param array $data An optional array of data for the form to interogate. + * @param boolean $loadData True if the form is to load its own data (default case), false if not. + * + * @return \JForm|boolean A \JForm object on success, false on failure + * + * @since 1.0.0 + */ + public function getForm($data = array(), $loadData = true) + { + // Initialise variables. + $app = Factory::getApplication(); + + // Get the form. + $form = $this->loadForm( + 'com_circolari.firmaTipo', + 'firmaTipo', + array( + 'control' => 'jform', + 'load_data' => $loadData + ) + ); + + + + if (empty($form)) + { + return false; + } + + return $form; + } + + + + /** + * Method to get the data that should be injected in the form. + * + * @return mixed The data for the form. + * + * @since 1.0.0 + */ + protected function loadFormData() + { + // Check the session for previously entered form data. + $data = Factory::getApplication()->getUserState('com_circolari.edit.firmatipo.data', array()); + + if (empty($data)) + { + if ($this->item === null) + { + $this->item = $this->getItem(); + } + + $data = $this->item; + + } + + return $data; + } + + /** + * Method to get a single record. + * + * @param integer $pk The id of the primary key. + * + * @return mixed Object on success, false on failure. + * + * @since 1.0.0 + */ + public function getItem($pk = null) + { + + if ($item = parent::getItem($pk)) + { + if (isset($item->params)) + { + $item->params = json_encode($item->params); + } + + // Do any procesing on fields here if needed + } + + return $item; + + } + + /** + * Method to duplicate an Etichetta + * + * @param array &$pks An array of primary key IDs. + * + * @return boolean True if successful. + * + * @throws Exception + */ + public function duplicate(&$pks) + { + $app = Factory::getApplication(); + $user = $app->getIdentity(); + $dispatcher = $this->getDispatcher(); + + // Access checks. + if (!$user->authorise('core.create', 'com_circolari')) + { + throw new \Exception(Text::_('JERROR_CORE_CREATE_NOT_PERMITTED')); + } + + $context = $this->option . '.' . $this->name; + + // Include the plugins for the save events. + PluginHelper::importPlugin($this->events_map['save']); + + $table = $this->getTable(); + + foreach ($pks as $pk) + { + + if ($table->load($pk, true)) + { + // Reset the id to create a new record. + $table->id = 0; + + if (!$table->check()) + { + throw new \Exception($table->getError()); + } + + + // Create the before save event. + $beforeSaveEvent = AbstractEvent::create( + $this->event_before_save, + [ + 'context' => $context, + 'subject' => $table, + 'isNew' => true, + 'data' => $table, + ] + ); + + // Trigger the before save event. + $dispatchResult = Factory::getApplication()->getDispatcher()->dispatch($this->event_before_save, $beforeSaveEvent); + + // Check if dispatch result is an array and handle accordingly + $result = isset($dispatchResult['result']) ? $dispatchResult['result'] : []; + + // Proceed with your logic + if (in_array(false, $result, true) || !$table->store()) { + throw new \Exception($table->getError()); + } + + // Trigger the after save event. + Factory::getApplication()->getDispatcher()->dispatch( + $this->event_after_save, + AbstractEvent::create( + $this->event_after_save, + [ + 'context' => $context, + 'subject' => $table, + 'isNew' => true, + 'data' => $table, + ] + ) + ); + } + else + { + throw new \Exception($table->getError()); + } + + } + + // Clean cache + $this->cleanCache(); + + return true; + } + + /** + * Prepare and sanitise the table prior to saving. + * + * @param Table $table Table Object + * + * @return void + * + * @since 1.0.0 + */ + protected function prepareTable($table) + { + jimport('joomla.filter.output'); + + if (empty($table->id)) + { + // Set ordering to the last item if not set + if (@$table->ordering === '') + { + $db = $this->getDbo(); + $db->setQuery('SELECT MAX(ordering) FROM #__circolari_firmetipi'); + $max = $db->loadResult(); + $table->ordering = $max + 1; + } + } + } +} diff --git a/administrator/src/Model/FirmetipiModel.php b/administrator/src/Model/FirmetipiModel.php new file mode 100644 index 0000000..963f30d --- /dev/null +++ b/administrator/src/Model/FirmetipiModel.php @@ -0,0 +1,195 @@ + + * @copyright 2024 Eddy Prosperi + * @license GNU General Public License versione 2 o successiva; vedi LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Model; +// No direct access. +defined('_JEXEC') or die; + +use \Joomla\CMS\MVC\Model\ListModel; +use \Joomla\Component\Fields\Administrator\Helper\FieldsHelper; +use \Joomla\CMS\Factory; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Helper\TagsHelper; +use \Joomla\Database\ParameterType; +use \Joomla\Utilities\ArrayHelper; + +/** + * Methods supporting a list of Etichette records. + * + * @since 1.0.0 + */ +class FirmetipiModel extends ListModel +{ + /** + * Constructor. + * + * @param array $config An optional associative array of configuration settings. + * + * @see JController + * @since 1.6 + */ + public function __construct($config = array()) + { + if (empty($config['filter_fields'])) + { + $config['filter_fields'] = array( + 'id', 'a.id', + 'state', 'a.state', + 'ordering', 'a.ordering', + 'created_by', 'a.created_by', + 'modified_by', 'a.modified_by', + 'nome', 'a.nome', + 'lingua', 'a.lingua', + ); + } + + parent::__construct($config); + } + + + + + + + + + /** + * Method to auto-populate the model state. + * + * Note. Calling getState in this method will result in recursion. + * + * @param string $ordering Elements order + * @param string $direction Order direction + * + * @return void + * + * @throws Exception + */ + protected function populateState($ordering = null, $direction = null) + { + // List state information. + parent::populateState("a.id", "ASC"); + + $context = $this->getUserStateFromRequest($this->context.'.filter.search', 'filter_search'); + $this->setState('filter.search', $context); + + // Split context into component and optional section + if (!empty($context)) + { + $parts = FieldsHelper::extract($context); + + if ($parts) + { + $this->setState('filter.component', $parts[0]); + $this->setState('filter.section', $parts[1]); + } + } + } + + /** + * Method to get a store id based on model configuration state. + * + * This is necessary because the model is used by the component and + * different modules that might need different sets of data or different + * ordering requirements. + * + * @param string $id A prefix for the store id. + * + * @return string A store id. + * + * @since 1.0.0 + */ + protected function getStoreId($id = '') + { + // Compile the store id. + $id .= ':' . $this->getState('filter.search'); + $id .= ':' . $this->getState('filter.state'); + + + return parent::getStoreId($id); + + } + + /** + * Build an SQL query to load the list data. + * + * @return DatabaseQuery + * + * @since 1.0.0 + */ + protected function getListQuery() + { + // Create a new query object. + $db = $this->getDbo(); + $query = $db->getQuery(true); + + // Select the required fields from the table. + $query->select( + $this->getState( + 'list.select', 'DISTINCT a.*' + ) + ); + $query->from('`#__circolari_firmetipi` AS a'); + + + + + // Filter by published state + $published = $this->getState('filter.state'); + + if (is_numeric($published)) + { + $query->where('a.state = ' . (int) $published); + } + elseif (empty($published)) + { + $query->where('(a.state IN (0, 1))'); + } + + // Filter by search in title + $search = $this->getState('filter.search'); + + if (!empty($search)) + { + if (stripos($search, 'id:') === 0) + { + $query->where('a.id = ' . (int) substr($search, 3)); + } + else + { + $search = $db->Quote('%' . $db->escape($search, true) . '%'); + + } + } + + // Add the list ordering clause. + $orderCol = $this->state->get('list.ordering', "a.id"); + $orderDirn = $this->state->get('list.direction', "ASC"); + + if ($orderCol && $orderDirn) + { + $query->order($db->escape($orderCol . ' ' . $orderDirn)); + } + + return $query; + } + + /** + * Get an array of data items + * + * @return mixed Array of data items on success, false on failure. + */ + public function getItems() + { + $items = parent::getItems(); + + + return $items; + } +} diff --git a/administrator/src/Service/Html/CIRCOLARI.php b/administrator/src/Service/Html/CIRCOLARI.php new file mode 100644 index 0000000..1c05d4c --- /dev/null +++ b/administrator/src/Service/Html/CIRCOLARI.php @@ -0,0 +1,53 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Service\Html; + +// No direct access +defined('_JEXEC') or die; + +use Joomla\Utilities\ArrayHelper; +use Joomla\CMS\Language\Text; +use Joomla\CMS\MVC\Model\DatabaseAwareTrait; +use Joomla\Database\DatabaseDriver; + +/** + * Circolari HTML Helper. + * + * @since 1.0.0 + */ +class CIRCOLARI +{ + use DatabaseAwareTrait; + + /** + * Public constructor. + * + * @param DatabaseDriver $db The Joomla DB driver object for the site's database. + */ + public function __construct(DatabaseDriver $db) + { + $this->setDbo($db); + } + + public function toggle($value = 0, $view='', $field='', $i='') + { + $states = array( + 0 => array('icon-unpublish', Text::_('Toggle'), ''), + 1 => array('icon-publish', Text::_('Toggle'), '') + ); + + $state = ArrayHelper::getValue($states, (int) $value, $states[0]); + $text = ''; + $html = '' . $text . ''; + + return $html; + } +} diff --git a/administrator/src/Table/CircolareTable.php b/administrator/src/Table/CircolareTable.php new file mode 100644 index 0000000..bb84ed5 --- /dev/null +++ b/administrator/src/Table/CircolareTable.php @@ -0,0 +1,279 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Table; +// No direct access +defined('_JEXEC') or die; + +use \Joomla\Utilities\ArrayHelper; +use \Joomla\CMS\Factory; +use \Joomla\CMS\Access\Access; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Table\Table as Table; +use \Joomla\CMS\Versioning\VersionableTableInterface; +use Joomla\CMS\Tag\TaggableTableInterface; +use Joomla\CMS\Tag\TaggableTableTrait; +use \Joomla\Database\DatabaseDriver; +use \Joomla\CMS\Filter\OutputFilter; +use \Joomla\CMS\Filesystem\File; +use \Joomla\Registry\Registry; +use \Pcrt\Component\Circolari\Administrator\Helper\CircolariHelper; +use \Joomla\CMS\Helper\ContentHelper; + + +/** + * Circolare table + * + * @since 1.0.0 + */ +class CircolareTable extends Table implements VersionableTableInterface, TaggableTableInterface +{ + use TaggableTableTrait; + + /** + * Indicates that columns fully support the NULL value in the database + * + * @var boolean + * @since 4.0.0 + */ + protected $_supportNullValue = true; + + + /** + * Constructor + * + * @param JDatabase &$db A database connector object + */ + public function __construct(DatabaseDriver $db) + { + $this->typeAlias = 'com_circolari.circolare'; + parent::__construct('#__circolari', 'id', $db); + $this->setColumnAlias('published', 'state'); + + } + + /** + * Get the type alias for the history table + * + * @return string The alias as described above + * + * @since 1.0.0 + */ + public function getTypeAlias() + { + return $this->typeAlias; + } + + /** + * Overloaded bind function to pre-process the params. + * + * @param array $array Named array + * @param mixed $ignore Optional array or list of parameters to ignore + * + * @return boolean True on success. + * + * @see Table:bind + * @since 1.0.0 + * @throws \InvalidArgumentException + */ + public function bind($array, $ignore = '') + { + $date = Factory::getDate(); + $task = Factory::getApplication()->input->get('task'); + $user = Factory::getApplication()->getIdentity(); + + $input = Factory::getApplication()->input; + $task = $input->getString('task', ''); + + if ($array['id'] == 0 && empty($array['created_by'])) + { + $array['created_by'] = Factory::getUser()->id; + } + + if ($array['id'] == 0 && empty($array['modified_by'])) + { + $array['modified_by'] = Factory::getUser()->id; + } + + if ($task == 'apply' || $task == 'save') + { + $array['modified_by'] = Factory::getUser()->id; + } + + if (isset($array['params']) && is_array($array['params'])) + { + $registry = new Registry; + $registry->loadArray($array['params']); + $array['params'] = (string) $registry; + } + + if (isset($array['metadata']) && is_array($array['metadata'])) + { + $registry = new Registry; + $registry->loadArray($array['metadata']); + $array['metadata'] = (string) $registry; + } + + if (!$user->authorise('core.admin', 'com_circolari.circolare.' . $array['id'])) + { + $actions = Access::getActionsFromFile( + JPATH_ADMINISTRATOR . '/components/com_circolari/access.xml', + "/access/section[@name='circolare']/" + ); + $default_actions = Access::getAssetRules('com_circolari.circolare.' . $array['id'])->getData(); + $array_jaccess = array(); + + foreach ($actions as $action) + { + if (key_exists($action->name, $default_actions)) + { + $array_jaccess[$action->name] = $default_actions[$action->name]; + } + } + + $array['rules'] = $this->JAccessRulestoArray($array_jaccess); + } + + // Bind the rules for ACL where supported. + if (isset($array['rules']) && is_array($array['rules'])) + { + $this->setRules($array['rules']); + } + + return parent::bind($array, $ignore); + } + + /** + * Method to store a row in the database from the Table instance properties. + * + * If a primary key value is set the row with that primary key value will be updated with the instance property values. + * If no primary key value is set a new row will be inserted into the database with the properties from the Table instance. + * + * @param boolean $updateNulls True to update fields even if they are null. + * + * @return boolean True on success. + * + * @since 1.0.0 + */ + public function store($updateNulls = true) + { + + + return parent::store($updateNulls); + } + + /** + * This function convert an array of Access objects into an rules array. + * + * @param array $jaccessrules An array of Access objects. + * + * @return array + */ + private function JAccessRulestoArray($jaccessrules) + { + $rules = array(); + + foreach ($jaccessrules as $action => $jaccess) + { + $actions = array(); + + if ($jaccess) + { + foreach ($jaccess->getData() as $group => $allow) + { + $actions[$group] = ((bool)$allow); + } + } + + $rules[$action] = $actions; + } + + return $rules; + } + + /** + * Overloaded check function + * + * @return bool + */ + public function check() + { + // If there is an ordering column and this is a new row then get the next ordering value + if (property_exists($this, 'ordering') && $this->id == 0) + { + $this->ordering = self::getNextOrder(); + } + + + + return parent::check(); + } + + /** + * Define a namespaced asset name for inclusion in the #__assets table + * + * @return string The asset name + * + * @see Table::_getAssetName + */ + protected function _getAssetName() + { + $k = $this->_tbl_key; + + return $this->typeAlias . '.' . (int) $this->$k; + } + + /** + * Returns the parent asset's id. If you have a tree structure, retrieve the parent's id using the external key field + * + * @param Table $table Table name + * @param integer $id Id + * + * @see Table::_getAssetParentId + * + * @return mixed The id on success, false on failure. + */ + protected function _getAssetParentId($table = null, $id = null) + { + // We will retrieve the parent-asset from the Asset-table + $assetParent = Table::getInstance('Asset'); + + // Default: if no asset-parent can be found we take the global asset + $assetParentId = $assetParent->getRootId(); + + // The item has the component as asset-parent + $assetParent->loadByName('com_circolari'); + + // Return the found asset-parent-id + if ($assetParent->id) + { + $assetParentId = $assetParent->id; + } + + return $assetParentId; + } + + //XXX_CUSTOM_TABLE_FUNCTION + + + /** + * Delete a record by id + * + * @param mixed $pk Primary key value to delete. Optional + * + * @return bool + */ + public function delete($pk = null) + { + $this->load($pk); + $result = parent::delete($pk); + + return $result; + } +} diff --git a/administrator/src/Table/FirmatipoTable.php b/administrator/src/Table/FirmatipoTable.php new file mode 100644 index 0000000..58e0a2a --- /dev/null +++ b/administrator/src/Table/FirmatipoTable.php @@ -0,0 +1,279 @@ + + * @copyright 2024 Eddy Prosperi + * @license GNU General Public License versione 2 o successiva; vedi LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\Table; +// No direct access +defined('_JEXEC') or die; + +use \Joomla\Utilities\ArrayHelper; +use \Joomla\CMS\Factory; +use \Joomla\CMS\Access\Access; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Table\Table as Table; +use \Joomla\CMS\Versioning\VersionableTableInterface; +use Joomla\CMS\Tag\TaggableTableInterface; +use Joomla\CMS\Tag\TaggableTableTrait; +use \Joomla\Database\DatabaseDriver; +use \Joomla\CMS\Filter\OutputFilter; +use \Joomla\CMS\Filesystem\File; +use \Joomla\Registry\Registry; +use \Pcrt\Component\Circolari\Administrator\Helper\CircolariHelper; +use \Joomla\CMS\Helper\ContentHelper; + + +/** + * Etichetta table + * + * @since 1.0.0 + */ +class FirmatipoTable extends Table implements VersionableTableInterface, TaggableTableInterface +{ + use TaggableTableTrait; + + /** + * Indicates that columns fully support the NULL value in the database + * + * @var boolean + * @since 4.0.0 + */ + protected $_supportNullValue = true; + + + /** + * Constructor + * + * @param JDatabase &$db A database connector object + */ + public function __construct(DatabaseDriver $db) + { + $this->typeAlias = 'com_circolari.firmaTipo'; + parent::__construct('#__circolari_firmetipi', 'id', $db); + $this->setColumnAlias('published', 'state'); + + } + + /** + * Get the type alias for the history table + * + * @return string The alias as described above + * + * @since 1.0.0 + */ + public function getTypeAlias() + { + return $this->typeAlias; + } + + /** + * Overloaded bind function to pre-process the params. + * + * @param array $array Named array + * @param mixed $ignore Optional array or list of parameters to ignore + * + * @return boolean True on success. + * + * @see Table:bind + * @since 1.0.0 + * @throws \InvalidArgumentException + */ + public function bind($array, $ignore = '') + { + $date = Factory::getDate(); + $task = Factory::getApplication()->input->get('task'); + $user = Factory::getApplication()->getIdentity(); + + $input = Factory::getApplication()->input; + $task = $input->getString('task', ''); + + if ($array['id'] == 0 && empty($array['created_by'])) + { + $array['created_by'] = Factory::getUser()->id; + } + + if ($array['id'] == 0 && empty($array['modified_by'])) + { + $array['modified_by'] = Factory::getUser()->id; + } + + if ($task == 'apply' || $task == 'save') + { + $array['modified_by'] = Factory::getUser()->id; + } + + if (isset($array['params']) && is_array($array['params'])) + { + $registry = new Registry; + $registry->loadArray($array['params']); + $array['params'] = (string) $registry; + } + + if (isset($array['metadata']) && is_array($array['metadata'])) + { + $registry = new Registry; + $registry->loadArray($array['metadata']); + $array['metadata'] = (string) $registry; + } + + if (!$user->authorise('core.admin', 'com_circolari.firmaTipo.' . $array['id'])) + { + $actions = Access::getActionsFromFile( + JPATH_ADMINISTRATOR . '/components/com_circolari/access.xml', + "/access/section[@name='firmaTipo']/" + ); + $default_actions = Access::getAssetRules('com_circolari.firmaTipo.' . $array['id'])->getData(); + $array_jaccess = array(); + + foreach ($actions as $action) + { + if (key_exists($action->name, $default_actions)) + { + $array_jaccess[$action->name] = $default_actions[$action->name]; + } + } + + $array['rules'] = $this->JAccessRulestoArray($array_jaccess); + } + + // Bind the rules for ACL where supported. + if (isset($array['rules']) && is_array($array['rules'])) + { + $this->setRules($array['rules']); + } + + return parent::bind($array, $ignore); + } + + /** + * Method to store a row in the database from the Table instance properties. + * + * If a primary key value is set the row with that primary key value will be updated with the instance property values. + * If no primary key value is set a new row will be inserted into the database with the properties from the Table instance. + * + * @param boolean $updateNulls True to update fields even if they are null. + * + * @return boolean True on success. + * + * @since 1.0.0 + */ + public function store($updateNulls = true) + { + + + return parent::store($updateNulls); + } + + /** + * This function convert an array of Access objects into an rules array. + * + * @param array $jaccessrules An array of Access objects. + * + * @return array + */ + private function JAccessRulestoArray($jaccessrules) + { + $rules = array(); + + foreach ($jaccessrules as $action => $jaccess) + { + $actions = array(); + + if ($jaccess) + { + foreach ($jaccess->getData() as $group => $allow) + { + $actions[$group] = ((bool)$allow); + } + } + + $rules[$action] = $actions; + } + + return $rules; + } + + /** + * Overloaded check function + * + * @return bool + */ + public function check() + { + // If there is an ordering column and this is a new row then get the next ordering value + if (property_exists($this, 'ordering') && $this->id == 0) + { + $this->ordering = self::getNextOrder(); + } + + + + return parent::check(); + } + + /** + * Define a namespaced asset name for inclusion in the #__assets table + * + * @return string The asset name + * + * @see Table::_getAssetName + */ + protected function _getAssetName() + { + $k = $this->_tbl_key; + + return $this->typeAlias . '.' . (int) $this->$k; + } + + /** + * Returns the parent asset's id. If you have a tree structure, retrieve the parent's id using the external key field + * + * @param Table $table Table name + * @param integer $id Id + * + * @see Table::_getAssetParentId + * + * @return mixed The id on success, false on failure. + */ + protected function _getAssetParentId($table = null, $id = null) + { + // We will retrieve the parent-asset from the Asset-table + $assetParent = Table::getInstance('Asset'); + + // Default: if no asset-parent can be found we take the global asset + $assetParentId = $assetParent->getRootId(); + + // The item has the component as asset-parent + $assetParent->loadByName('com_circolari'); + + // Return the found asset-parent-id + if ($assetParent->id) + { + $assetParentId = $assetParent->id; + } + + return $assetParentId; + } + + //XXX_CUSTOM_TABLE_FUNCTION + + + /** + * Delete a record by id + * + * @param mixed $pk Primary key value to delete. Optional + * + * @return bool + */ + public function delete($pk = null) + { + $this->load($pk); + $result = parent::delete($pk); + + return $result; + } +} diff --git a/administrator/src/View/Circolare/HtmlView.php b/administrator/src/View/Circolare/HtmlView.php new file mode 100644 index 0000000..5a6858e --- /dev/null +++ b/administrator/src/View/Circolare/HtmlView.php @@ -0,0 +1,114 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\View\Circolare; +// No direct access +defined('_JEXEC') or die; + +use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; +use \Joomla\CMS\Toolbar\ToolbarHelper; +use \Joomla\CMS\Factory; +use \Pcrt\Component\Circolari\Administrator\Helper\CircolariHelper; +use \Joomla\CMS\Language\Text; + +/** + * View class for a single Circolare. + * + * @since 1.0.0 + */ +class HtmlView extends BaseHtmlView +{ + protected $state; + + protected $item; + + protected $form; + + /** + * Display the view + * + * @param string $tpl Template name + * + * @return void + * + * @throws Exception + */ + public function display($tpl = null) + { + $this->state = $this->get('State'); + $this->item = $this->get('Item'); + $this->form = $this->get('Form'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + throw new \Exception(implode("\n", $errors)); + } + $this->addToolbar(); + + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + * + * @throws Exception + */ + protected function addToolbar() + { + Factory::getApplication()->input->set('hidemainmenu', true); + + $user = Factory::getApplication()->getIdentity(); + $isNew = ($this->item->id == 0); + + if (isset($this->item->checked_out)) + { + $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $user->get('id')); + } + else + { + $checkedOut = false; + } + + $canDo = CircolariHelper::getActions(); + + ToolbarHelper::title(Text::_('COM_CIRCOLARI_TITLE_CIRCOLARE'), "generic"); + + // If not checked out, can save the item. + if (!$checkedOut && ($canDo->get('core.edit') || ($canDo->get('core.create')))) + { + ToolbarHelper::apply('circolare.apply', 'JTOOLBAR_APPLY'); + ToolbarHelper::save('circolare.save', 'JTOOLBAR_SAVE'); + } + + if (!$checkedOut && ($canDo->get('core.create'))) + { + ToolbarHelper::custom('circolare.save2new', 'save-new.png', 'save-new_f2.png', 'JTOOLBAR_SAVE_AND_NEW', false); + } + + // If an existing item, can save to a copy. + if (!$isNew && $canDo->get('core.create')) + { + ToolbarHelper::custom('circolare.save2copy', 'save-copy.png', 'save-copy_f2.png', 'JTOOLBAR_SAVE_AS_COPY', false); + } + + + + if (empty($this->item->id)) + { + ToolbarHelper::cancel('circolare.cancel', 'JTOOLBAR_CANCEL'); + } + else + { + ToolbarHelper::cancel('circolare.cancel', 'JTOOLBAR_CLOSE'); + } + } +} diff --git a/administrator/src/View/Circolares/HtmlView.php b/administrator/src/View/Circolares/HtmlView.php new file mode 100644 index 0000000..0b8fa5a --- /dev/null +++ b/administrator/src/View/Circolares/HtmlView.php @@ -0,0 +1,183 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\View\Circolares; +// No direct access +defined('_JEXEC') or die; + +use \Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; +use \Pcrt\Component\Circolari\Administrator\Helper\CircolariHelper; +use \Joomla\CMS\Toolbar\Toolbar; +use \Joomla\CMS\Toolbar\ToolbarHelper; +use \Joomla\CMS\Language\Text; +use \Joomla\Component\Content\Administrator\Extension\ContentComponent; +use \Joomla\CMS\Form\Form; +use \Joomla\CMS\HTML\Helpers\Sidebar; +/** + * View class for a list of Circolares. + * + * @since 1.0.0 + */ +class HtmlView extends BaseHtmlView +{ + protected $items; + + protected $pagination; + + protected $state; + + /** + * Display the view + * + * @param string $tpl Template name + * + * @return void + * + * @throws Exception + */ + public function display($tpl = null) + { + $this->state = $this->get('State'); + $this->items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->filterForm = $this->get('FilterForm'); + $this->activeFilters = $this->get('ActiveFilters'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + throw new \Exception(implode("\n", $errors)); + } + + $this->addToolbar(); + + $this->sidebar = Sidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + * + * @since 1.0.0 + */ + protected function addToolbar() + { + $state = $this->get('State'); + $canDo = CircolariHelper::getActions(); + + ToolbarHelper::title(Text::_('COM_CIRCOLARI_TITLE_CIRCOLARES'), "generic"); + + $toolbar = Toolbar::getInstance('toolbar'); + + // Check if the form exists before showing the add/edit buttons + $formPath = JPATH_COMPONENT_ADMINISTRATOR . '/src/View/Circolares'; + + if (file_exists($formPath)) + { + if ($canDo->get('core.create')) + { + $toolbar->addNew('circolare.add'); + } + } + + if ($canDo->get('core.edit.state')) + { + $dropdown = $toolbar->dropdownButton('status-group') + ->text('JTOOLBAR_CHANGE_STATUS') + ->toggleSplit(false) + ->icon('fas fa-ellipsis-h') + ->buttonClass('btn btn-action') + ->listCheck(true); + + $childBar = $dropdown->getChildToolbar(); + + if (isset($this->items[0]->state)) + { + $childBar->publish('circolares.publish')->listCheck(true); + $childBar->unpublish('circolares.unpublish')->listCheck(true); + $childBar->archive('circolares.archive')->listCheck(true); + } + elseif (isset($this->items[0])) + { + // If this component does not use state then show a direct delete button as we can not trash + $toolbar->delete('circolares.delete') + ->text('JTOOLBAR_EMPTY_TRASH') + ->message('JGLOBAL_CONFIRM_DELETE') + ->listCheck(true); + } + + $childBar->standardButton('duplicate') + ->text('JTOOLBAR_DUPLICATE') + ->icon('fas fa-copy') + ->task('circolares.duplicate') + ->listCheck(true); + + if (isset($this->items[0]->checked_out)) + { + $childBar->checkin('circolares.checkin')->listCheck(true); + } + + if (isset($this->items[0]->state)) + { + $childBar->trash('circolares.trash')->listCheck(true); + } + } + + + + // Show trash and delete for components that uses the state field + if (isset($this->items[0]->state)) + { + + if ($this->state->get('filter.state') == ContentComponent::CONDITION_TRASHED && $canDo->get('core.delete')) + { + $toolbar->delete('circolares.delete') + ->text('JTOOLBAR_EMPTY_TRASH') + ->message('JGLOBAL_CONFIRM_DELETE') + ->listCheck(true); + } + } + + if ($canDo->get('core.admin')) + { + $toolbar->preferences('com_circolari'); + } + + // Set sidebar action + Sidebar::setAction('index.php?option=com_circolari&view=circolares'); + } + + /** + * Method to order fields + * + * @return void + */ + protected function getSortFields() + { + return array( + 'a.`id`' => Text::_('JGRID_HEADING_ID'), + 'a.`state`' => Text::_('JSTATUS'), + 'a.`ordering`' => Text::_('JGRID_HEADING_ORDERING'), + ); + } + + /** + * Check if state is set + * + * @param mixed $state State + * + * @return bool + */ + public function getState($state) + { + return isset($this->state->{$state}) ? $this->state->{$state} : false; + } +} diff --git a/administrator/src/View/Firmatipo/HtmlView.php b/administrator/src/View/Firmatipo/HtmlView.php new file mode 100644 index 0000000..6326bfa --- /dev/null +++ b/administrator/src/View/Firmatipo/HtmlView.php @@ -0,0 +1,114 @@ + + * @copyright 2024 Eddy Prosperi + * @license GNU General Public License versione 2 o successiva; vedi LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\View\Firmatipo; +// No direct access +defined('_JEXEC') or die; + +use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; +use \Joomla\CMS\Toolbar\ToolbarHelper; +use \Joomla\CMS\Factory; +use \Pcrt\Component\Circolari\Administrator\Helper\CircolariHelper; +use \Joomla\CMS\Language\Text; + +/** + * View class HtmlView a single Firmatipo. + * + * @since 1.0.0 + */ +class HtmlView extends BaseHtmlView +{ + protected $state; + + protected $item; + + protected $form; + + /** + * Display the view + * + * @param string $tpl Template name + * + * @return void + * + * @throws Exception + */ + public function display($tpl = null) + { + $this->state = $this->get('State'); + $this->item = $this->get('Item'); + $this->form = $this->get('Form'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + throw new \Exception(implode("\n", $errors)); + } + $this->addToolbar(); + + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + * + * @throws Exception + */ + protected function addToolbar() + { + Factory::getApplication()->input->set('hidemainmenu', true); + + $user = Factory::getApplication()->getIdentity(); + $isNew = ($this->item->id == 0); + + if (isset($this->item->checked_out)) + { + $checkedOut = !($this->item->checked_out == 0 || $this->item->checked_out == $user->get('id')); + } + else + { + $checkedOut = false; + } + + $canDo = CircolariHelper::getActions(); + + ToolbarHelper::title(Text::_('Firma'), "generic"); + + // If not checked out, can save the item. + if (!$checkedOut && ($canDo->get('core.edit') || ($canDo->get('core.create')))) + { + ToolbarHelper::apply('firmatipo.apply', 'JTOOLBAR_APPLY'); + ToolbarHelper::save('firmatipo.save', 'JTOOLBAR_SAVE'); + } + + if (!$checkedOut && ($canDo->get('core.create'))) + { + ToolbarHelper::custom('firmatipo.save2new', 'save-new.png', 'save-new_f2.png', 'JTOOLBAR_SAVE_AND_NEW', false); + } + + // If an existing item, can save to a copy. + if (!$isNew && $canDo->get('core.create')) + { + ToolbarHelper::custom('firmatipo.save2copy', 'save-copy.png', 'save-copy_f2.png', 'JTOOLBAR_SAVE_AS_COPY', false); + } + + + + if (empty($this->item->id)) + { + ToolbarHelper::cancel('firmatipo.cancel', 'JTOOLBAR_CANCEL'); + } + else + { + ToolbarHelper::cancel('firmatipo.cancel', 'JTOOLBAR_CLOSE'); + } + } +} diff --git a/administrator/src/View/Firmetipi/HtmlView.php b/administrator/src/View/Firmetipi/HtmlView.php new file mode 100644 index 0000000..63c3a09 --- /dev/null +++ b/administrator/src/View/Firmetipi/HtmlView.php @@ -0,0 +1,177 @@ + + * @copyright 2024 Eddy Prosperi + * @license GNU General Public License versione 2 o successiva; vedi LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Administrator\View\Firmetipi; +// No direct access +defined('_JEXEC') or die; + +use \Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; +use \Pcrt\Component\Circolari\Administrator\Helper\CircolariHelper; +use \Joomla\CMS\Toolbar\Toolbar; +use \Joomla\CMS\Toolbar\ToolbarHelper; +use \Joomla\CMS\Language\Text; +use \Joomla\Component\Content\Administrator\Extension\ContentComponent; +use \Joomla\CMS\Form\Form; +use \Joomla\CMS\HTML\Helpers\Sidebar; +/** + * View class HtmlView a list of Firmetipi. + * + * @since 1.0.0 + */ +class HtmlView extends BaseHtmlView +{ + protected $items; + + protected $pagination; + + protected $state; + + /** + * Display the view + * + * @param string $tpl Template name + * + * @return void + * + * @throws Exception + */ + public function display($tpl = null) + { + $this->state = $this->get('State'); + $this->items = $this->get('Items'); + $this->pagination = $this->get('Pagination'); + $this->filterForm = $this->get('FilterForm'); + $this->activeFilters = $this->get('ActiveFilters'); + + // Check for errors. + if (count($errors = $this->get('Errors'))) + { + throw new \Exception(implode("\n", $errors)); + } + + $this->addToolbar(); + + $this->sidebar = Sidebar::render(); + parent::display($tpl); + } + + /** + * Add the page title and toolbar. + * + * @return void + * + * @since 1.0.0 + */ + protected function addToolbar() + { + $state = $this->get('State'); + $canDo = CircolariHelper::getActions(); + + ToolbarHelper::title(Text::_('Firme'), "generic"); + + $toolbar = Toolbar::getInstance('toolbar'); + + // Check if the form exists before showing the add/edit buttons + $formPath = JPATH_COMPONENT_ADMINISTRATOR . '/src/View/Firmetipi'; + + if (file_exists($formPath)) + { + if ($canDo->get('core.create')) + { + $toolbar->addNew('firmatipo.add'); + } + } + + if ($canDo->get('core.edit.state')) + { + $dropdown = $toolbar->dropdownButton('status-group') + ->text('JTOOLBAR_CHANGE_STATUS') + ->toggleSplit(false) + ->icon('fas fa-ellipsis-h') + ->buttonClass('btn btn-action') + ->listCheck(true); + + $childBar = $dropdown->getChildToolbar(); + + if (isset($this->items[0]->state)) + { + $childBar->publish('firmetipi.publish')->listCheck(true); + $childBar->unpublish('firmetipi.unpublish')->listCheck(true); + $childBar->archive('firmetipi.archive')->listCheck(true); + } + + $childBar->standardButton('duplicate') + ->text('JTOOLBAR_DUPLICATE') + ->icon('fas fa-copy') + ->task('firmetipi.duplicate') + ->listCheck(true); + + if (isset($this->items[0]->checked_out)) + { + $childBar->checkin('firmetipi.checkin')->listCheck(true); + } + + if (isset($this->items[0]->state)) + { + $childBar->trash('firmetipi.trash')->listCheck(true); + } + } + + + + // Show trash and delete for components that uses the state field + if (isset($this->items[0]->state)) + { + + if ($this->state->get('filter.state') == ContentComponent::CONDITION_TRASHED && $canDo->get('core.delete')) + { + $toolbar->delete('firmetipi.delete') + ->text('JTOOLBAR_EMPTY_TRASH') + ->message('JGLOBAL_CONFIRM_DELETE') + ->listCheck(true); + } + } + + if ($canDo->get('core.admin')) + { + $toolbar->preferences('com_circolari'); + } + + // Set sidebar action + Sidebar::setAction('index.php?option=com_circolari&view=firmetipi'); + } + + /** + * Method to order fields + * + * @return void + */ + protected function getSortFields() + { + return array( + 'a.`id`' => Text::_('JGRID_HEADING_ID'), + 'a.`state`' => Text::_('JSTATUS'), + 'a.`ordering`' => Text::_('JGRID_HEADING_ORDERING'), + 'a.`nome`' => Text::_('COM_HIGHLIGHTS_ETICHETTE_NOME'), + 'a.`lingua`' => Text::_('COM_HIGHLIGHTS_ETICHETTE_LINGUA'), + ); + } + + /** + * Check if state is set + * + * @param mixed $state State + * + * @return bool + */ + public function getState($state) + { + return isset($this->state->{$state}) ? $this->state->{$state} : false; + } +} diff --git a/administrator/tmpl/circolare/default.php b/administrator/tmpl/circolare/default.php new file mode 100644 index 0000000..adae16f --- /dev/null +++ b/administrator/tmpl/circolare/default.php @@ -0,0 +1,32 @@ + + * @copyright 2023 Super User + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access +defined('_JEXEC') or die; + +use \Joomla\CMS\HTML\HTMLHelper; +use \Joomla\CMS\Factory; +use \Joomla\CMS\Uri\Uri; +use \Joomla\CMS\Router\Route; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Session\Session; +use Joomla\Utilities\ArrayHelper; + + +?> + +
+ + + + +
+ +
+ diff --git a/administrator/tmpl/circolare/edit.php b/administrator/tmpl/circolare/edit.php new file mode 100644 index 0000000..0ddfdea --- /dev/null +++ b/administrator/tmpl/circolare/edit.php @@ -0,0 +1,52 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access +defined('_JEXEC') or die; + +use \Joomla\CMS\HTML\HTMLHelper; +use \Joomla\CMS\Factory; +use \Joomla\CMS\Uri\Uri; +use \Joomla\CMS\Router\Route; +use \Joomla\CMS\Language\Text; + +$wa = $this->document->getWebAssetManager(); +$wa->useScript('keepalive') + ->useScript('form.validate'); +HTMLHelper::_('bootstrap.tooltip'); +?> + +
+ + + 'Circolari')); ?> + +
+
+
+ + form->renderField('title'); ?> + form->renderField('description'); ?> + form->renderField('attachment'); ?> + form->renderField('image'); ?> + form->renderField('tipologia_firma'); ?> +
+
+
+ + + + form->renderField('created_by'); ?> + form->renderField('modified_by'); ?> + + + +
diff --git a/administrator/tmpl/circolares/default.php b/administrator/tmpl/circolares/default.php new file mode 100644 index 0000000..4df70c0 --- /dev/null +++ b/administrator/tmpl/circolares/default.php @@ -0,0 +1,148 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access +defined('_JEXEC') or die; + + +use \Joomla\CMS\HTML\HTMLHelper; +use \Joomla\CMS\Factory; +use \Joomla\CMS\Uri\Uri; +use \Joomla\CMS\Router\Route; +use \Joomla\CMS\Layout\LayoutHelper; +use \Joomla\CMS\Language\Text; +use Joomla\CMS\Session\Session; + +HTMLHelper::_('bootstrap.tooltip'); +HTMLHelper::_('behavior.multiselect'); + +// Import CSS +$wa = $this->document->getWebAssetManager(); +$wa->useStyle('com_circolari.admin') + ->useScript('com_circolari.admin'); + +$user = Factory::getApplication()->getIdentity(); +$userId = $user->get('id'); +$listOrder = $this->state->get('list.ordering'); +$listDirn = $this->state->get('list.direction'); +$canOrder = $user->authorise('core.edit.state', 'com_circolari'); + +$saveOrder = $listOrder == 'a.ordering'; + +if (!empty($saveOrder)) { + $saveOrderingUrl = 'index.php?option=com_circolari&task=circolares.saveOrderAjax&tmpl=component&' . Session::getFormToken() . '=1'; + HTMLHelper::_('draggablelist.draggable'); +} + +?> + +
+
+
+
+ $this)); ?> + +
+ + + + + + + + + + items[0]->ordering)): ?> + + + + + + + + + + + + + + + + + + items as $i => $item) : + $canEdit = $user->authorise('core.edit', 'com_circolari'); + $canChange = $user->authorise('core.edit.state', 'com_circolari'); + ?> + + + + + + + items[0]->ordering)) : ?> + + + + + + + + + +
+ + + + +Scadenza + + + + + + + +
+ pagination->getListFooter(); ?> +
+ id); ?> + + + title, ENT_QUOTES, 'UTF-8'); ?> + + tipologia_firma, ENT_QUOTES, "UTF-8"); ?>firma_obbligatoria ? 'Sì' : 'No'; ?>scadenza; ?> + + + + + + + + state, $i, 'circolares.', $canChange, 'cb'); ?>id; ?>
+ + + + + +
+
+
+
\ No newline at end of file diff --git a/administrator/tmpl/firmatipo/default.php b/administrator/tmpl/firmatipo/default.php new file mode 100644 index 0000000..adae16f --- /dev/null +++ b/administrator/tmpl/firmatipo/default.php @@ -0,0 +1,32 @@ + + * @copyright 2023 Super User + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +// No direct access +defined('_JEXEC') or die; + +use \Joomla\CMS\HTML\HTMLHelper; +use \Joomla\CMS\Factory; +use \Joomla\CMS\Uri\Uri; +use \Joomla\CMS\Router\Route; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Session\Session; +use Joomla\Utilities\ArrayHelper; + + +?> + +
+ + + + +
+ +
+ diff --git a/administrator/tmpl/firmatipo/edit.php b/administrator/tmpl/firmatipo/edit.php new file mode 100644 index 0000000..de56235 --- /dev/null +++ b/administrator/tmpl/firmatipo/edit.php @@ -0,0 +1,55 @@ + + * @copyright 2024 Eddy Prosperi + * @license GNU General Public License versione 2 o successiva; vedi LICENSE.txt + */ + +// No direct access +defined('_JEXEC') or die; + +use \Joomla\CMS\HTML\HTMLHelper; +use \Joomla\CMS\Factory; +use \Joomla\CMS\Uri\Uri; +use \Joomla\CMS\Router\Route; +use \Joomla\CMS\Language\Text; + +$wa = $this->document->getWebAssetManager(); +$wa->useScript('keepalive') + ->useScript('form.validate'); +HTMLHelper::_('bootstrap.tooltip'); +?> + +
+ + + 'etichetta')); ?> + +
+
+
+ + form->renderField('nome'); ?> + form->renderField('lingua'); ?> +
+
+
+ + + + + + form->renderField('created_by'); ?> + form->renderField('modified_by'); ?> + + + + + + + +
diff --git a/administrator/tmpl/firmetipi/default.php b/administrator/tmpl/firmetipi/default.php new file mode 100644 index 0000000..ec94a05 --- /dev/null +++ b/administrator/tmpl/firmetipi/default.php @@ -0,0 +1,47 @@ + +getIdentity(); +$listOrder = $this->state->get('list.ordering'); +$listDirn = $this->state->get('list.direction'); +?> + +
+
+
+ + + + + + + + + + + items as $i => $item) : ?> + + + + + + + + +
#
+ + nome, ENT_QUOTES, 'UTF-8'); ?> + + descrizione, ENT_QUOTES, 'UTF-8'); ?>id; ?>
+
+
+ +
diff --git a/administrator/tmpl/firmetipi/edit.php b/administrator/tmpl/firmetipi/edit.php new file mode 100644 index 0000000..38245e8 --- /dev/null +++ b/administrator/tmpl/firmetipi/edit.php @@ -0,0 +1,30 @@ + + + +
+
+
+ form->getFieldsets() as $fieldset) : ?> + form->getFieldset($fieldset->name); ?> + +
+ label; ?> + input; ?> +
+ + +
+
+ + +
diff --git a/administrator/tmpl/index.html b/administrator/tmpl/index.html new file mode 100644 index 0000000..42682b4 --- /dev/null +++ b/administrator/tmpl/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/circolari.xml b/circolari.xml new file mode 100644 index 0000000..ef60936 --- /dev/null +++ b/circolari.xml @@ -0,0 +1,91 @@ + + + com_circolari + 2025-07-22 + 2025 Tommaso Cippitelli + GNU General Public License version 2 or later; see LICENSE.txt + Tommaso Cippitelli + tommaso.cippitelli@protocollicreativi.it + http:// + CVS: 1.0.0 + + Pcrt\Component\Circolari + + + + + + sql/install.mysql.utf8.sql + + + + + sql/updates + + + + + sql/uninstall.mysql.utf8.sql + + + + + + + src + + tmpl + + + css + js + joomla.asset.json + + + + en-GB/com_circolari.ini + it-IT/com_circolari.ini + + + + COM_CIRCOLARI + + COM_CIRCOLARI_TITLE_CIRCOLARES + COM_CIRCOLARI_TITLE_FIRMETIPI + + + + access.xml + config.xml + forms + src + tmpl + services + presets + sql + + + + en-GB/com_circolari.ini + en-GB/com_circolari.sys.ini + it-IT/com_circolari.ini + it-IT/com_circolari.sys.ini + + + + +
+ +
+
+
+ + + + + + https://nocdn.component-creator.com/index.php?task=builder.preupdatecheckhook&option=com_combuilder&component=NzY0NjYtMjE1NzU5 + +
+ + diff --git a/installer/index.html b/installer/index.html new file mode 100644 index 0000000..42682b4 --- /dev/null +++ b/installer/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/css/admin.css b/media/css/admin.css new file mode 100644 index 0000000..41e2e7b --- /dev/null +++ b/media/css/admin.css @@ -0,0 +1,11 @@ +.jcc-color-box { + float: left; + width: 15px; + height: 15px; + margin-right: 5px; + border: 1px solid rgba(0, 0, 0, .2); +} + +.other-filters{ + padding: 0 14px; +} \ No newline at end of file diff --git a/media/css/list.css b/media/css/list.css new file mode 100644 index 0000000..8399d4e --- /dev/null +++ b/media/css/list.css @@ -0,0 +1,7 @@ +/** + * @version CVS: 1.0.0 + * @package com_circolari + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + * @author Tommaso Cippitelli + */ diff --git a/media/joomla.asset.json b/media/joomla.asset.json new file mode 100644 index 0000000..55ffd76 --- /dev/null +++ b/media/joomla.asset.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json", + "name": "com_circolari", + "version": "CVS: 1.0.0", + "license": "GNU General Public License version 2 or later; see LICENSE.txt", + "assets": [ + { + "name": "com_circolari.admin", + "type": "style", + "uri": "com_circolari/admin.css" + }, + { + "name": "com_circolari.admin", + "type": "script", + "uri": "com_circolari/admin.js", + "dependencies": [ + "jquery" + ], + "attributes": { + "defer": true + } + }, + { + "name": "com_circolari.list", + "type": "style", + "uri": "com_circolari/list.css" + } + ] +} diff --git a/media/js/admin.js b/media/js/admin.js new file mode 100644 index 0000000..115e0fb --- /dev/null +++ b/media/js/admin.js @@ -0,0 +1,32 @@ +window.Joomla = window.Joomla || {}; + +(function (window, Joomla) { + Joomla.toggleField = function (id, task, field) { + + var f = document.adminForm, i = 0, cbx, cb = f[ id ]; + + if (!cb) return false; + + while (true) { + cbx = f[ 'cb' + i ]; + + if (!cbx) break; + + cbx.checked = false; + i++; + } + + var inputField = document.createElement('input'); + + inputField.type = 'hidden'; + inputField.name = 'field'; + inputField.value = field; + f.appendChild(inputField); + + cb.checked = true; + f.boxchecked.value = 1; + Joomla.submitform(task); + + return false; + }; +})(window, Joomla); \ No newline at end of file diff --git a/site/forms/index.html b/site/forms/index.html new file mode 100644 index 0000000..42682b4 --- /dev/null +++ b/site/forms/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/site/languages/en-GB/com_circolari.ini b/site/languages/en-GB/com_circolari.ini new file mode 100644 index 0000000..793487c --- /dev/null +++ b/site/languages/en-GB/com_circolari.ini @@ -0,0 +1,43 @@ +COM_CIRCOLARI = "Circolari" +COM_CIRCOLARI_ITEM_SAVED_SUCCESSFULLY = "Item saved successfully" +COM_CIRCOLARI_ITEM_DELETED_SUCCESSFULLY = "Item deleted successfully" +COM_CIRCOLARI_ITEM_DELETED_UNSUCCESSFULLY = "Could not delete item" +COM_CIRCOLARI_ITEM_DOESNT_EXIST = "Item does not exist" +COM_CIRCOLARI_ITEM_NOT_LOADED = "Could not load the item" +COM_CIRCOLARI_VIEW_FILE = "[View File]" +COM_CIRCOLARI_ADD_ITEM = "Add" +COM_CIRCOLARI_EDIT_ITEM = "Edit" +COM_CIRCOLARI_DELETE_ITEM = "Delete" +COM_CIRCOLARI_DELETE_MESSAGE = "Are you sure that you want delete this item?" +COM_CIRCOLARI_DELETE_CONFIRM = "You're about to delete the item #%s. Are you sure?" +COM_CIRCOLARI_PUBLISH_ITEM = "Publish" +COM_CIRCOLARI_UNPUBLISH_ITEM = "Unpublish" +COM_CIRCOLARI_NO_ITEMS = "There are no items in the list" +COM_CIRCOLARI_SEARCH_TOOLS = "Search Tools" +COM_CIRCOLARI_SEARCH_TOOLS_DESC = "" +COM_CIRCOLARI_SEARCH_FILTER_SUBMIT = "Search" +COM_CIRCOLARI_SEARCH_FILTER_CLEAR = "Clear" +COM_CIRCOLARI_SEARCH_FILTER_DATE_FORMAT = "Dates should be in this format: \"YYYY-MM-DD\". Some filter fields have been ignored." + +COM_CIRCOLARI_ERROR_MESSAGE_NOT_AUTHORISED = "You don't have permission to access this. Please contact a website administrator if this is incorrect." + +COM_CIRCOLARI_ADD_ITEM_TITLE = "Add" +COM_CIRCOLARI_EDIT_ITEM_TITLE = "Edit %s" + +COM_CIRCOLARI_ACTION_PERMISSIONS_LABEL = "Permissions" +COM_CIRCOLARI_VALIDATION_FORM_FAILED = "Invalid form" +COM_CIRCOLARI_CHECKEDIN_SUCCESSFULLY = "Item successfully checked in" + + +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_ID="ID" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_STATE="State" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_ORDERING="Order" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_CHECKED_OUT="N/A" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_CHECKED_OUT_TIME="N/A" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_CREATED_BY="Created by" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_MODIFIED_BY="Modified by" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_TITLE="Title" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_DESCRIPTION="Description" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_ATTACHMENT="Attachment" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_IMAGE="Image" + diff --git a/site/languages/it-IT/com_circolari.ini b/site/languages/it-IT/com_circolari.ini new file mode 100644 index 0000000..793487c --- /dev/null +++ b/site/languages/it-IT/com_circolari.ini @@ -0,0 +1,43 @@ +COM_CIRCOLARI = "Circolari" +COM_CIRCOLARI_ITEM_SAVED_SUCCESSFULLY = "Item saved successfully" +COM_CIRCOLARI_ITEM_DELETED_SUCCESSFULLY = "Item deleted successfully" +COM_CIRCOLARI_ITEM_DELETED_UNSUCCESSFULLY = "Could not delete item" +COM_CIRCOLARI_ITEM_DOESNT_EXIST = "Item does not exist" +COM_CIRCOLARI_ITEM_NOT_LOADED = "Could not load the item" +COM_CIRCOLARI_VIEW_FILE = "[View File]" +COM_CIRCOLARI_ADD_ITEM = "Add" +COM_CIRCOLARI_EDIT_ITEM = "Edit" +COM_CIRCOLARI_DELETE_ITEM = "Delete" +COM_CIRCOLARI_DELETE_MESSAGE = "Are you sure that you want delete this item?" +COM_CIRCOLARI_DELETE_CONFIRM = "You're about to delete the item #%s. Are you sure?" +COM_CIRCOLARI_PUBLISH_ITEM = "Publish" +COM_CIRCOLARI_UNPUBLISH_ITEM = "Unpublish" +COM_CIRCOLARI_NO_ITEMS = "There are no items in the list" +COM_CIRCOLARI_SEARCH_TOOLS = "Search Tools" +COM_CIRCOLARI_SEARCH_TOOLS_DESC = "" +COM_CIRCOLARI_SEARCH_FILTER_SUBMIT = "Search" +COM_CIRCOLARI_SEARCH_FILTER_CLEAR = "Clear" +COM_CIRCOLARI_SEARCH_FILTER_DATE_FORMAT = "Dates should be in this format: \"YYYY-MM-DD\". Some filter fields have been ignored." + +COM_CIRCOLARI_ERROR_MESSAGE_NOT_AUTHORISED = "You don't have permission to access this. Please contact a website administrator if this is incorrect." + +COM_CIRCOLARI_ADD_ITEM_TITLE = "Add" +COM_CIRCOLARI_EDIT_ITEM_TITLE = "Edit %s" + +COM_CIRCOLARI_ACTION_PERMISSIONS_LABEL = "Permissions" +COM_CIRCOLARI_VALIDATION_FORM_FAILED = "Invalid form" +COM_CIRCOLARI_CHECKEDIN_SUCCESSFULLY = "Item successfully checked in" + + +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_ID="ID" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_STATE="State" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_ORDERING="Order" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_CHECKED_OUT="N/A" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_CHECKED_OUT_TIME="N/A" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_CREATED_BY="Created by" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_MODIFIED_BY="Modified by" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_TITLE="Title" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_DESCRIPTION="Description" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_ATTACHMENT="Attachment" +COM_CIRCOLARI_FORM_LBL_CIRCOLARE_IMAGE="Image" + diff --git a/site/src/Controller/DisplayController.php b/site/src/Controller/DisplayController.php new file mode 100644 index 0000000..fd2170f --- /dev/null +++ b/site/src/Controller/DisplayController.php @@ -0,0 +1,64 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Site\Controller; + +\defined('_JEXEC') or die; + +use Joomla\CMS\Component\ComponentHelper; +use Joomla\CMS\Factory; +use Joomla\CMS\Language\Text; +use Joomla\CMS\MVC\Factory\MVCFactoryInterface; + +/** + * Display Component Controller + * + * @since 1.0.0 + */ +class DisplayController extends \Joomla\CMS\MVC\Controller\BaseController +{ + /** + * Constructor. + * + * @param array $config An optional associative array of configuration settings. + * Recognized key values include 'name', 'default_task', 'model_path', and + * 'view_path' (this list is not meant to be comprehensive). + * @param MVCFactoryInterface $factory The factory. + * @param CMSApplication $app The JApplication for the dispatcher + * @param Input $input Input + * + * @since 1.0.0 + */ + public function __construct($config = array(), ?MVCFactoryInterface $factory = null, $app = null, $input = null) + { + parent::__construct($config, $factory, $app, $input); + } + + /** + * Method to display a view. + * + * @param boolean $cachable If true, the view output will be cached. + * @param boolean $urlparams An array of safe URL parameters and their variable types, for valid values see {@link InputFilter::clean()}. + * + * @return \Joomla\CMS\MVC\Controller\BaseController This object to support chaining. + * + * @since 1.0.0 + */ + public function display($cachable = false, $urlparams = false) + { + + $view = $this->input->getCmd('view', 'circolares'); + $view = $view == "featured" ? 'circolares' : $view; + $this->input->set('view', $view); + + + parent::display($cachable, $urlparams); + return $this; + } +} diff --git a/site/src/Field/CreatedbyField.php b/site/src/Field/CreatedbyField.php new file mode 100644 index 0000000..1bd5a54 --- /dev/null +++ b/site/src/Field/CreatedbyField.php @@ -0,0 +1,67 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Site\Field; + +defined('JPATH_BASE') or die; + +use \Joomla\CMS\Factory; +use \Joomla\CMS\Form\FormField; +use \Joomla\CMS\User\UserFactoryInterface; + +/** + * Supports an HTML select list of categories + * + * @since 1.0.0 + */ +class CreatedbyField extends FormField +{ + /** + * The form field type. + * + * @var string + * @since 1.0.0 + */ + protected $type = 'createdby'; + + /** + * Method to get the field input markup. + * + * @return string The field input markup. + * + * @since 1.0.0 + */ + protected function getInput() + { + // Initialize variables. + $html = array(); + + // Load user + $user_id = $this->value; + + if ($user_id) + { + $container = \Joomla\CMS\Factory::getContainer(); + $userFactory = $container->get(UserFactoryInterface::class); + $user = $userFactory->loadUserById($user_id); + } + else + { + $user = Factory::getApplication()->getIdentity(); + $html[] = ''; + } + + if (!$this->hidden) + { + $html[] = "
" . $user->name . " (" . $user->username . ")
"; + } + + return implode($html); + } +} diff --git a/site/src/Field/ForeignkeyField.php b/site/src/Field/ForeignkeyField.php new file mode 100644 index 0000000..486ef9b --- /dev/null +++ b/site/src/Field/ForeignkeyField.php @@ -0,0 +1,296 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Site\Field; + +defined('JPATH_BASE') or die; + +use \Joomla\CMS\Factory; +use \Joomla\CMS\HTML\HTMLHelper; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Form\Field\ListField; + +/** + * Supports a value from an external table + * + * @since 1.0.0 + */ +class ForeignKeyField extends ListField +{ + /** + * The form field type. + * + * @var string + * @since 1.0.0 + */ + protected $type = 'foreignkey'; + + protected $layout = 'joomla.form.field.list-fancy-select'; + + /** + * The translate. + * + * @var boolean + * @since 1.0.0 + */ + protected $translate = true; + + protected $header = false; + + private $input_type; + + private $table; + + private $key_field; + + private $value_field; + + private $option_key_field; + + private $option_value_field; + + private $condition; + + /** + * Method to get the field input markup. + * + * @return string The field input markup. + * + * @since 1.0.0 + */ + protected function processQuery() + { + // Type of input the field shows + $this->input_type = $this->getAttribute('input_type'); + + // Database Table + $this->table = $this->getAttribute('table'); + + // The field that the field will save on the database + $this->key_field = (string) $this->getAttribute('key_field'); + + // The column that the field shows in the input + $this->value_field = (string) $this->getAttribute('value_field'); + + // The option field that the field will save on the database + $this->option_key_field = (string) $this->getAttribute('option_key_field'); + + // The option value that the field shows in the input + $this->option_value_field = (string) $this->getAttribute('option_value_field'); + + // Flag to identify if the fk_value is multiple + $this->value_multiple = (int) $this->getAttribute('value_multiple', 0); + + $this->required = (string) $this->getAttribute('required', 0); + + // Flag to identify if the fk_value hides the trashed items + $this->hideTrashed = (int) $this->getAttribute('hide_trashed', 0); + + // Flag to identify if the fk_value hides the unpublished items + $this->hideUnpublished = (int) $this->getAttribute('hide_unpublished', 0); + + // Flag to identify if the fk_value hides the published items + $this->hidePublished = (int) $this->getAttribute('hide_published', 0); + + // Flag to identify if the fk_value hides the archived items + $this->hideArchived = (int) $this->getAttribute('hide_archived', 0); + + // Flag to identify if the fk has default order + $this->fk_ordering = (string) $this->getAttribute('fk_ordering'); + + // The where SQL for foreignkey + $this->condition = (string) $this->getAttribute('condition'); + + // Flag for translate options + $this->translate = (bool) $this->getAttribute('translate'); + + // Initialize variables. + $html = ''; + $fk_value = ''; + + // Load all the field options + $db = Factory::getContainer()->get('DatabaseDriver'); + $query = $db->getQuery(true); + + // Support for multiple fields on fk_values + if ($this->value_multiple == 1) + { + // Get the fields for multiple value + $this->value_fields = (string) $this->getAttribute('value_field_multiple'); + $this->value_fields = explode(',', $this->value_fields); + $this->separator = (string) $this->getAttribute('separator'); + + $fk_value = ' CONCAT('; + + foreach ($this->value_fields as $field) + { + $fk_value .= $db->quoteName($field) . ', \'' . $this->separator . '\', '; + } + + $fk_value = substr($fk_value, 0, -(strlen($this->separator) + 6)); + $fk_value .= ') AS ' . $db->quoteName($this->value_field); + } + else + { + $fk_value = $db->quoteName($this->value_field); + } + + $query + ->select( + array( + $db->quoteName($this->key_field), + $fk_value + ) + ) + ->from($this->table); + + if ($this->hideTrashed) + { + $query->where($db->quoteName('state') . ' != -2'); + } + + if ($this->hideUnpublished) + { + $query->where($db->quoteName('state') . ' != 0'); + } + + if ($this->hidePublished) + { + $query->where($db->quoteName('state') . ' != 1'); + } + + if ($this->hideArchived) + { + $query->where($db->quoteName('state') . ' != 2'); + } + + if ($this->fk_ordering) + { + $query->order($this->fk_ordering); + } + + if($this->condition) + { + $query->where($this->condition); + } + + + + return $query; + } + + /** + * Method to get the field input for a foreignkey field. + * + * @return string The field input. + * + * @since 1.0.0 + */ + protected function getInput() + { + $data = $this->getLayoutData(); + + if (!\is_array($this->value) && !empty($this->value)) + { + if (\is_object($this->value)) + { + $this->value = get_object_vars($this->value); + } + + // String in format 2,5,4 + if (\is_string($this->value)) + { + $this->value = explode(',', $this->value); + } + + // Integer is given + if (\is_int($this->value)) + { + $this->value = array($this->value); + } + + $data['value'] = $this->value; + } + + $data['options'] = $this->getOptions(); + + return $this->getRenderer($this->layout)->render($data); + } + + /** + * Method to get the field options. + * + * @return array The field option objects. + * + * @since 1.0.0 + */ + protected function getOptions() + { + $options = array(); + $db = Factory::getContainer()->get('DatabaseDriver'); + try + { + $db->setQuery($this->processQuery()); + $results = $db->loadObjectList(); + } + catch (ExecutionFailureException $e) + { + Factory::getApplication()->enqueueMessage(Text::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error'); + } + + // Add header. + if (!empty($this->header)) + { + $options[] = (object) ["value" => '', "text" => Text::_($this->header)]; + } + + if(!empty($this->option_value_field) || !empty($this->option_key_field)) + { + $options[] = (object) ["value" => $this->option_key_field, "text" => Text::_($this->option_value_field)]; + } + + // Build the field options. + if (!empty($results)) + { + foreach ($results as $item) + { + $options[] = (object) [ + "value" => $item->{$this->key_field}, + "text" => $this->translate == true ? Text::_($item->{$this->value_field}) : $item->{$this->value_field} + ]; + } + } + + // Merge any additional options in the XML definition. + $options = array_merge(parent::getOptions(), $options); + + return $options; + } + + /** + * Wrapper method for getting attributes from the form element + * + * @param string $attr_name Attribute name + * @param mixed $default Optional value to return if attribute not found + * + * @return mixed The value of the attribute if it exists, null otherwise + */ + public function getAttribute($attr_name, $default = null) + { + if (!empty($this->element[$attr_name])) + { + return $this->element[$attr_name]; + } + else + { + return $default; + } + } +} diff --git a/site/src/Field/ModifiedbyField.php b/site/src/Field/ModifiedbyField.php new file mode 100644 index 0000000..07d0579 --- /dev/null +++ b/site/src/Field/ModifiedbyField.php @@ -0,0 +1,53 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Site\Field; + +defined('JPATH_BASE') or die; + +use \Joomla\CMS\Factory; +use \Joomla\CMS\Form\FormField; + +/** + * Supports an HTML select list of categories + * + * @since 1.0.0 + */ +class ModifiedbyField extends FormField +{ + /** + * The form field type. + * + * @var string + * @since 1.0.0 + */ + protected $type = 'modifiedby'; + + /** + * Method to get the field input markup. + * + * @return string The field input markup. + * + * @since 1.0.0 + */ + protected function getInput() + { + // Initialize variables. + $html = array(); + $user = Factory::getApplication()->getIdentity(); + $html[] = ''; + + if (!$this->hidden) + { + $html[] = "
" . $user->name . " (" . $user->username . ")
"; + } + + return implode($html); + } +} diff --git a/site/src/Field/NestedparentField.php b/site/src/Field/NestedparentField.php new file mode 100644 index 0000000..8fb468c --- /dev/null +++ b/site/src/Field/NestedparentField.php @@ -0,0 +1,83 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Site\Field; + +defined('JPATH_BASE') or die; + +use Joomla\CMS\Helper\UserGroupsHelper; +use \Joomla\CMS\Factory; +use Joomla\CMS\Form\Field\ListField; + +/** + * Supports an HTML select list of categories + * + * @since 1.0.0 + */ +class NestedparentField extends ListField +{ + /** + * The form field type. + * + * @var string + * @since 1.0.0 + */ + protected $type = 'nestedparent'; + + /** + * Method to get the field options. + * + * @return array The field option objects. + * + * @since 1.0.0 + */ + protected function getOptions() + { + $options = array(); + $table = $this->getAttribute('table'); + + $db = Factory::getContainer()->get('DatabaseDriver'); + $query = $db->getQuery(true) + ->select('DISTINCT(a.id) AS value, a.title AS text, a.level, a.lft') + ->from($table . ' AS a'); + + + // Prevent parenting to children of this item. + if ($id = $this->form->getValue('id')) + { + $query->join('LEFT', $db->quoteName($table) . ' AS p ON p.id = ' . (int) $id) + ->where('NOT(a.lft >= p.lft AND a.rgt <= p.rgt)'); + } + + $query->order('a.lft ASC'); + + // Get the options. + $db->setQuery($query); + + try + { + $options = $db->loadObjectList(); + } + catch (\RuntimeException $e) + { + \JError::raiseWarning(500, $e->getMessage()); + } + + // Pad the option text with spaces using depth level as a multiplier. + for ($i = 0, $n = count($options); $i < $n; $i++) + { + $options[$i]->text = str_repeat('- ', $options[$i]->level) . $options[$i]->text; + } + + // Merge any additional options in the XML definition. + $options = array_merge(parent::getOptions(), $options); + + return $options; + } +} diff --git a/site/src/Field/SubmitField.php b/site/src/Field/SubmitField.php new file mode 100644 index 0000000..3ed3d79 --- /dev/null +++ b/site/src/Field/SubmitField.php @@ -0,0 +1,49 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Site\Field; + +// Check to ensure this file is included in Joomla! +defined('_JEXEC') or die('Restricted access'); + +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Form\FormField; + +/** + * Class SubmitField + * + * @since 1.0.0 + */ +class SubmitField extends FormField +{ + protected $type = 'submit'; + + protected $value; + + protected $for; + + /** + * Get a form field markup for the input + * + * @return string + */ + public function getInput() + { + $this->value = $this->getAttribute('value'); + + return ''; + } +} diff --git a/site/src/Field/TimecreatedField.php b/site/src/Field/TimecreatedField.php new file mode 100644 index 0000000..4342c73 --- /dev/null +++ b/site/src/Field/TimecreatedField.php @@ -0,0 +1,65 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Site\Field; + +defined('JPATH_BASE') or die; + +use \Joomla\CMS\Factory; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Form\FormField; +use \Joomla\CMS\Date\Date; +use Joomla\CMS\HTML\HTMLHelper; + +/** + * Supports an HTML select list of categories + * + * @since 1.0.0 + */ +class TimecreatedField extends FormField +{ + /** + * The form field type. + * + * @var string + * @since 1.0.0 + */ + protected $type = 'timecreated'; + + /** + * Method to get the field input markup. + * + * @return string The field input markup. + * + * @since 1.0.0 + */ + protected function getInput() + { + // Initialize variables. + $html = array(); + + $time_created = $this->value; + + if (!strtotime($time_created)) + { + $time_created = Factory::getDate()->toSql(); + $html[] = ''; + } + + $hidden = (boolean) $this->element['hidden']; + + if ($hidden == null || !$hidden) + { + $pretty_date = HTMLHelper::_('date', $time_created, Text::_('DATE_FORMAT_LC2'), true); + $html[] = "
" . $pretty_date . "
"; + } + + return implode($html); + } +} diff --git a/site/src/Field/TimeupdatedField.php b/site/src/Field/TimeupdatedField.php new file mode 100644 index 0000000..cb7f6b0 --- /dev/null +++ b/site/src/Field/TimeupdatedField.php @@ -0,0 +1,68 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Site\Field; + +defined('JPATH_BASE') or die; + +use \Joomla\CMS\Factory; +use \Joomla\CMS\Language\Text; +use \Joomla\CMS\Form\FormField; +use \Joomla\CMS\Date\Date; +use Joomla\CMS\HTML\HTMLHelper; + +/** + * Supports an HTML select list of categories + * + * @since 1.0.0 + */ +class TimeupdatedField extends FormField +{ + /** + * The form field type. + * + * @var string + * @since 1.0.0 + */ + protected $type = 'timeupdated'; + + /** + * Method to get the field input markup. + * + * @return string The field input markup. + * + * @since 1.0.0 + */ + protected function getInput() + { + // Initialize variables. + $html = array(); + + $old_time_updated = $this->value; + $hidden = (boolean) $this->element['hidden']; + + if ($hidden == null || !$hidden) + { + if (!strtotime($old_time_updated)) + { + $html[] = '-'; + } + else + { + $pretty_date = HTMLHelper::_('date', $old_time_updated, Text::_('DATE_FORMAT_LC2'), true); + $html[] = "
" . $pretty_date . "
"; + } + } + + $time_updated = Factory::getDate()->toSql(); + $html[] = ''; + + return implode($html); + } +} diff --git a/site/src/Field/index.html b/site/src/Field/index.html new file mode 100644 index 0000000..42682b4 --- /dev/null +++ b/site/src/Field/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/site/src/Helper/CircolariHelper.php b/site/src/Helper/CircolariHelper.php new file mode 100644 index 0000000..836cf14 --- /dev/null +++ b/site/src/Helper/CircolariHelper.php @@ -0,0 +1,71 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Site\Helper; + +defined('_JEXEC') or die; + +use \Joomla\CMS\Factory; +use \Joomla\CMS\MVC\Model\BaseDatabaseModel; + +/** + * Class CircolariFrontendHelper + * + * @since 1.0.0 + */ +class CircolariHelper +{ + + + /** + * Gets the files attached to an item + * + * @param int $pk The item's id + * + * @param string $table The table's name + * + * @param string $field The field's name + * + * @return array The files + */ + public static function getFiles($pk, $table, $field) + { + $db = Factory::getContainer()->get('DatabaseDriver'); + $query = $db->getQuery(true); + + $query + ->select($field) + ->from($table) + ->where('id = ' . (int) $pk); + + $db->setQuery($query); + + return explode(',', $db->loadResult()); + } + + /** + * Gets the edit permission for an user + * + * @param mixed $item The item + * + * @return bool + */ + public static function canUserEdit($item) + { + $permission = false; + $user = Factory::getApplication()->getIdentity(); + + if ($user->authorise('core.edit', 'com_circolari') || (isset($item->created_by) && $user->authorise('core.edit.own', 'com_circolari') && $item->created_by == $user->id) || $user->authorise('core.create', 'com_circolari')) + { + $permission = true; + } + + return $permission; + } +} diff --git a/site/src/Helper/index.html b/site/src/Helper/index.html new file mode 100644 index 0000000..42682b4 --- /dev/null +++ b/site/src/Helper/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/site/src/Service/Category.php b/site/src/Service/Category.php new file mode 100644 index 0000000..c39c186 --- /dev/null +++ b/site/src/Service/Category.php @@ -0,0 +1,21 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Site\Service; +// No direct access +defined('_JEXEC') or die; + +use \Joomla\CMS\Categories\Categories; +/** + * Content Component Category Tree + * + * @since 1.0.0 + */ + diff --git a/site/src/Service/Router.php b/site/src/Service/Router.php new file mode 100644 index 0000000..cdb2142 --- /dev/null +++ b/site/src/Service/Router.php @@ -0,0 +1,95 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Site\Service; + +// No direct access +defined('_JEXEC') or die; + +use Joomla\CMS\Component\Router\RouterViewConfiguration; +use Joomla\CMS\Component\Router\RouterView; +use Joomla\CMS\Component\Router\Rules\StandardRules; +use Joomla\CMS\Component\Router\Rules\NomenuRules; +use Joomla\CMS\Component\Router\Rules\MenuRules; +use Joomla\CMS\Factory; +use Joomla\CMS\Categories\Categories; +use Joomla\CMS\Application\SiteApplication; +use Joomla\CMS\Categories\CategoryFactoryInterface; +use Joomla\CMS\Categories\CategoryInterface; +use Joomla\Database\DatabaseInterface; +use Joomla\CMS\Menu\AbstractMenu; +use Joomla\CMS\Component\ComponentHelper; + +/** + * Class CircolariRouter + * + */ +class Router extends RouterView +{ + private $noIDs; + /** + * The category factory + * + * @var CategoryFactoryInterface + * + * @since 1.0.0 + */ + private $categoryFactory; + + /** + * The category cache + * + * @var array + * + * @since 1.0.0 + */ + private $categoryCache = []; + + public function __construct(SiteApplication $app, AbstractMenu $menu, CategoryFactoryInterface $categoryFactory, DatabaseInterface $db) + { + $params = ComponentHelper::getParams('com_circolari'); + $this->noIDs = (bool) $params->get('sef_ids'); + $this->categoryFactory = $categoryFactory; + + + + parent::__construct($app, $menu); + + $this->attachRule(new MenuRules($this)); + $this->attachRule(new StandardRules($this)); + $this->attachRule(new NomenuRules($this)); + } + + + + + + + /** + * Method to get categories from cache + * + * @param array $options The options for retrieving categories + * + * @return CategoryInterface The object containing categories + * + * @since 1.0.0 + */ + private function getCategories(array $options = []): CategoryInterface + { + $key = serialize($options); + + if (!isset($this->categoryCache[$key])) + { + $this->categoryCache[$key] = $this->categoryFactory->createCategory($options); + } + + return $this->categoryCache[$key]; + } +} diff --git a/site/tmpl/index.html b/site/tmpl/index.html new file mode 100644 index 0000000..42682b4 --- /dev/null +++ b/site/tmpl/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webservices/src/Controller/INTERNAL_NAME_list.php b/webservices/src/Controller/INTERNAL_NAME_list.php new file mode 100644 index 0000000..fee2675 --- /dev/null +++ b/webservices/src/Controller/INTERNAL_NAME_list.php @@ -0,0 +1,37 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ +namespace Pcrt\Component\Circolari\Api\Controller; + +\defined('_JEXEC') or die; + +use Joomla\CMS\MVC\Controller\ApiController; + +/** + * The XXX_UCFIRST_INTERNAL_NAME_FORCE_LIST_XXX controller + * + * @since 1.0.0 + */ +class XXX_UCFIRST_INTERNAL_NAME_FORCE_LIST_XXXController extends ApiController +{ + /** + * The content type of the item. + * + * @var string + * @since 1.0.0 + */ + protected $contentType = 'XXX_INTERNAL_NAME_FORCE_LIST_XXX'; + + /** + * The default view for the display method. + * + * @var string + * @since 1.0.0 + */ + protected $default_view = 'XXX_INTERNAL_NAME_FORCE_LIST_XXX'; +} \ No newline at end of file diff --git a/webservices/src/View/INTERNAL_NAME_list/JsonapiView.php b/webservices/src/View/INTERNAL_NAME_list/JsonapiView.php new file mode 100644 index 0000000..9396658 --- /dev/null +++ b/webservices/src/View/INTERNAL_NAME_list/JsonapiView.php @@ -0,0 +1,42 @@ + + * @copyright 2025 Tommaso Cippitelli + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Pcrt\Component\Circolari\Api\View\XXX_UCFIRST_INTERNAL_NAME_XXX; + +\defined('_JEXEC') or die; + +use Joomla\CMS\MVC\View\JsonApiView as BaseApiView; + +/** + * The XXX_UCFIRST_INTERNAL_NAME_FORCE_LIST_XXX view + * + * @since 1.0.0 + */ +class JsonApiView extends BaseApiView +{ + /** + * The fields to render item in the documents + * + * @var array + * @since 1.0.0 + */ + protected $fieldsToRenderItem = [ + //XXX_FIELDS_TO_RENDER_ITEM + ]; + + /** + * The fields to render items in the documents + * + * @var array + * @since 1.0.0 + */ + protected $fieldsToRenderList = [ + //XXX_FIELDS_TO_RENDER_LIST + ]; +} \ No newline at end of file