Report & excel frontend & admin

This commit is contained in:
2025-09-08 08:39:59 +02:00
parent 9b7f845414
commit 09f40214d4
6 changed files with 320 additions and 22 deletions

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<form>
<!-- Gruppo FILTRI -->
<fields name="filter">
<field name="search" type="text"
label="JSEARCH_FILTER"
description="JSEARCH_FILTER_DESC"
hint="Ricerca per utente/email/titolo" />
<field name="circolare_id" type="sql"
label="Circolare"
query="SELECT id AS value, title AS text FROM #__circolari ORDER BY title ASC"
key_field="value" value_field="text"
default="0" >
<option value="0">- Tutte -</option>
</field>
<field name="scelta" type="sql"
label="Scelta"
query="SELECT DISTINCT COALESCE(f.firma_label, b.label) AS value
FROM #__circolari_firme f
LEFT JOIN #__circolari_firmetipi_bottoni b ON b.id = f.firmatipo_bottone_id
WHERE COALESCE(f.firma_label, b.label) IS NOT NULL
ORDER BY value ASC"
key_field="value" value_field="value"
default="">
<option value="">- Tutte -</option>
</field>
<field name="date_from" type="calendar" label="Dalla data" format="%Y-%m-%d"/>
<field name="date_to" type="calendar" label="Alla data" format="%Y-%m-%d"/>
</fields>
<!-- Gruppo LIST (ordinamento/paginazione) -->
<fields name="list">
<field name="fullordering" type="list" label="JGLOBAL_SORT_BY" default="f.data_firma DESC">
<option value="f.data_firma DESC">Data ↓</option>
<option value="f.data_firma ASC">Data ↑</option>
<option value="u.name ASC">Nome ↑</option>
<option value="u.name DESC">Nome ↓</option>
<option value="c.title ASC">Circolare ↑</option>
<option value="c.title DESC">Circolare ↓</option>
</field>
<field name="limit" type="limitbox" default="20"/>
</fields>
</form>

View File

@ -0,0 +1,75 @@
<?php
namespace Pcrt\Component\Circolari\Administrator\Controller;
\defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Controller\BaseController;
class ReportfirmeController extends BaseController
{
public function exportCsv()
{
if (!\Joomla\CMS\Session\Session::checkToken('get')) {
throw new \RuntimeException(\Joomla\CMS\Language\Text::_('JINVALID_TOKEN'), 403);
}
$app = \Joomla\CMS\Factory::getApplication();
$user = $app->getIdentity();
if (!$user->authorise('core.manage', 'com_circolari') && !$user->authorise('core.admin', 'com_circolari')) {
throw new \RuntimeException(\Joomla\CMS\Language\Text::_('JERROR_ALERTNOAUTHOR'), 403);
}
/** @var \Pcrt\Component\Circolari\Administrator\Model\ReportfirmeModel $model */
$model = $this->getModel('Reportfirme', 'Administrator');
// ✅ Inizializza lo state (richiama internamente populateState())
$model->getState();
// ✅ Esporta TUTTI i risultati che rispettano i filtri correnti (niente paginazione)
$model->setState('list.start', 0);
$model->setState('list.limit', 0);
// Prendi i dati
$rows = $model->getItems();
// Pulisci output e invia header per download
while (ob_get_level() > 0) { @ob_end_clean(); }
$filename = 'report_firme_' . date('Ymd_His') . '.csv';
$app->clearHeaders();
$app->setHeader('Content-Description', 'File Transfer', true);
$app->setHeader('Content-Type', 'application/vnd.ms-excel; charset=utf-8', true);
$app->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"', true);
$app->setHeader('Content-Transfer-Encoding', 'binary', true);
$app->setHeader('Expires', '0', true);
$app->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true);
$app->setHeader('Pragma', 'public', true);
$app->sendHeaders();
// CSV con BOM UTF-8, separatore ';'
$out = fopen('php://output', 'w');
fwrite($out, chr(0xEF).chr(0xBB).chr(0xBF));
fputcsv($out, ['ID','Circolare','ID Utente','Nome','Username','Email','Scelta','Data firma'], ';');
foreach ($rows as $r) {
$date = \Joomla\CMS\Factory::getDate($r->data_firma)->format('d/m/Y H:i');
fputcsv($out, [
$r->id,
$r->circolare_title,
$r->user_id,
$r->user_name,
$r->username,
$r->email,
$r->scelta_label, // ✅ nessun uso di f.firma
$date,
], ';');
}
fclose($out);
$app->close();
}
}

View File

