update component
This commit is contained in:
22
administrator/forms/attachments.xml
Normal file
22
administrator/forms/attachments.xml
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form>
|
||||
<fields>
|
||||
<field
|
||||
name="path"
|
||||
type="media"
|
||||
label="File"
|
||||
required="true"
|
||||
preview="true"
|
||||
types="documents"
|
||||
directory="images/file"
|
||||
/>
|
||||
<field
|
||||
name="title"
|
||||
type="text"
|
||||
label="Titolo"
|
||||
required="false"
|
||||
maxlength="190"
|
||||
filter="string"
|
||||
/>
|
||||
</fields>
|
||||
</form>
|
||||
@ -18,16 +18,17 @@
|
||||
|
||||
<field name="description" type="editor" label="COM_CIRCOLARI_FORM_LBL_CIRCOLARE_DESCRIPTION"
|
||||
filter="safehtml" buttons="true" />
|
||||
<field name="attachment" type="media" label="COM_CIRCOLARI_FORM_LBL_CIRCOLARE_ATTACHMENT"
|
||||
directory="documents/circolari" preview="false" upload="true" />
|
||||
<field
|
||||
name="allegato_titolo"
|
||||
type="text"
|
||||
label="Titolo allegato"
|
||||
description="Nome leggibile mostrato accanto al file allegato"
|
||||
filter="string"
|
||||
name="attachments"
|
||||
type="subform"
|
||||
label="Allegati"
|
||||
description="Aggiungi uno o più allegati alla circolare"
|
||||
formsource="administrator/components/com_circolari/forms/attachments.xml"
|
||||
multiple="true"
|
||||
layout="joomla.form.field.subform.repeatable-table"
|
||||
/>
|
||||
|
||||
|
||||
<field name="image" type="media" label="COM_CIRCOLARI_FORM_LBL_CIRCOLARE_IMAGE"
|
||||
directory="images" preview="true" upload="true" />
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ CREATE TABLE IF NOT EXISTS `#__circolari_firmetipi` (
|
||||
|
||||
-- Tabella principale circolari
|
||||
CREATE TABLE IF NOT EXISTS `#__circolari` (`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`state` TINYINT(1) DEFAULT 1,
|
||||
`state` TINYINT(3) DEFAULT 1,
|
||||
`ordering` INT(11) DEFAULT 0,
|
||||
`checked_out` INT(11) UNSIGNED DEFAULT NULL,
|
||||
`checked_out_time` DATETIME DEFAULT NULL,
|
||||
@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS `#__circolari` (`id` INT(11) UNSIGNED NOT NULL AUTO_I
|
||||
`usergroup_id` INT(11) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`hits` INT(11) UNSIGNED NOT NULL DEFAULT 0,
|
||||
`title` VARCHAR(255) DEFAULT "",
|
||||
`alias` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`alias` VARCHAR(400) NOT NULL DEFAULT '',
|
||||
`description` TEXT,
|
||||
`attachment` VARCHAR(255) DEFAULT "",
|
||||
`image` VARCHAR(255) DEFAULT "",
|
||||
|
||||
29
administrator/sql/updates/1.2.2.sql
Normal file
29
administrator/sql/updates/1.2.2.sql
Normal file
@ -0,0 +1,29 @@
|
||||
-- CREA la nuova tabella (se non esiste)
|
||||
CREATE TABLE IF NOT EXISTS `#__circolari_attachments` (
|
||||
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`circolare_id` INT(11) UNSIGNED NOT NULL,
|
||||
`path` VARCHAR(255) NOT NULL,
|
||||
`title` VARCHAR(190) DEFAULT NULL,
|
||||
`ordering` INT(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_circolare_id` (`circolare_id`)
|
||||
) ENGINE=InnoDB DEFAULT COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- AGGIUNGI il nuovo campo alla tabella principale (se non esiste)
|
||||
ALTER TABLE `#__circolari`
|
||||
ADD COLUMN `attachment_id` INT(11) UNSIGNED DEFAULT NULL
|
||||
AFTER `scadenza`;
|
||||
|
||||
-- MIGRAZIONE DATI (opzionale): porta il vecchio allegato singolo nella nuova tabella
|
||||
INSERT INTO `#__circolari_attachments` (`circolare_id`, `path`, `title`, `ordering`)
|
||||
SELECT `id`, `attachment`, COALESCE(`allegato_titolo`, ''), 0
|
||||
FROM `#__circolari`
|
||||
WHERE `attachment` IS NOT NULL AND `attachment` <> '';
|
||||
|
||||
-- RIMUOVI i vecchi campi
|
||||
ALTER TABLE `#__circolari`
|
||||
DROP COLUMN `allegato_titolo`,
|
||||
DROP COLUMN `attachment`;
|
||||
|
||||
-- INDICE (opzionale, per il nuovo campo)
|
||||
ALTER TABLE `#__circolari` ADD KEY `idx_attachment_id` (`attachment_id`);
|
||||
@ -44,7 +44,7 @@ class CircolariComponent extends MVCComponent implements RouterServiceInterface,
|
||||
public function boot(ContainerInterface $container)
|
||||
{
|
||||
$db = $container->get('DatabaseDriver');
|
||||
$this->getRegistry()->register('circolari', new CIRCOLARI($db));
|
||||
$this->getRegistry()->register('circolari', new CIRCOLARI($db),true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,337 +1,70 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @version CVS: 1.0.0
|
||||
* @package Com_Circolari
|
||||
* @author Tommaso Cippitelli <tommaso.cippitelli@protocollicreativi.it>
|
||||
* @copyright 2025 Tommaso Cippitelli
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
* @author Tommaso C.
|
||||
* @license GNU GPL v2 or later
|
||||
*/
|
||||
|
||||
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;
|
||||
\defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Application\ApplicationHelper;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Model\AdminModel;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\CMS\Table\Table;
|
||||
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';
|
||||
public $typeAlias = 'com_circolari.circolare';
|
||||
protected $item = null;
|
||||
|
||||
/**
|
||||
* @var string Alias to manage history control
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public $typeAlias = 'com_circolari.circolare';
|
||||
/* =========================
|
||||
* JTable / Form plumbing
|
||||
* ========================= */
|
||||
|
||||
/**
|
||||
* @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 = 'Table', $config = array())
|
||||
public function getTable($type = 'Circolare', $prefix = 'Table', $config = [])
|
||||
{
|
||||
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)
|
||||
public function getForm($data = [], $loadData = true)
|
||||
{
|
||||
// Initialise variables.
|
||||
$app = Factory::getApplication();
|
||||
|
||||
// Get the form.
|
||||
$form = $this->loadForm(
|
||||
'com_circolari.circolare',
|
||||
'circolare',
|
||||
array(
|
||||
'control' => 'jform',
|
||||
'load_data' => $loadData
|
||||
)
|
||||
['control' => 'jform', 'load_data' => $loadData]
|
||||
);
|
||||
|
||||
|
||||
|
||||
if (empty($form)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $form;
|
||||
return $form ?: false;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Helpers DB lato admin
|
||||
* ========================= */
|
||||
|
||||
|
||||
/**
|
||||
* 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()
|
||||
/** Ritorna gli allegati della circolare in formato assoc list */
|
||||
public function getAttachments(int $circolareId): array
|
||||
{
|
||||
// Check the session for previously entered form data.
|
||||
$data = Factory::getApplication()->getUserState('com_circolari.edit.circolare.data', array());
|
||||
if ($circolareId <= 0) return [];
|
||||
|
||||
if (empty($data)) {
|
||||
if ($this->item === null) {
|
||||
$this->item = $this->getItem();
|
||||
}
|
||||
$db = Factory::getContainer()->get('DatabaseDriver');
|
||||
$q = $db->getQuery(true)
|
||||
->select(['id','path','title','ordering'])
|
||||
->from($db->quoteName('#__circolari_attachments'))
|
||||
->where($db->quoteName('circolare_id') . ' = ' . (int)$circolareId)
|
||||
->order($db->escape('ordering ASC, id ASC'));
|
||||
|
||||
$data = $this->item;
|
||||
}
|
||||
|
||||
if ((is_array($data) && empty($data['id'])) || (is_object($data) && empty($data->id))) {
|
||||
if (is_array($data)) {
|
||||
$data['categoria_id'] = (int)($data['categoria_id'] ?? 0) ?: 0;
|
||||
} else {
|
||||
$data->categoria_id = (int)($data->categoria_id ?? 0) ?: 0;
|
||||
}
|
||||
}
|
||||
|
||||
$id = (int) ($data->id ?? $this->getState($this->getName() . '.id'));
|
||||
if ($id) {
|
||||
$db = Factory::getContainer()->get('DatabaseDriver');
|
||||
$q = $db->getQuery(true)
|
||||
->select($db->quoteName('usergroup_id'))
|
||||
->from($db->quoteName('#__circolari_usergroups'))
|
||||
->where($db->quoteName('circolare_id') . ' = ' . (int) $id);
|
||||
$db->setQuery($q);
|
||||
$data->usergroup_ids = $db->loadColumn() ?: [];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function check()
|
||||
{
|
||||
|
||||
|
||||
|
||||
// Se firma obbligatoria, scadenza deve esserci
|
||||
$isObbl = (int) ($this->firma_obbligatoria ?? 0);
|
||||
if ($isObbl === 1 && empty($this->scadenza)) {
|
||||
$this->setError(\Joomla\CMS\Language\Text::_('COM_CIRCOLARI_ERR_SCADENZA_REQUIRED'));
|
||||
return false;
|
||||
}
|
||||
|
||||
// ordering per nuovi record
|
||||
if (property_exists($this, 'ordering') && (int) $this->id === 0) {
|
||||
$this->ordering = self::getNextOrder();
|
||||
}
|
||||
|
||||
// Titolo obbligatorio (se vuoi forzarlo)
|
||||
$this->title = trim((string) ($this->title ?? ''));
|
||||
if ($this->title === '') {
|
||||
$this->setError(Text::_('JLIB_DATABASE_ERROR_MUSTCONTAIN_A_TITLE'));
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- ALIAS: genera se vuoto, ripulisci, evita "solo numeri", garantisci univocità ---
|
||||
$this->alias = trim((string) ($this->alias ?? ''));
|
||||
|
||||
// Se mancante → dal titolo
|
||||
if ($this->alias === '') {
|
||||
$this->alias = ApplicationHelper::stringURLSafe($this->title);
|
||||
} else {
|
||||
$this->alias = ApplicationHelper::stringURLSafe($this->alias);
|
||||
}
|
||||
|
||||
// Evita alias vuoto o numerico puro
|
||||
if ($this->alias === '' || ctype_digit($this->alias)) {
|
||||
$seed = (int) ($this->id ?: time());
|
||||
$this->alias = ApplicationHelper::stringURLSafe($this->title . '-' . $seed);
|
||||
}
|
||||
|
||||
// Unicità alias nel contesto tabella
|
||||
$base = $this->alias;
|
||||
$i = 2;
|
||||
while ($this->aliasExists($this->alias, (int) $this->id)) {
|
||||
$this->alias = $base . '-' . $i;
|
||||
$i++;
|
||||
}
|
||||
|
||||
return parent::check();
|
||||
$db->setQuery($q);
|
||||
return $db->loadAssocList() ?: [];
|
||||
}
|
||||
|
||||
/** Verifica unicità alias */
|
||||
protected function aliasExists(string $alias, int $excludeId = 0): bool
|
||||
{
|
||||
$q = $this->_db->getQuery(true)
|
||||
@ -347,6 +80,190 @@ class CircolareModel extends AdminModel
|
||||
return ((int) $this->_db->loadResult()) > 0;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Caricamento dati per il form
|
||||
* ========================= */
|
||||
|
||||
public function getItem($pk = null)
|
||||
{
|
||||
$item = parent::getItem($pk);
|
||||
|
||||
if ($item) {
|
||||
// params come JSON (come già avevi)
|
||||
if (isset($item->params)) {
|
||||
$item->params = json_encode($item->params);
|
||||
}
|
||||
// Allegati per comodità in view/form
|
||||
if (!empty($item->id)) {
|
||||
$item->attachments = $this->getAttachments((int)$item->id);
|
||||
}
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
protected function loadFormData()
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
$data = $app->getUserState('com_circolari.edit.circolare.data', []);
|
||||
|
||||
if (empty($data)) {
|
||||
if ($this->item === null) {
|
||||
$this->item = $this->getItem();
|
||||
}
|
||||
$data = $this->item ?: [];
|
||||
}
|
||||
|
||||
// Normalizza a array per JForm
|
||||
$arr = is_object($data) ? (array) $data : (array) $data;
|
||||
|
||||
// Categoria default 0 in creazione
|
||||
if (empty($arr['id'])) {
|
||||
$arr['categoria_id'] = (int)($arr['categoria_id'] ?? 0) ?: 0;
|
||||
}
|
||||
|
||||
// Carica gruppi e allegati se in modifica
|
||||
$id = (int) ($arr['id'] ?? $this->getState($this->getName() . '.id'));
|
||||
if ($id) {
|
||||
$db = Factory::getContainer()->get('DatabaseDriver');
|
||||
|
||||
// Gruppi che possono firmare
|
||||
$q = $db->getQuery(true)
|
||||
->select($db->quoteName('usergroup_id'))
|
||||
->from($db->quoteName('#__circolari_usergroups'))
|
||||
->where($db->quoteName('circolare_id') . ' = ' . (int) $id);
|
||||
$db->setQuery($q);
|
||||
$arr['usergroup_ids'] = $db->loadColumn() ?: [];
|
||||
|
||||
// Allegati
|
||||
$arr['attachments'] = $this->getAttachments($id);
|
||||
} else {
|
||||
$arr['attachments'] = [];
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Duplicazione
|
||||
* ========================= */
|
||||
|
||||
public function duplicate(&$pks)
|
||||
{
|
||||
$app = Factory::getApplication();
|
||||
$user = $app->getIdentity();
|
||||
|
||||
if (!$user->authorise('core.create', 'com_circolari')) {
|
||||
throw new \Exception(Text::_('JERROR_CORE_CREATE_NOT_PERMITTED'));
|
||||
}
|
||||
|
||||
$context = $this->option . '.' . $this->name;
|
||||
PluginHelper::importPlugin($this->events_map['save']);
|
||||
|
||||
$table = $this->getTable();
|
||||
|
||||
foreach ($pks as $pk) {
|
||||
if ($table->load($pk, true)) {
|
||||
$table->id = 0;
|
||||
|
||||
if (!$table->check()) {
|
||||
throw new \Exception($table->getError());
|
||||
}
|
||||
|
||||
$before = AbstractEvent::create(
|
||||
$this->event_before_save,
|
||||
['context' => $context, 'subject' => $table, 'isNew' => true, 'data' => $table]
|
||||
);
|
||||
$dispatchResult = $app->getDispatcher()->dispatch($this->event_before_save, $before);
|
||||
$result = isset($dispatchResult['result']) ? $dispatchResult['result'] : [];
|
||||
|
||||
if (in_array(false, $result, true) || !$table->store()) {
|
||||
throw new \Exception($table->getError());
|
||||
}
|
||||
|
||||
$app->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());
|
||||
}
|
||||
}
|
||||
|
||||
$this->cleanCache();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Prepara/Check JTable
|
||||
* ========================= */
|
||||
|
||||
protected function prepareTable($table)
|
||||
{
|
||||
if (empty($table->id)) {
|
||||
if (@$table->ordering === '' || $table->ordering === null) {
|
||||
$db = $this->getDbo();
|
||||
$db->setQuery('SELECT MAX(ordering) FROM #__circolari');
|
||||
$max = (int) $db->loadResult();
|
||||
$table->ordering = $max + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nota: questo check era già nel tuo Model (non nel Table).
|
||||
* Lo lascio invariato per non rompere il flusso.
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
// Firma obbligatoria: scadenza richiesta
|
||||
$isObbl = (int) ($this->firma_obbligatoria ?? 0);
|
||||
if ($isObbl === 1 && empty($this->scadenza)) {
|
||||
$this->setError(Text::_('COM_CIRCOLARI_ERR_SCADENZA_REQUIRED'));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ordering per nuovi record
|
||||
if (property_exists($this, 'ordering') && (int) $this->id === 0) {
|
||||
$this->ordering = self::getNextOrder();
|
||||
}
|
||||
|
||||
// Titolo
|
||||
$this->title = trim((string) ($this->title ?? ''));
|
||||
if ($this->title === '') {
|
||||
$this->setError(Text::_('JLIB_DATABASE_ERROR_MUSTCONTAIN_A_TITLE'));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Alias
|
||||
$this->alias = trim((string) ($this->alias ?? ''));
|
||||
if ($this->alias === '') {
|
||||
$this->alias = ApplicationHelper::stringURLSafe($this->title);
|
||||
} else {
|
||||
$this->alias = ApplicationHelper::stringURLSafe($this->alias);
|
||||
}
|
||||
if ($this->alias === '' || ctype_digit($this->alias)) {
|
||||
$seed = (int) ($this->id ?: time());
|
||||
$this->alias = ApplicationHelper::stringURLSafe($this->title . '-' . $seed);
|
||||
}
|
||||
|
||||
$base = $this->alias;
|
||||
$i = 2;
|
||||
while ($this->aliasExists($this->alias, (int) $this->id)) {
|
||||
$this->alias = $base . '-' . $i;
|
||||
$i++;
|
||||
}
|
||||
|
||||
return parent::check();
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Salvataggio con sync allegati & gruppi
|
||||
* ========================= */
|
||||
|
||||
public function save($data)
|
||||
{
|
||||
$ok = parent::save($data);
|
||||
@ -354,28 +271,103 @@ class CircolareModel extends AdminModel
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = (int) $this->getState($this->getName() . '.id');
|
||||
$id = (int) $this->getState($this->getName() . '.id');
|
||||
$groups = array_map('intval', $data['usergroup_ids'] ?? []);
|
||||
|
||||
$db = Factory::getContainer()->get('DatabaseDriver');
|
||||
$db->transactionStart();
|
||||
|
||||
try {
|
||||
// ripulisci associazioni esistenti
|
||||
/* ----- Allegati: replace completo ----- */
|
||||
$attachments = $data['attachments'] ?? [];
|
||||
$attachments = is_array($attachments) ? $attachments : [];
|
||||
|
||||
// pulisci
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->delete($db->quoteName('#__circolari_attachments'))
|
||||
->where($db->quoteName('circolare_id') . ' = ' . (int) $id)
|
||||
)->execute();
|
||||
|
||||
// reinserisci
|
||||
if (!empty($attachments)) {
|
||||
$q = $db->getQuery(true)
|
||||
->insert($db->quoteName('#__circolari_attachments'))
|
||||
->columns([
|
||||
$db->quoteName('circolare_id'),
|
||||
$db->quoteName('path'),
|
||||
$db->quoteName('title'),
|
||||
$db->quoteName('ordering')
|
||||
]);
|
||||
|
||||
$added = 0;
|
||||
foreach ($attachments as $row) {
|
||||
$path = trim((string)($row['path'] ?? ''));
|
||||
if ($path === '') continue;
|
||||
|
||||
$title = trim((string)($row['title'] ?? ''));
|
||||
$ordering = (int)($row['ordering'] ?? 0);
|
||||
|
||||
$q->values(
|
||||
(int)$id . ','
|
||||
. $db->quote($path) . ','
|
||||
. $db->quote($title) . ','
|
||||
. (int)$ordering
|
||||
);
|
||||
$added++;
|
||||
}
|
||||
|
||||
if ($added > 0) {
|
||||
$db->setQuery($q)->execute();
|
||||
}
|
||||
|
||||
// [Opzionale] aggiorna attachment_id al primo allegato se la colonna esiste
|
||||
$cols = array_change_key_case($db->getTableColumns('#__circolari', false));
|
||||
if (isset($cols['attachment_id'])) {
|
||||
$firstId = (int) $db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->select('id')
|
||||
->from($db->quoteName('#__circolari_attachments'))
|
||||
->where($db->quoteName('circolare_id') . ' = ' . (int)$id)
|
||||
->order($db->escape('ordering ASC, id ASC'))
|
||||
)->loadResult();
|
||||
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->update($db->quoteName('#__circolari'))
|
||||
->set($db->quoteName('attachment_id') . ' = ' . ($firstId ?: 'NULL'))
|
||||
->where($db->quoteName('id') . ' = ' . (int)$id)
|
||||
)->execute();
|
||||
}
|
||||
} else {
|
||||
// nessun allegato: azzera eventuale attachment_id (se esiste)
|
||||
$cols = array_change_key_case($db->getTableColumns('#__circolari', false));
|
||||
if (isset($cols['attachment_id'])) {
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->update($db->quoteName('#__circolari'))
|
||||
->set($db->quoteName('attachment_id') . ' = NULL')
|
||||
->where($db->quoteName('id') . ' = ' . (int)$id)
|
||||
)->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/* ----- Gruppi: replace completo ----- */
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)
|
||||
->delete($db->quoteName('#__circolari_usergroups'))
|
||||
->where($db->quoteName('circolare_id') . ' = ' . (int) $id)
|
||||
)->execute();
|
||||
|
||||
// reinserisci le nuove
|
||||
if (!empty($groups)) {
|
||||
$q = $db->getQuery(true)
|
||||
->insert($db->quoteName('#__circolari_usergroups'))
|
||||
->columns([$db->quoteName('circolare_id'), $db->quoteName('usergroup_id')]);
|
||||
|
||||
foreach ($groups as $gid) {
|
||||
$q->values((int) $id . ',' . (int) $gid);
|
||||
if ($gid > 0) {
|
||||
$q->values((int) $id . ',' . (int) $gid);
|
||||
}
|
||||
}
|
||||
$db->setQuery($q)->execute();
|
||||
}
|
||||
|
||||
@ -47,7 +47,6 @@ class CircolaresModel extends ListModel
|
||||
'modified_by', 'a.modified_by',
|
||||
'title', 'a.title',
|
||||
'description', 'a.description',
|
||||
'attachment', 'a.attachment',
|
||||
'image', 'a.image',
|
||||
);
|
||||
}
|
||||
@ -77,7 +76,7 @@ class CircolaresModel extends ListModel
|
||||
protected function populateState($ordering = null, $direction = null)
|
||||
{
|
||||
// List state information.
|
||||
parent::populateState('id', 'ASC');
|
||||
parent::populateState('id', 'DESC');
|
||||
|
||||
$context = $this->getUserStateFromRequest($this->context.'.filter.search', 'filter_search');
|
||||
$this->setState('filter.search', $context);
|
||||
|
||||
@ -38,8 +38,7 @@ HTMLHelper::_('bootstrap.tooltip');
|
||||
<?php echo $this->form->renderField('alias'); ?>
|
||||
<?php echo $this->form->renderField('categoria_id'); ?>
|
||||
<?php echo $this->form->renderField('description'); ?>
|
||||
<?php echo $this->form->renderField('attachment'); ?>
|
||||
<?php echo $this->form->renderField('allegato_titolo'); ?>
|
||||
<?php echo $this->form->renderField('attachments'); ?>
|
||||
<?php echo $this->form->renderField('image'); ?>
|
||||
<?php echo $this->form->renderField('firma_obbligatoria'); ?>
|
||||
<?php echo $this->form->renderField('usergroup_ids'); ?>
|
||||
|
||||
Reference in New Issue
Block a user