diff --git a/site/src/Controller/DisplayController.php b/site/src/Controller/DisplayController.php
index c0e48eb..898aa0e 100644
--- a/site/src/Controller/DisplayController.php
+++ b/site/src/Controller/DisplayController.php
@@ -3,20 +3,29 @@ namespace Pcrt\Component\Circolari\Site\Controller;
\defined('_JEXEC') or die;
+use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Controller\BaseController;
class DisplayController extends BaseController
{
- protected $default_view = 'circolare'; // default se manca ?view=
-
public function display($cachable = false, $urlparams = [])
{
- // Se qualcuno forza un view strano, non rompiamo
- $view = $this->input->getCmd('view', $this->default_view);
- if (!in_array($view, ['circolare'], true)) {
- $view = $this->default_view;
- $this->input->set('view', $view);
+ $app = Factory::getApplication();
+ $in = $app->input;
+
+ $view = $in->getCmd('view', '');
+ $id = $in->getInt('id', 0);
+
+ if ($id > 0) {
+ // Singolo solo se c'è l'id
+ $in->set('view', 'circolare');
+ } else {
+ // Nessun id: forziamo la lista (anche se il menu chiede "circolare")
+ if ($view === '' || $view === 'circolare' || $view === 'category') {
+ $in->set('view', 'circolari'); // <- lista
+ }
}
+
return parent::display($cachable, $urlparams);
}
}
diff --git a/site/src/Model/CircolareModel.php b/site/src/Model/CircolareModel.php
index 9168335..0bbcf6a 100644
--- a/site/src/Model/CircolareModel.php
+++ b/site/src/Model/CircolareModel.php
@@ -3,31 +3,56 @@ namespace Pcrt\Component\Circolari\Site\Model;
\defined('_JEXEC') or die;
-use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Model\ItemModel;
+use Joomla\CMS\Factory;
class CircolareModel extends ItemModel
{
- protected function populateState(): void
+ protected function populateState()
{
$app = Factory::getApplication();
- $this->setState('circolare.id', (int) $app->input->getInt('id'));
+ $id = $app->input->getInt('id', 0);
+ $this->setState('circolare.id', $id);
+
+ $catid = $app->input->getInt('catid', 0);
+ $this->setState('filter.catid', $catid);
parent::populateState();
}
public function getItem($pk = null)
{
- $pk = $pk ?: (int) $this->getState('circolare.id');
- if (!$pk) return null;
+ $pk = (int) ($pk ?: $this->getState('circolare.id'));
- $db = Factory::getContainer()->get('DatabaseDriver');
+ if ($pk <= 0) {
+ return null;
+ }
+
+ $db = $this->getDatabase();
$q = $db->getQuery(true)
- ->select('*')
- ->from($db->quoteName('#__circolari'))
- ->where($db->quoteName('id') . ' = ' . (int) $pk)
- ->where($db->quoteName('state') . ' = 1');
- $db->setQuery($q);
+ ->select('c.*') // <<< evita errori di colonne
+ ->from($db->quoteName('#__circolari') . ' AS c')
+ ->where('c.id = ' . (int) $pk);
- return $db->loadObject();
+ // Se esistono le colonne, applica filtri
+ $cols = array_change_key_case(
+ $db->getTableColumns($db->replacePrefix('#__circolari'), false),
+ CASE_LOWER
+ );
+
+ // catid (se impostato e colonna esiste)
+ $catid = (int) $this->getState('filter.catid', 0);
+ if ($catid > 0 && isset($cols['catid'])) {
+ $q->where('c.catid = ' . $catid);
+ }
+
+ // stato (se colonna esiste)
+ if (isset($cols['state'])) {
+ $q->where('COALESCE(c.state, 1) = 1');
+ }
+
+ $db->setQuery($q);
+ $row = $db->loadObject();
+
+ return $row ?: null;
}
}
diff --git a/site/src/Model/CircolariModel.php b/site/src/Model/CircolariModel.php
new file mode 100644
index 0000000..19470bd
--- /dev/null
+++ b/site/src/Model/CircolariModel.php
@@ -0,0 +1,119 @@
+getUserStateFromRequest($this->context . '.list.limit', 'limit', $app->get('list_limit'), 'uint');
+ $this->setState('list.limit', $limit);
+
+ $start = $app->getUserStateFromRequest($this->context . '.list.start', 'limitstart', 0, 'uint');
+ $this->setState('list.start', $start);
+
+ // sorting
+ $orderCol = $app->getUserStateFromRequest($this->context . '.list.ordering', 'filter_order', $ordering, 'cmd');
+ if (!\in_array($orderCol, $this->filter_fields, true)) {
+ $orderCol = $ordering;
+ }
+ $this->setState('list.ordering', $orderCol);
+
+ $orderDirn = strtoupper($app->getUserStateFromRequest($this->context . '.list.direction', 'filter_order_Dir', $direction, 'cmd'));
+ $this->setState('list.direction', $orderDirn === 'ASC' ? 'ASC' : 'DESC');
+
+ // filtro testuale
+ $search = $app->getUserStateFromRequest($this->context . '.list.filter', 'filter-search', '', 'string');
+ $this->setState('list.filter', $search);
+
+ // categoria (se usi catid)
+ $this->setState('filter.catid', $app->input->getInt('catid', 0));
+
+ parent::populateState($ordering, $direction);
+ }
+
+ protected function getListQuery()
+ {
+ $db = $this->getDatabase();
+ $q = $db->getQuery(true)
+ ->select('c.*')
+ ->from($db->quoteName('#__circolari', 'c'));
+
+ // colonne effettive in tabella
+ $cols = array_change_key_case($db->getTableColumns($db->replacePrefix('#__circolari')));
+
+ // pubblicati
+ if (isset($cols['state'])) {
+ $q->where('COALESCE(c.state,1)=1');
+ }
+
+ // catid
+ $catid = (int) $this->getState('filter.catid', 0);
+ if ($catid > 0 && isset($cols['catid'])) {
+ $q->where('c.catid=' . $catid);
+ }
+
+ // search su title
+ $search = trim((string) $this->getState('list.filter', ''));
+ if ($search !== '' && isset($cols['title'])) {
+ $like = $db->quote('%' . $db->escape($search, true) . '%', false);
+ $q->where('c.title LIKE ' . $like);
+ }
+
+ // ordinamento
+ $orderCol = $this->getState('list.ordering', 'c.created');
+ $orderDir = $this->getState('list.direction', 'DESC');
+ $q->order($db->escape($orderCol . ' ' . $orderDir));
+
+ return $q;
+ }
+
+ // conteggio robusto (gestisce DISTINCT/GROUP BY)
+ public function getTotal()
+ {
+ if (isset($this->total)) {
+ return $this->total;
+ }
+
+ $db = $this->getDatabase();
+ $sub = $this->getListQuery();
+ $query = $db->getQuery(true)
+ ->select('COUNT(*)')
+ ->from('(' . $sub . ') AS x');
+
+ $db->setQuery($query);
+ $this->total = (int) $db->loadResult();
+
+ return $this->total;
+ }
+
+ public function getItems()
+ {
+ $items = parent::getItems();
+ if (!\is_array($items)) {
+ return [];
+ }
+ return array_values(array_filter($items, static function ($it) {
+ return \is_object($it) && !empty($it->id);
+ }));
+ }
+}
diff --git a/site/src/Service/Category.php b/site/src/Service/Category.php
deleted file mode 100644
index c39c186..0000000
--- a/site/src/Service/Category.php
+++ /dev/null
@@ -1,21 +0,0 @@
-
- * @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/View/Circolare/HtmlView.php b/site/src/View/Circolare/HtmlView.php
index 08146db..4e8a012 100644
--- a/site/src/View/Circolare/HtmlView.php
+++ b/site/src/View/Circolare/HtmlView.php
@@ -3,35 +3,50 @@ namespace Pcrt\Component\Circolari\Site\View\Circolare;
\defined('_JEXEC') or die;
-use Joomla\CMS\Language\Text;
+use Joomla\CMS\Factory;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
+use Joomla\CMS\Language\Text;
class HtmlView extends BaseHtmlView
{
protected $item;
+ public $items = [];
+ public $pagination;
+ public $state;
public function display($tpl = null)
{
+ // Carica la singola
$this->item = $this->get('Item');
- if (!$this->item) {
- throw new \Exception(Text::_('COM_CIRCOLARI_ITEM_NOT_FOUND'), 404);
- }
+ // Se NON c'è l'item → mostra la lista
+ if (!$this->item) {
+ $app = \Joomla\CMS\Factory::getApplication();
+ $factory = $app->bootComponent('com_circolari')->getMVCFactory();
- // Se il layout non c'è, stampa un fallback minimale (debug-friendly)
- $tplPath = JPATH_COMPONENT_SITE . '/tmpl/circolare/default.php';
- if (!is_file($tplPath)) {
- $title = htmlspecialchars($this->item->title ?? 'Circolare');
- $body = $this->item->description ?? $this->item->testo ?? $this->item->descrizione ?? '';
- $html = ''.$title.'