From 06439a275fdc763abe3f2725f1752766d2fa146f Mon Sep 17 00:00:00 2001 From: Dasc3er Date: Mon, 15 Mar 2021 10:43:14 +0100 Subject: [PATCH] Introduzione simulazione dei widget Nuove strutture per gestire i widget del gestionale, base per la gestione deile stampe e miglioramento del sistema di simulazione delle richieste al gestionale legacy. --- UPGRADING.md | 21 ++ app/Http/Controllers/LegacyController.php | 47 ++-- app/Http/Controllers/PrintController.php | 33 +++ app/Http/Controllers/Test.php | 10 - .../Controllers/WidgetModalController.php | 23 ++ app/OSM/ComponentManager.php | 32 +++ app/OSM/ComponentManagerTrait.php | 41 ++++ app/OSM/Prints/Autofill.php | 116 ++++++++++ app/OSM/Prints/MPDFManager.php | 150 +++++++++++++ app/OSM/Prints/Manager.php | 204 ++++++++++++++++++ app/OSM/Prints/Retro/Manager.php | 176 +++++++++++++++ app/OSM/Prints/Template.php | 83 +++++++ app/OSM/Widgets/LinkWidget.php | 36 ++++ app/OSM/Widgets/Manager.php | 68 ++++++ app/OSM/Widgets/ModalWidget.php | 40 ++++ app/OSM/Widgets/Retro/LinkWidget.php | 40 ++++ app/OSM/Widgets/Retro/ModalWidget.php | 84 ++++++++ app/OSM/Widgets/Retro/StatsWidget.php | 47 ++++ app/OSM/Widgets/StatsWidget.php | 64 ++++++ app/OSM/Widgets/Widget.php | 70 ++++++ app/View/Components/Widget.php | 40 ++++ legacy | 2 +- resources/views/components/widget.blade.php | 25 +++ resources/views/modules/base.blade.php | 62 ++++++ resources/views/modules/title.blade.php | 17 ++ routes/web.php | 8 + 26 files changed, 1515 insertions(+), 24 deletions(-) create mode 100644 UPGRADING.md create mode 100644 app/Http/Controllers/PrintController.php delete mode 100644 app/Http/Controllers/Test.php create mode 100644 app/Http/Controllers/WidgetModalController.php create mode 100644 app/OSM/ComponentManager.php create mode 100644 app/OSM/ComponentManagerTrait.php create mode 100644 app/OSM/Prints/Autofill.php create mode 100644 app/OSM/Prints/MPDFManager.php create mode 100644 app/OSM/Prints/Manager.php create mode 100644 app/OSM/Prints/Retro/Manager.php create mode 100644 app/OSM/Prints/Template.php create mode 100644 app/OSM/Widgets/LinkWidget.php create mode 100644 app/OSM/Widgets/Manager.php create mode 100644 app/OSM/Widgets/ModalWidget.php create mode 100644 app/OSM/Widgets/Retro/LinkWidget.php create mode 100644 app/OSM/Widgets/Retro/ModalWidget.php create mode 100644 app/OSM/Widgets/Retro/StatsWidget.php create mode 100644 app/OSM/Widgets/StatsWidget.php create mode 100644 app/OSM/Widgets/Widget.php create mode 100644 app/View/Components/Widget.php create mode 100644 resources/views/components/widget.blade.php create mode 100644 resources/views/modules/base.blade.php create mode 100644 resources/views/modules/title.blade.php diff --git a/UPGRADING.md b/UPGRADING.md new file mode 100644 index 000000000..73254fb75 --- /dev/null +++ b/UPGRADING.md @@ -0,0 +1,21 @@ +```sql +ALTER TABLE zz_users ADD COLUMN remember_token VARCHAR (255) AFTER password; + +ALTER TABLE `zz_widgets` DROP `class`, ADD `class` varchar(255) NOT NULL; + +UPDATE `zz_widgets` SET `class` = 'App\\OSM\\Widgets\\Retro\\ModalWidget' WHERE `more_link_type` = 'popup'; +UPDATE `zz_widgets` SET `class` = 'App\\OSM\\Widgets\\Retro\\LinkWidget' WHERE `more_link_type` = 'link'; +UPDATE `zz_widgets` SET `class` = 'App\\OSM\\Widgets\\Retro\\StatsWidget' WHERE `more_link_type` = 'javascript'; +UPDATE `zz_widgets` SET `class` = 'App\\OSM\\Widgets\\Retro\\StatsWidget' WHERE `type` = 'print'; +UPDATE `zz_widgets` SET `class` = 'App\\OSM\\Widgets\\Retro\\StatsWidget' WHERE `class` = ''; +UPDATE `zz_widgets` SET `more_link` = `php_include` WHERE `more_link` = ''; +UPDATE `zz_widgets` SET `class` = 'App\\OSM\\Widgets\\Retro\\ModalWidget' WHERE `name` = 'Stampa calendario'; + +UPDATE `zz_widgets` SET `more_link` = REPLACE(`more_link`, 'plugins/', 'modules/'); + +ALTER TABLE `zz_widgets` DROP `print_link`, DROP `more_link_type`, DROP `php_include`; + +UPDATE `zz_widgets` SET `more_link` = REPLACE(`more_link`, './', '/'); + +UPDATE `zz_widgets` SET `class` = 'Modules\\Dashboard\\NotificheWidget', `more_link` = '' WHERE `zz_widgets`.`name` = 'Note interne'; +``` diff --git a/app/Http/Controllers/LegacyController.php b/app/Http/Controllers/LegacyController.php index 29068f9ed..081fb3c65 100644 --- a/app/Http/Controllers/LegacyController.php +++ b/app/Http/Controllers/LegacyController.php @@ -14,15 +14,46 @@ class LegacyController extends Controller public function index(Request $request) { $path = substr($request->getPathInfo(), 1); - $base_path = base_path('legacy'); + // Gestione dell'output + $output = self::simulate($path); + $response = response($output); + + // Fix content-type per contenuti non HTML + if (ends_with($path, '.js')) { + $response = $response->header('Content-Type', 'application/javascript'); + } elseif (string_contains($path, 'pdfgen.php')) { + $response = $response->header('Content-Type', 'application/pdf'); + } + // Correzione header per API + elseif (self::isApiRequest($path)) { + $response = $response->header('Content-Type', 'application/json'); + } + + return $response; + } + + protected static function isApiRequest($path) + { // Fix per redirect all'API $api_request = false; if (in_array($path, ['api', 'api/', 'api/index.php'])) { - $path = 'api/index.php'; $api_request = true; } + return $api_request; + } + + public static function simulate($path) + { + $base_path = base_path('legacy'); + + // Fix per redirect all'API + $api_request = self::isApiRequest($path); + if ($api_request) { + $path = 'api/index.php'; + } + // Ricerca del file interessato $file = realpath($base_path.'/'.$path); if (strpos($file, $base_path) === false) { @@ -40,17 +71,7 @@ class LegacyController extends Controller // Gestione dell'output $output = ob_get_clean(); - $response = response($output); - // Fix content-type per contenuti non HTML - if (ends_with($path, '.js')) { - $response = $response->header('Content-Type', 'application/javascript'); - } elseif (string_contains($path, 'pdfgen.php')) { - $response = $response->header('Content-Type', 'application/pdf'); - } elseif ($api_request) { - $response = $response->header('Content-Type', 'application/json'); - } - - return $response; + return $output; } } diff --git a/app/Http/Controllers/PrintController.php b/app/Http/Controllers/PrintController.php new file mode 100644 index 000000000..6178a7b9f --- /dev/null +++ b/app/Http/Controllers/PrintController.php @@ -0,0 +1,33 @@ + $args['print_id'], + 'record_id' => $args['record_id'], + ]); + $args['link'] = base_url().'/assets/pdfjs/web/viewer.html?file='.$link; + + $response = $this->twig->render($response, '@resources/uploads/frame.twig', $args); + + return $response; + } + + public function open(Request $request) + { + $print = Template::find($args['print_id']); + $manager = $print->getManager(); + + $pdf = $manager->render(); + + return response()->setContent($pdf) + ->header('Content-Type', 'application/pdf'); + } +} diff --git a/app/Http/Controllers/Test.php b/app/Http/Controllers/Test.php deleted file mode 100644 index 53d7ca9e7..000000000 --- a/app/Http/Controllers/Test.php +++ /dev/null @@ -1,10 +0,0 @@ -getManager(); + + if (!($class instanceof ModalWidget)) { + throw new NotFoundHttpException(); + } + + return $class->getModal(); + } +} diff --git a/app/OSM/ComponentManager.php b/app/OSM/ComponentManager.php new file mode 100644 index 000000000..b65ca2a2b --- /dev/null +++ b/app/OSM/ComponentManager.php @@ -0,0 +1,32 @@ +. + */ + +namespace App\OSM; + +use Illuminate\Database\Eloquent\Model; + +abstract class ComponentManager +{ + protected $model; + + public function __construct(Model $model) + { + $this->model = $model; + } +} diff --git a/app/OSM/ComponentManagerTrait.php b/app/OSM/ComponentManagerTrait.php new file mode 100644 index 000000000..218dbc3b6 --- /dev/null +++ b/app/OSM/ComponentManagerTrait.php @@ -0,0 +1,41 @@ +. + */ + +namespace App\OSM; + +/** + * Implementazione di base dell'interazione con i componenti a livello interno. + * + * @since 2.5 + */ +trait ComponentManagerTrait +{ + protected $manager_object; + + public function getManager(): ComponentManager + { + if (!isset($this->manager_object)) { + $class = $this->attributes['class']; + + $this->manager_object = new $class($this); + } + + return $this->manager_object; + } +} diff --git a/app/OSM/Prints/Autofill.php b/app/OSM/Prints/Autofill.php new file mode 100644 index 000000000..181b22cef --- /dev/null +++ b/app/OSM/Prints/Autofill.php @@ -0,0 +1,116 @@ +. + */ + +namespace App\OSM\Prints; + +/** + * Classe dedicata alla gestione delle righe fantasma per il miglioramento grafico delle stampe tabellari. + * + * @since 2.3 + */ +class Autofill +{ + protected $space = 0; + protected $current = 0; + + protected $char_number; + protected $column_number; + + protected $max_rows = 20; + protected $max_rows_first_page = 20; + protected $max_additional = 15; + + public function __construct($column_number, $char_number = 70) + { + $this->column_number = $column_number; + $this->char_number = $char_number; + } + + public function setRows($rows, $additional = null, $first_page = null) + { + $this->max_rows = $rows; + + $this->max_additional = isset($additional) ? $additional : floor($this->max_rows - $this->max_rows / 4); + $this->max_rows_first_page = isset($first_page) ? $first_page : $rows; + } + + public function count($text, $small = false) + { + $count = ceil(strlen($text) / $this->char_number); + $count += substr_count($text, PHP_EOL); + $count += substr_count($text, '
'); + + if ($small) { + $count = $count / 3; + } + + $this->set($count); + } + + public function set($count) + { + if ($count > $this->current) { + $this->current = $count; + } + } + + public function next() + { + $this->space += $this->current; + $this->current = 0; + } + + public function getAdditionalNumber() + { + $page = ceil($this->space / $this->max_rows_first_page); + if ($page > 1) { + $rows = floor($this->space) % $this->max_rows; + } else { + $rows = floor($this->space) % $this->max_rows_first_page; + } + + $number = $this->max_additional - $rows; + + return $number > 0 ? $number : 0; + } + + public function generate() + { + $this->next(); + + $result = ''; + + $number = $this->getAdditionalNumber(); + + for ($i = 0; $i < $number; ++$i) { + $result .= ' + '; + + for ($c = 0; $c < $this->column_number; ++$c) { + $result .= ' +  '; + } + + $result .= ' + '; + } + + return $result; + } +} diff --git a/app/OSM/Prints/MPDFManager.php b/app/OSM/Prints/MPDFManager.php new file mode 100644 index 000000000..35c3233ea --- /dev/null +++ b/app/OSM/Prints/MPDFManager.php @@ -0,0 +1,150 @@ +. + */ + +namespace App\OSM\Prints; + +use AppLegacy; +use Mpdf\Mpdf; + +/** + * Classe per la gestione delle informazioni relative alle stampe installate. + * + * @since 2.5 + */ +abstract class MPDFManager extends Manager +{ + public function getManager() + { + if (!isset($this->manager)) { + $settings = $this->getSettings(); + + // Instanziamento dell'oggetto mPDF + $manager = new Mpdf([ + 'mode' => 'utf-8', + 'format' => $settings['format'], + 'orientation' => strtoupper($settings['orientation']) == 'L' ? 'L' : 'P', + 'font-size' => $settings['font-size'], + 'margin_left' => $settings['margins']['left'], + 'margin_right' => $settings['margins']['right'], + 'setAutoBottomMargin' => 'stretch', + 'setAutoTopMargin' => 'stretch', + + // Abilitazione per lo standard PDF/A + //'PDFA' => true, + //'PDFAauto' => true, + ]); + + // Inclusione dei fogli di stile CSS + $styles = [ + AppLegacy::filepath('templates/base|custom|', 'bootstrap.css'), + AppLegacy::filepath('templates/base|custom|', 'style.css'), + ]; + + foreach ($styles as $value) { + $manager->WriteHTML(file_get_contents($value), 1); + } + + // Impostazione del font-size + $manager->WriteHTML('body {font-size: '.$settings['font-size'].'pt;}', 1); + + $this->manager = $manager; + } + + return $this->manager; + } + + /** + * Genera la stampa PDF richiesta. + */ + public function generate(?string $directory = null): array + { + $info = $this->init(); + $settings = $this->getSettings(); + $manager = $this->getManager(); + + $replaces = $this->getReplaces($info['id_cliente'], $info['id_sede']); + + $args = array_merge($info, $replaces); + + // Impostazione header + $this->renderHeader($args); + + // Impostazione footer + $this->renderFooter($args); + + // Impostazione body + $this->renderBody($args); + + // Impostazione footer per l'ultima pagina + if (!empty($options['last-page-footer'])) { + $args['is_last_page'] = true; + $footer = $this->getFooter($args); + + $manager->WriteHTML(''); + $manager->WriteHTML('
'.$footer.'
'); + } + + $file = $this->getFileData($this->record_id, $directory, $replaces); + $title = $file['name']; + + // Impostazione del titolo del PDF + $this->getManager()->SetTitle($title); + + return $file; + } + + /** + * Genera la stampa PDF richiesta e la visualizza nel browser. + */ + public function render(): void + { + $this->generate(); + + // Creazione effettiva del PDF + $this->getManager()->Output(null, \Mpdf\Output\Destination::INLINE); + } + + /** + * Genera la stampa PDF richiesta e la visualizza nel browser. + */ + public function save(string $directory): void + { + parent::save($directory); + $file = $this->generate($directory); + + // Creazione effettiva del PDF + $this->getManager()->Output($file['path'], \Mpdf\Output\Destination::FILE); + } + + protected function renderHeader(array $args): void + { + $content = $this->getHeader($args); + + // Impostazione di header + $this->getManager()->SetHTMLHeader($content); + } + + protected function renderFooter(array $args): void + { + $content = $this->getFooter($args); + + // Impostazione di footer + $this->getManager()->SetHTMLFooter($content); + } +} diff --git a/app/OSM/Prints/Manager.php b/app/OSM/Prints/Manager.php new file mode 100644 index 000000000..c422c2b40 --- /dev/null +++ b/app/OSM/Prints/Manager.php @@ -0,0 +1,204 @@ +. + */ + +namespace App\OSM\Prints; + +use App; +use AppLegacy; + +abstract class Manager extends App\OSM\ComponentManager +{ + protected $record_id; + + protected $manager; + protected $replaces; + + public function setRecord(?int $record_id = null) + { + $this->record_id = $record_id; + } + + /** + * Genera e salva la stampa PDF richiesta. + */ + public function save(string $directory): void + { + if (empty($directory) || !directory($directory)) { + throw new \InvalidArgumentException(); + } + } + + /** + * Genera la stampa PDF richiesta e la visualizza nel browser. + */ + abstract public function render(array $args = []): string; + + /** + * Genera la stampa PDF richiesta. + */ + abstract public function generate(?string $directory = null): array; + + protected function getSettings(): array + { + // Impostazioni di default + $default = include AppLegacy::filepath('templates/base|custom|', 'settings.php'); + + // Impostazioni personalizzate della stampa + $custom = $this->getTemplateSettings(); + + // Individuazione delle impostazioni finali + $settings = array_merge($default, (array) $custom); + + return $settings; + } + + protected function getHeader(array $args): string + { + $content = $this->getTemplateHeader($args); + + return !empty($content) ? $content : '$default_header$'; + } + + protected function getFooter(array $args): string + { + $content = $this->getTemplateFooter($args); + + return !empty($content) ? $content : '$default_footer$'; + } + + protected function getReplaces(?int $id_cliente = null, ?int $id_sede = null): array + { + if (isset($this->replaces)) { + return $this->replaces; + } + + $database = $this->database; + $id_record = $this->record_id; + + // Informazioni cliente + $query = 'SELECT an_anagrafiche.*, an_sedi.*, + IF(an_sedi.codice_fiscale != "", an_sedi.codice_fiscale, sede_legale.codice_fiscale) AS codice_fiscale, + IF(an_sedi.piva != "", an_sedi.piva, sede_legale.piva) AS piva + FROM an_anagrafiche + INNER JOIN an_sedi ON an_anagrafiche.idanagrafica = an_sedi.idanagrafica + INNER JOIN an_sedi AS sede_legale ON an_anagrafiche.id_sede_legale = an_sedi.id + WHERE an_sedi.idanagrafica='.prepare($id_cliente); + if (empty($id_sede)) { + $query .= ' AND `an_sedi`.`id`=`an_anagrafiche`.`id_sede_legale`'; + } else { + $query .= ' AND `an_sedi`.`id`='.prepare($id_sede); + } + $cliente = $database->fetchOne($query); + + // Informazioni azienda + $id_azienda = setting('Azienda predefinita'); + $azienda = $database->fetchOne('SELECT *, (SELECT iban FROM co_banche WHERE id IN (SELECT idbanca FROM co_documenti WHERE id = '.prepare($id_record).' ) ) AS codiceiban, (SELECT nome FROM co_banche WHERE id IN (SELECT idbanca FROM co_documenti WHERE id = '.prepare($id_record).' ) ) AS appoggiobancario, (SELECT bic FROM co_banche WHERE id IN (SELECT idbanca FROM co_documenti WHERE id = '.prepare($id_record).' ) ) AS bic FROM an_anagrafiche WHERE idanagrafica = '.prepare($id_azienda)); + + // Prefissi e contenuti del replace + $results = [ + 'cliente' => $cliente, + 'azienda' => $azienda, + ]; + + foreach ($results as $prefix => $values) { + // Eventuali estensioni dei contenuti + $citta = ''; + if (!empty($values['cap'])) { + $citta .= $values['cap']; + } + if (!empty($values['citta'])) { + $citta .= ' '.$values['citta']; + } + if (!empty($values['provincia'])) { + $citta .= ' ('.$values['provincia'].')'; + } + + $results[$prefix]['citta_full'] = $citta; + } + + // Header di default + $header_file = AppLegacy::filepath('templates/base|custom|/header.php'); + $default_header = include $header_file; + $default_header = !empty($options['hide-header']) ? '' : $default_header; + + // Footer di default + $footer_file = AppLegacy::filepath('templates/base|custom|/footer.php'); + $default_footer = include $footer_file; + $default_footer = !empty($options['hide-footer']) ? '' : $default_footer; + + // Logo di default + $default_logo = AppLegacy::filepath('templates/base|custom|/logo_azienda.jpg'); + + // Logo generico + if (!empty(setting('Logo stampe'))) { + $default_logo = AppLegacy::filepath('files/anagrafiche/'.setting('Logo stampe')); + } + + // Valori aggiuntivi per la sostituzione + $this->replaces = array_merge($results, [ + 'default_header' => $default_header, + 'default_footer' => $default_footer, + 'default_logo' => $default_logo, + ]); + + return $this->replaces; + } + + protected function getFileData($directory, $original_replaces) + { + $id_record = $this->record_id; + $module = $this->print->module; + + $name = $this->print->filename.'.pdf'; + $name = $module->replacePlaceholders($id_record, $name); + + $replaces = []; + foreach ($original_replaces as $key => $value) { + $key = str_replace('$', '', $key); + + $replaces['{'.$key.'}'] = $value; + } + + $name = replace($name, $replaces); + + $filename = sanitizeFilename($name); + $file = rtrim($directory, '/').'/'.$filename; + + return [ + 'name' => $name, + 'path' => $file, + ]; + } + + abstract protected function init(): array; + + abstract protected function getManager(); + + abstract protected function renderHeader(array $args): void; + + abstract protected function renderFooter(array $args): void; + + abstract protected function renderBody(array $args): void; + + abstract protected function getTemplateSettings(): array; + + abstract protected function getTemplateHeader(array $args): string; + + abstract protected function getTemplateFooter(array $args): string; +} diff --git a/app/OSM/Prints/Retro/Manager.php b/app/OSM/Prints/Retro/Manager.php new file mode 100644 index 000000000..bbbf2addd --- /dev/null +++ b/app/OSM/Prints/Retro/Manager.php @@ -0,0 +1,176 @@ +. + */ + +namespace App\OSM\Prints\Retro; + +use App; +use AppLegacy; +use App\OSM\Prints\MPDFManager; + +class Manager extends MPDFManager +{ + protected $body; + protected $header; + protected $footer; + + protected function renderBody(array $args): void + { + $this->load($args); + + $this->getManager()->WriteHTML($this->body); + } + + protected function load(array $args): void + { + if (isset($this->body)) { + return; + } + + // Fix per le variabili in PHP + foreach ($args['cliente'] as $key => $value) { + $args['c_'.$key] = $value; + } + + foreach ($args['azienda'] as $key => $value) { + $args['f_'.$key] = $value; + } + + extract($args); + $dbo = $database = database(); + + ob_start(); + include $this->filepath('header.php'); + $content = ob_get_clean(); + + $this->header = $this->replace($content); + + ob_start(); + include $this->filepath('body.php'); + $content = ob_get_clean(); + + if (!empty($autofill)) { + $result = $autofill->generate(); + + $content = str_replace('|autofill|', $result, $content); + } + + $this->body = $this->replace($content); + + ob_start(); + include $this->filepath('footer.php'); + $content = ob_get_clean(); + + $this->footer = $this->replace($content); + } + + protected function getReplaces(?int $id_cliente = null, ?int $id_sede = null): array + { + $replaces = parent::getReplaces($id_cliente, $id_sede); + + // Logo specifico della stampa + $logo = \Prints::filepath($this->print->id, 'logo_azienda.jpg'); + $logo = $logo ?: $replaces['default_logo']; + + // Valori aggiuntivi per la sostituzione + $this->replaces = array_merge($replaces, [ + 'logo' => $logo, + ]); + + return $this->replaces; + } + + protected function replace($content): string + { + $info = $this->init(); + $replaces = $this->getReplaces($info['id_cliente'], $info['id_sede']); + + $replaces = array_merge($replaces, (array) $info['custom']); + + $list = []; + foreach ($replaces as $key => $value) { + if (!is_array($value)) { + $list[$key] = $value; + } + } + + foreach ($replaces['cliente'] as $key => $value) { + $list['c_'.$key] = $value; + } + + foreach ($replaces['azienda'] as $key => $value) { + $list['f_'.$key] = $value; + } + + $results = []; + foreach ($list as $key => $value) { + $results['$'.$key.'$'] = $value; + } + + return replace($content, $results); + } + + protected function getPath(): string + { + return base_path().'/templates/'.$this->print->directory; + } + + protected function filepath($file): ?string + { + return AppLegacy::filepath($this->getPath().'|custom|', $file); + } + + protected function init(): array + { + $record_id = $id_record = $this->record_id; + $module_id = $id_module = $this->print->module->id; + $print_id = $id_print = $this->print->id; + + $dbo = $database = database(); + + // Individuazione delle variabili fondamentali per la sostituzione dei contenuti + include $this->filepath('init.php'); + + return get_defined_vars(); + } + + protected function getTemplateSettings(): array + { + $file = $this->filepath('settings.php'); + + if (file_exists($file)) { + return include $file; + } + + return []; + } + + protected function getTemplateHeader(array $args): string + { + $this->load($args); + + return $this->header; + } + + protected function getTemplateFooter(array $args): string + { + $this->load($args); + + return $this->footer; + } +} diff --git a/app/OSM/Prints/Template.php b/app/OSM/Prints/Template.php new file mode 100644 index 000000000..50a1fbe1d --- /dev/null +++ b/app/OSM/Prints/Template.php @@ -0,0 +1,83 @@ +. + */ + +namespace App\OSM\Prints; + +use App\OSM\ComponentManagerTrait; +use Common\SimpleModelTrait; +use Models\Group; +use Common\Model; +use Illuminate\Database\Eloquent\Builder; +use Models\Module; +use Traits\LocalPoolTrait; + +class Template extends Model +{ + use SimpleModelTrait; + use LocalPoolTrait; + use ComponentManagerTrait; + + protected $table = 'zz_prints'; + protected $main_folder = 'templates'; + + // Attributi Eloquent + + /** + * Restituisce un array associativo dalla codifica JSON delle opzioni di stampa. + * + * @param string $string + * + * @return array + */ + public function getOptionsAttribute() + { + // Fix per contenuti con newline integrate + $string = str_replace(["\n", "\r"], ['\\n', '\\r'], $this->options); + + $result = (array) json_decode($string, true); + + return $result; + } + + /* Relazioni Eloquent */ + + public function module() + { + return $this->belongsTo(Module::class, 'id_module'); + } + + /* + public function groups() + { + return $this->morphToMany(Group::class, 'permission', 'zz_permissions', 'external_id', 'group_id')->where('permission_level', '!=', '-')->withPivot('permission_level'); + }*/ + + protected static function boot() + { + parent::boot(); + + static::addGlobalScope('enabled', function (Builder $builder) { + $builder->where('enabled', true); + }); + + static::addGlobalScope('permission', function (Builder $builder) { + //$builder->with('groups'); + }); + } +} diff --git a/app/OSM/Widgets/LinkWidget.php b/app/OSM/Widgets/LinkWidget.php new file mode 100644 index 000000000..4532052e4 --- /dev/null +++ b/app/OSM/Widgets/LinkWidget.php @@ -0,0 +1,36 @@ +. + */ + +namespace App\OSM\Widgets; + +/** + * Tipologia di widget indirizzato alla presentazione di un link ausiliario per l'utente finale. + * Presenta esclusivamente un tiolo e al click prevede il reindirizzamento a un indirizzo specifico. + * + * @since 2.5 + */ +abstract class LinkWidget extends Manager +{ + abstract public function getLink(): string; + + public function getAttributes(): string + { + return 'href="'.$this->getLink().'"'; + } +} diff --git a/app/OSM/Widgets/Manager.php b/app/OSM/Widgets/Manager.php new file mode 100644 index 000000000..a99361b38 --- /dev/null +++ b/app/OSM/Widgets/Manager.php @@ -0,0 +1,68 @@ +. + */ + +namespace App\OSM\Widgets; + +use App\OSM\ComponentManager; + +/** + * Classe dedicata alla gestione di base dei widget del gestionale. + * Introduce un rendering di base e definisce i comportamenti standard da estendere per un utilizzo piĆ¹ completo. + * + * @since 2.5 + */ +abstract class Manager extends ComponentManager +{ + protected $record_id; + + public function setRecord(?int $record_id = null) + { + $this->record_id = $record_id; + } + + /** + * Get the view / contents that represent the component. + * + * @return \Illuminate\Contracts\View\View|string + */ + public function render() + { + $widget = $this->model; + + $title = $this->getTitle(); + $content = $this->getContent(); + $attributes = $this->getAttributes(); + + return view('components.widget', [ + 'widget' => $widget, + 'title' => $title, + 'content' => $content, + 'attrs' => $attributes, + ]); + } + + abstract public function getTitle(): string; + + abstract public function getContent(): string; + + public function getAttributes(): string + { + return 'href="#"'; + } +} diff --git a/app/OSM/Widgets/ModalWidget.php b/app/OSM/Widgets/ModalWidget.php new file mode 100644 index 000000000..4cb4dc2c2 --- /dev/null +++ b/app/OSM/Widgets/ModalWidget.php @@ -0,0 +1,40 @@ +. + */ + +namespace App\OSM\Widgets; + +/** + * Tipologia di widget dedicato alla gestione di un modal aperto al click + * Presenta un titolo e una valore personalizzato; al click produce l'apertura del modal specificato. + * + * @since 2.5 + */ +abstract class ModalWidget extends Manager +{ + abstract public function getModal(): string; + + abstract public function getLink(): string; + + public function getAttributes(): string + { + $title = $this->getTitle(); + + return 'data-href="'.$this->getLink().'" data-toggle="modal" data-title="'.$title.'"'; + } +} diff --git a/app/OSM/Widgets/Retro/LinkWidget.php b/app/OSM/Widgets/Retro/LinkWidget.php new file mode 100644 index 000000000..576e680ba --- /dev/null +++ b/app/OSM/Widgets/Retro/LinkWidget.php @@ -0,0 +1,40 @@ +. + */ + +namespace App\OSM\Widgets\Retro; + +use App\OSM\Widgets\LinkWidget as Original; + +class LinkWidget extends Original +{ + public function getLink(): string + { + return base_url().$this->model['more_link']; + } + + public function getTitle(): string + { + return $this->model['text']; + } + + public function getContent(): string + { + return ''; + } +} diff --git a/app/OSM/Widgets/Retro/ModalWidget.php b/app/OSM/Widgets/Retro/ModalWidget.php new file mode 100644 index 000000000..5d9bf3d23 --- /dev/null +++ b/app/OSM/Widgets/Retro/ModalWidget.php @@ -0,0 +1,84 @@ +. + */ + +namespace App\OSM\Widgets\Retro; + +use App\Http\Controllers\LegacyController; +use Models\Module; +use Util\Query; +use App\OSM\Widgets\ModalWidget as Original; + +class ModalWidget extends Original +{ + public function getModal(): string + { + $content = ''; + + $widget = $this->model; + if (!empty($widget['more_link'])) { + $content = LegacyController::simulate($widget['more_link']); + } + + return $content; + } + + public function getLink(): string + { + $id = $this->model->id; + + return route('widget-modal', [ + 'id' => $id, + ]); + } + + public function getTitle(): string + { + return $this->model['text'] ?: ''; + } + + public function getContent(): string + { + $content = ''; + + $widget = $this->model; + if (!empty($widget['query'])) { + $query = $widget['query']; + $module = Module::pool($widget['id_module']); + + $additionals = \Modules::getAdditionalsQuery($widget['id_module']); + //$additionals = $module->getAdditionalsQuery(); + if (!empty($additionals)) { + $query = str_replace('1=1', '1=1 '.$additionals, $query); + } + + $query = Query::replacePlaceholder($query); + + // Individuazione del risultato della query + $database = database(); + $value = '-'; + if (!empty($query)) { + $value = $database->fetchArray($query)[0]['dato']; + } + + $content = preg_match('/\\d/', $value) ? $value : '-'; + } + + return $content; + } +} diff --git a/app/OSM/Widgets/Retro/StatsWidget.php b/app/OSM/Widgets/Retro/StatsWidget.php new file mode 100644 index 000000000..4ccb8a320 --- /dev/null +++ b/app/OSM/Widgets/Retro/StatsWidget.php @@ -0,0 +1,47 @@ +. + */ + +namespace App\OSM\Widgets\Retro; + +use App\OSM\Widgets\StatsWidget as Original; + +class StatsWidget extends Original +{ + public function getQuery(): string + { + return $this->model['query'] ?: 'SELECT 0 AS dato'; + } + + public function getAttributes(): string + { + $attributes = parent::getAttributes(); + $js = $this->model['more_link']; + + if (!empty($js)) { + return $attributes.' onclick="'.$js.'"'; + } + + return $attributes; + } + + public function getTitle(): string + { + return $this->model['text']; + } +} diff --git a/app/OSM/Widgets/StatsWidget.php b/app/OSM/Widgets/StatsWidget.php new file mode 100644 index 000000000..4d9117ebd --- /dev/null +++ b/app/OSM/Widgets/StatsWidget.php @@ -0,0 +1,64 @@ +. + */ + +namespace App\OSM\Widgets; + +use Models\Module; +use Util\Query; + +/** + * Tipologia di widget indirizzato alla visualizzazione di una statistica informativa per l'utente finale. + * Presenta un titolo e una valore personalizzato; al click non prevede particolari operazioni. + * + * @since 2.5 + */ +abstract class StatsWidget extends Manager +{ + abstract public function getQuery(): string; + + public function getContent(): string + { + $widget = $this->model; + + // Individuazione della query relativa + $query = $this->getQuery(); + + $module = Module::pool($widget['id_module']); + + $additionals = \Modules::getAdditionalsQuery($widget['id_module']); + //$additionals = $module->getAdditionalsQuery(); + if (!empty($additionals)) { + $query = str_replace('1=1', '1=1 '.$additionals, $query); + } + + $query = Query::replacePlaceholder($query); + + // Individuazione del risultato della query + $database = database(); + $value = null; + if (!empty($query)) { + $value = $database->fetchArray($query)[0]['dato']; + if (!preg_match('/\\d/', $value)) { + $value = '-'; + } + } + + return $value; + } +} diff --git a/app/OSM/Widgets/Widget.php b/app/OSM/Widgets/Widget.php new file mode 100644 index 000000000..536a5b221 --- /dev/null +++ b/app/OSM/Widgets/Widget.php @@ -0,0 +1,70 @@ +. + */ + +namespace App\OSM\Widgets; + +use App\OSM\ComponentManagerTrait; +use Common\SimpleModelTrait; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Model; +use Models\Module; + +/** + * Modello Eloquent per i widget del gestionale. + * + * @since 2.5 + */ +class Widget extends Model +{ + use SimpleModelTrait; + use ComponentManagerTrait; + + protected $table = 'zz_widgets'; + + protected $appends = [ + 'permission', + ]; + + /* Relazioni Eloquent */ + + public function module() + { + return $this->belongsTo(Module::class, 'id_module'); + } + + /* + public function groups() + { + return $this->morphToMany(Group::class, 'permission', 'zz_permissions', 'external_id', 'group_id')->where('permission_level', '!=', '-')->withPivot('permission_level'); + } + */ + + protected static function boot() + { + parent::boot(); + + static::addGlobalScope('enabled', function (Builder $builder) { + $builder->where('enabled', true); + }); + + static::addGlobalScope('permission', function (Builder $builder) { + //$builder->with('groups'); + }); + } +} diff --git a/app/View/Components/Widget.php b/app/View/Components/Widget.php new file mode 100644 index 000000000..1d70845c6 --- /dev/null +++ b/app/View/Components/Widget.php @@ -0,0 +1,40 @@ +widget = Model::find($id); + $this->manager = $this->widget->getManager(); + } + + /** + * Get the view / contents that represent the component. + * + * @return \Illuminate\Contracts\View\View|string + */ + public function render() + { + $manager = $this->manager; + + return $manager->render(); + } +} diff --git a/legacy b/legacy index 5730434cc..767e211f4 160000 --- a/legacy +++ b/legacy @@ -1 +1 @@ -Subproject commit 5730434cc63c67880049f6adb116791dc8af8a5b +Subproject commit 767e211f4c616315618e222b6d55338f92d247a5 diff --git a/resources/views/components/widget.blade.php b/resources/views/components/widget.blade.php new file mode 100644 index 000000000..58557df7a --- /dev/null +++ b/resources/views/components/widget.blade.php @@ -0,0 +1,25 @@ + +
+ + + + @if(!empty($widget['icon'])) + + @endif + + +
+ + {{ $title }} + + {{ !empty($widget['help']) ? '' : '' }} + + + @if(isset($content)) + {{ $content }} + @endif +
+
+
diff --git a/resources/views/modules/base.blade.php b/resources/views/modules/base.blade.php new file mode 100644 index 000000000..0eeada437 --- /dev/null +++ b/resources/views/modules/base.blade.php @@ -0,0 +1,62 @@ +@extends('layouts.app') + +@section('title', $module->title) + +@section('content') + @yield('top_content') + + + +
+
+ @yield('module_content') +
+
+ + @yield('bottom_content') + + +@endsection + +@section('top_content') + + {( "name": "widgets", "id_module": "{{ $module->id }}", "id_record": "{{ 1 }}", "position": "top", "place": "controller" )} +@endsection + +@section('bottom_content') + + {( "name": "widgets", "id_module": "{{ $module->id }}", "id_record": "{{ 1 }}", "position": "right", "place": "controller" )} +@endsection diff --git a/resources/views/modules/title.blade.php b/resources/views/modules/title.blade.php new file mode 100644 index 000000000..9c85b4aae --- /dev/null +++ b/resources/views/modules/title.blade.php @@ -0,0 +1,17 @@ +@if(!empty($module->help)) + + {{ $module->title }} + + + +@else + {{ $module->title }} +@endif + +{{-- $module->hasAddFile() and --}} +@if($module->permission == 'rw') + + +@endif diff --git a/routes/web.php b/routes/web.php index add4c0fdc..4bbf41065 100644 --- a/routes/web.php +++ b/routes/web.php @@ -9,6 +9,7 @@ use App\Http\Controllers\MessageController; use App\Http\Controllers\RequirementsController; use App\Http\Controllers\Test; use App\Http\Controllers\UserController; +use App\Http\Controllers\WidgetModalController; use Illuminate\Support\Facades\Route; /* @@ -119,6 +120,13 @@ Route::get('/logs', [UserController::class, 'logs']) ->middleware(['auth']) ->name('logs'); + +// Log di accesso +Route::get('/widget/modal/{id}', [WidgetModalController::class, 'modal']) + ->whereNumber('id') + ->middleware(['auth']) + ->name('widget-modal'); + // Informazioni sull'utente Route::prefix('user') ->middleware(['auth'])