@ -0,0 +1,92 @@
<?php
namespace Pcrt\Component\Circolari\Administrator\Model;
\defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Model\ListModel;
class ReportfirmeModel extends ListModel
{
protected $filter_fields = ['f.data_firma','u.name','c.title','f.id','scelta_label'];
protected function populateState($ordering = 'f.data_firma', $direction = 'DESC')
{
$app = Factory::getApplication();
$this->setState('filter.search', $app->getUserStateFromRequest($this->context.'.filter.search', 'filter_search', '', 'string'));
$this->setState('filter.circolare_id', $app->getUserStateFromRequest($this->context.'.filter.circolare_id', 'filter_circolare_id', 0, 'int'));
$this->setState('filter.scelta', $app->getUserStateFromRequest($this->context.'.filter.scelta', 'filter_scelta', '', 'string'));
$this->setState('filter.date_from', $app->getUserStateFromRequest($this->context.'.filter.date_from', 'filter_date_from', '', 'string'));
$this->setState('filter.date_to', $app->getUserStateFromRequest($this->context.'.filter.date_to', 'filter_date_to', '', 'string'));
parent::populateState($ordering, $direction);
}
protected function getListQuery()
{
$db = $this->getDatabase();
$q = $db->getQuery(true);
$q->select([
'f.id','f.circolare_id','f.user_id','f.data_firma',
'u.name AS user_name','u.username','u.email',
'c.title AS circolare_title',
'f.firma_label',
'b.label AS bottone_label',
// scelta normalizzata: prima firma_label (copia al momento della firma), altrimenti label del bottone
'COALESCE(f.firma_label, b.label) AS scelta_label',
])
->from($db->quoteName('#__circolari_firme','f'))
->join('INNER', $db->quoteName('#__users','u') . ' ON u.id = f.user_id')
->join('INNER', $db->quoteName('#__circolari','c') . ' ON c.id = f.circolare_id')
->join('LEFT', $db->quoteName('#__circolari_firmetipi_bottoni','b') . ' ON b.id = f.firmatipo_bottone_id');
// Filtri
$search = (string) $this->getState('filter.search', '');
if ($search !== '') {
$like = $db->quote('%' . $db->escape($search, true) . '%');
$q->where('('
. 'u.name LIKE ' . $like
. ' OR u.username LIKE ' . $like
. ' OR u.email LIKE ' . $like
. ' OR c.title LIKE ' . $like
. ')');
}
$circolareId = (int) $this->getState('filter.circolare_id', 0);
if ($circolareId > 0) {
$q->where('f.circolare_id = ' . (int)$circolareId);
}
$scelta = (string) $this->getState('filter.scelta', '');
if ($scelta !== '') {
$q->where('(f.firma_label = ' . $db->quote($scelta) . ' OR b.label = ' . $db->quote($scelta) . ')');
}
$from = (string) $this->getState('filter.date_from', '');
if ($from !== '') {
$q->where('f.data_firma >= ' . $db->quote($from . ' 00:00:00'));
}
$to = (string) $this->getState('filter.date_to', '');
if ($to !== '') {
$q->where('f.data_firma <= ' . $db->quote($to . ' 23:59:59'));
}
// Ordinamento
$orderCol = $this->state->get('list.ordering', 'f.data_firma');
$orderDirn = $this->state->get('list.direction', 'DESC');
$q->order($db->escape($orderCol . ' ' . $orderDirn));
return $q;
}
public function getItems()
{
$rows = parent::getItems();
foreach ($rows as $r) {
$r->scelta_label = $r->scelta_label ?: '-';
}
return $rows;
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Pcrt\Component\Circolari\Administrator\View\Reportfirme;
\defined('_JEXEC') or die;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
class HtmlView extends BaseHtmlView
{
// DEVONO essere public perché i layout core vi accedono direttamente
public $items;
public $state;
public $pagination;
public $filterForm;
public $activeFilters;
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'); // JForm dei filtri (forms/filter_reportfirme.xml)
$this->activeFilters = $this->get('ActiveFilters');
parent::display($tpl);
}
}

View File

@ -0,0 +1,58 @@
<?php
\defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Session\Session;
$listOrder = $this->state->get('list.ordering', 'f.data_firma');
$listDirn = $this->state->get('list.direction', 'DESC');
// Carica CSS base
HTMLHelper::_('bootstrap.tooltip');
HTMLHelper::_('behavior.multiselect');
HTMLHelper::_('formbehavior.chosen', 'select');
?>
<form action="<?php echo Route::_('index.php?option=com_circolari&view=reportfirme'); ?>" method="post" name="adminForm" id="adminForm">
<div id="j-main-container" class="j-main-container">
<?php echo LayoutHelper::render('joomla.searchtools.default', ['view' => $this]); ?>
<table class="table table-striped">
<thead>
<tr>
<th><?php echo HTMLHelper::_('grid.sort', 'ID', 'f.id', $listDirn, $listOrder); ?></th>
<th><?php echo HTMLHelper::_('grid.sort', 'Circolare', 'c.title', $listDirn, $listOrder); ?></th>
<th><?php echo HTMLHelper::_('grid.sort', 'Nome', 'u.name', $listDirn, $listOrder); ?></th>
<th>Username</th>
<th>Email</th>
<th><?php echo HTMLHelper::_('grid.sort', 'Scelta', 'scelta_label', $listDirn, $listOrder); ?></th>
<th><?php echo HTMLHelper::_('grid.sort', 'Data firma', 'f.data_firma', $listDirn, $listOrder); ?></th>
</tr>
</thead>
<tbody>
<?php if (empty($this->items)) : ?>
<tr><td colspan="7" class="text-center text-muted">Nessun risultato</td></tr>
<?php else : ?>
<?php foreach ($this->items as $i => $item) : ?>
<tr>
<td><?php echo (int) $item->id; ?></td>
<td><?php echo $this->escape($item->circolare_title); ?></td>
<td><?php echo $this->escape($item->user_name); ?></td>
<td><?php echo $this->escape($item->username); ?></td>
<td><?php echo $this->escape($item->email); ?></td>
<td><span class="badge bg-secondary"><?php echo $this->escape($item->scelta_label); ?></span></td>
<td><?php echo HTMLHelper::_('date', $item->data_firma, 'd/m/Y H:i'); ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
<?php echo $this->pagination->getListFooter(); ?>
<input type="hidden" name="task" value="">
<input type="hidden" name="boxchecked" value="0">
<?php echo HTMLHelper::_('form.token'); ?>
</div>
</form>

View File

@ -10,9 +10,8 @@
<version>1.1.7</version> <version>1.1.7</version>
<description></description> <description></description>
<namespace path="src">Pcrt\Component\Circolari</namespace> <namespace path="src">Pcrt\Component\Circolari</namespace>
<install> <!-- Runs on install --> <install> <!-- Runs on install -->
<sql> <sql>
<file driver="mysql" charset="utf8">sql/install.mysql.utf8.sql</file> <file driver="mysql" charset="utf8">sql/install.mysql.utf8.sql</file>
@ -29,7 +28,6 @@
</sql> </sql>
</uninstall> </uninstall>
<files folder="site"> <files folder="site">
<folder>src</folder> <folder>src</folder>
@ -42,18 +40,22 @@
<filename>joomla.asset.json</filename> <filename>joomla.asset.json</filename>
</media> </media>
<languages folder="site/languages"> <languages folder="site/languages">
<language tag="en-GB">en-GB/com_circolari.ini</language> <language tag="en-GB">en-GB/com_circolari.ini</language>
<language tag="it-IT">it-IT/com_circolari.ini</language> <language tag="it-IT">it-IT/com_circolari.ini</language>
</languages> </languages>
<administration> <administration>
<menu>COM_CIRCOLARI</menu> <menu>COM_CIRCOLARI</menu>
<submenu> <submenu>
<menu link="option=com_circolari&amp;view=circolares" view="circolares" alt="Circolari/Circolares">COM_CIRCOLARI_TITLE_CIRCOLARES</menu> <menu link="option=com_circolari&amp;view=circolares" view="circolares"
<menu link="option=com_circolari&amp;view=firmetipi" view="firmetipi" alt="Circolari/Firmetipi">COM_CIRCOLARI_TITLE_FIRMETIPI</menu> alt="Circolari/Circolares">COM_CIRCOLARI_TITLE_CIRCOLARES</menu>
<menu link="option=com_circolari&amp;view=categorie">COM_CIRCOLARI_TITLE_CATEGORIE</menu> <menu link="option=com_circolari&amp;view=firmetipi" view="firmetipi"
</submenu> alt="Circolari/Firmetipi">COM_CIRCOLARI_TITLE_FIRMETIPI</menu>
<menu link="option=com_circolari&amp;view=categorie">COM_CIRCOLARI_TITLE_CATEGORIE</menu>
<menu link="option=com_circolari&amp;view=reportfirme" view="reportfirme">Report Firme</menu>
</submenu>
<files folder="administrator"> <files folder="administrator">
<filename>access.xml</filename> <filename>access.xml</filename>
@ -66,11 +68,11 @@
<folder>sql</folder> <folder>sql</folder>
</files> </files>
<languages folder="administrator/languages"> <languages folder="administrator/languages">
<language tag="en-GB">en-GB/com_circolari.ini</language> <language tag="en-GB">en-GB/com_circolari.ini</language>
<language tag="en-GB">en-GB/com_circolari.sys.ini</language> <language tag="en-GB">en-GB/com_circolari.sys.ini</language>
<language tag="it-IT">it-IT/com_circolari.ini</language> <language tag="it-IT">it-IT/com_circolari.ini</language>
<language tag="it-IT">it-IT/com_circolari.sys.ini</language> <language tag="it-IT">it-IT/com_circolari.sys.ini</language>
</languages> </languages>
</administration> </administration>
<config> <config>
@ -82,11 +84,12 @@
</config> </config>
<plugins> <plugins>
</plugins> </plugins>
<updateservers> <updateservers>
<server type="extension" priority="1" name="com_circolari">https://nocdn.component-creator.com/index.php?task=builder.preupdatecheckhook&amp;option=com_combuilder&amp;component=NzY0NjYtMjE1NzU5</server> <server type="extension" priority="1" name="com_circolari">
https://nocdn.component-creator.com/index.php?task=builder.preupdatecheckhook&amp;option=com_combuilder&amp;component=NzY0NjYtMjE1NzU5</server>
</updateservers> </updateservers>
</extension> </extension>
<!-- Component built by the Joomla Component Creator --> <!-- Component built by the Joomla Component Creator -->
<!-- http://www.component-creator.com/ --> <!-- http://www.component-creator.com/ -->