Skip to content

Commit 3d658d5

Browse files
committed
feat: verifica title assenti database
1 parent 51cfe96 commit 3d658d5

3 files changed

Lines changed: 352 additions & 1 deletion

File tree

modules/aggiornamenti/actions.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use Modules\Aggiornamenti\Controlli\PianoContiRagioneSociale;
2929
use Modules\Aggiornamenti\Controlli\PluginDuplicati;
3030
use Modules\Aggiornamenti\Controlli\ReaValidi;
31+
use Modules\Aggiornamenti\Controlli\TabelleLanguage;
3132
use Modules\Aggiornamenti\UpdateHook;
3233

3334
$id = post('id');
@@ -152,6 +153,7 @@
152153
ColonneDuplicateViste::class,
153154
PluginDuplicati::class,
154155
ReaValidi::class,
156+
TabelleLanguage::class,
155157
];
156158

157159
$results = [];

modules/aggiornamenti/controlli.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,8 @@ function hasGlobalActions(controllo) {
309309
"Modules\\\\Aggiornamenti\\\\Controlli\\\\PianoContiRagioneSociale",
310310
"Modules\\\\Aggiornamenti\\\\Controlli\\\\ReaValidi",
311311
"Modules\\\\Aggiornamenti\\\\Controlli\\\\ColonneDuplicateViste",
312-
"Modules\\\\Aggiornamenti\\\\Controlli\\\\PluginDuplicati"
312+
"Modules\\\\Aggiornamenti\\\\Controlli\\\\PluginDuplicati",
313+
"Modules\\\\Aggiornamenti\\\\Controlli\\\\TabelleLanguage"
313314
];
314315
315316
return controlliConAzioniGlobali.includes(controllo["class"]);
@@ -363,6 +364,17 @@ function getMessaggioConferma(controlloClass) {
363364
"'.tr('I plugin duplicati verranno rimossi definitivamente dal database').'",
364365
"'.tr('Non può essere annullata').'"
365366
]
367+
},
368+
"Modules\\\\Aggiornamenti\\\\Controlli\\\\TabelleLanguage": {
369+
titolo: "'.tr('Conferma correzione tabelle multilingua').'",
370+
descrizione: "'.tr('Sei sicuro di voler correggere tutti i record mancanti nelle tabelle multilingua?').'",
371+
operazioni: [
372+
"'.tr('Inserirà i record mancanti nelle tabelle _lang per tutte le lingue disponibili').'",
373+
"'.tr('Popolerà i campi con valori di default presi dalle tabelle principali quando possibile').'",
374+
"'.tr('Non modificherà i record esistenti, aggiungerà solo quelli mancanti').'",
375+
"'.tr('Migliorerà la coerenza del database multilingua').'",
376+
"'.tr('Operazione sicura e reversibile').'"
377+
]
366378
}
367379
};
368380
Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
<?php
2+
3+
/*
4+
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
5+
* Copyright (C) DevCode s.r.l.
6+
*
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
*/
20+
21+
namespace Modules\Aggiornamenti\Controlli;
22+
23+
use Models\Locale;
24+
25+
class TabelleLanguage extends Controllo
26+
{
27+
public function getName()
28+
{
29+
return tr('Integrità tabelle multilingua');
30+
}
31+
32+
public function getType($record)
33+
{
34+
return 'warning';
35+
}
36+
37+
public function getOptions($record)
38+
{
39+
return [
40+
[
41+
'name' => tr('Correggi'),
42+
'icon' => 'fa fa-check',
43+
'color' => 'success',
44+
'params' => [],
45+
],
46+
];
47+
}
48+
49+
/**
50+
* Indica se questo controllo supporta azioni globali
51+
*/
52+
public function hasGlobalActions()
53+
{
54+
return true;
55+
}
56+
57+
/**
58+
* Restituisce le azioni globali disponibili per questo controllo
59+
*/
60+
public function getGlobalActions()
61+
{
62+
return [
63+
[
64+
'name' => tr('Correggi tutti'),
65+
'icon' => 'fa fa-check-circle',
66+
'color' => 'success',
67+
'params' => [],
68+
],
69+
];
70+
}
71+
72+
public function check()
73+
{
74+
$database = database();
75+
76+
// Ottieni tutte le lingue disponibili
77+
$languages = Locale::all();
78+
$total_languages = count($languages);
79+
80+
if ($total_languages == 0) {
81+
return; // Salta se non ci sono lingue configurate
82+
}
83+
84+
// Ottieni tutte le tabelle del database
85+
$tables = $database->fetchArray('SHOW TABLES');
86+
$table_column = 'Tables_in_' . $database->getDatabaseName();
87+
88+
$main_tables = [];
89+
$lang_tables = [];
90+
91+
// Separa le tabelle principali da quelle _lang
92+
foreach ($tables as $table) {
93+
$table_name = $table[$table_column];
94+
if (substr($table_name, -5) === '_lang') {
95+
$lang_tables[] = $table_name;
96+
} else {
97+
$main_tables[] = $table_name;
98+
}
99+
}
100+
101+
// Raggruppa i risultati per tabella
102+
$results_by_table = [];
103+
104+
// Per ogni tabella _lang, trova la corrispondente tabella principale
105+
foreach ($lang_tables as $lang_table) {
106+
$main_table = str_replace('_lang', '', $lang_table);
107+
108+
// Verifica se la tabella principale esiste
109+
if (!in_array($main_table, $main_tables)) {
110+
continue;
111+
}
112+
113+
// Verifica se la tabella principale ha un campo 'id'
114+
$main_columns = $database->fetchArray("SHOW COLUMNS FROM `{$main_table}`");
115+
$has_id_field = false;
116+
foreach ($main_columns as $column) {
117+
if ($column['Field'] === 'id') {
118+
$has_id_field = true;
119+
break;
120+
}
121+
}
122+
123+
if (!$has_id_field) {
124+
continue;
125+
}
126+
127+
// Verifica se la tabella _lang ha i campi necessari
128+
$lang_columns = $database->fetchArray("SHOW COLUMNS FROM `{$lang_table}`");
129+
$has_id_record = false;
130+
$has_id_lang = false;
131+
$other_fields = [];
132+
133+
foreach ($lang_columns as $column) {
134+
$field_name = $column['Field'];
135+
if ($field_name === 'id_record') {
136+
$has_id_record = true;
137+
} elseif ($field_name === 'id_lang') {
138+
$has_id_lang = true;
139+
} elseif (!in_array($field_name, ['id', 'id_record', 'id_lang'])) {
140+
$other_fields[] = $field_name;
141+
}
142+
}
143+
144+
if (!$has_id_record || !$has_id_lang) {
145+
continue;
146+
}
147+
148+
// Determina il campo da usare per il nome del record
149+
$name_field = $this->getNameField($main_table, $main_columns);
150+
151+
// Trova i record che non hanno traduzioni per tutte le lingue
152+
$name_select = $name_field ? "mt.`{$name_field}` as record_name," : "CONCAT('ID: ', mt.id) as record_name,";
153+
154+
$missing_records = $database->fetchArray("
155+
SELECT
156+
mt.id,
157+
{$name_select}
158+
'{$main_table}' as main_table,
159+
'{$lang_table}' as lang_table,
160+
COUNT(DISTINCT lt.id_lang) as lingue_presenti,
161+
{$total_languages} as lingue_totali,
162+
GROUP_CONCAT(DISTINCT lt.id_lang ORDER BY lt.id_lang) as id_lingue_presenti
163+
FROM `{$main_table}` mt
164+
LEFT JOIN `{$lang_table}` lt ON mt.id = lt.id_record
165+
GROUP BY mt.id
166+
HAVING COUNT(DISTINCT lt.id_lang) < {$total_languages}
167+
");
168+
169+
if (!empty($missing_records)) {
170+
$results_by_table[$main_table] = [
171+
'main_table' => $main_table,
172+
'lang_table' => $lang_table,
173+
'total_missing' => count($missing_records),
174+
'records' => []
175+
];
176+
177+
foreach ($missing_records as $record) {
178+
$lingue_mancanti = [];
179+
$lingue_presenti = !empty($record['id_lingue_presenti']) ? explode(',', $record['id_lingue_presenti']) : [];
180+
181+
foreach ($languages as $language) {
182+
if (!in_array($language->id, $lingue_presenti)) {
183+
$lingue_mancanti[] = $language->name;
184+
}
185+
}
186+
187+
$results_by_table[$main_table]['records'][] = [
188+
'id' => $record['id'],
189+
'record_name' => $record['record_name'] ?: 'ID: ' . $record['id'],
190+
'lingue_presenti' => $record['lingue_presenti'],
191+
'lingue_totali' => $record['lingue_totali'],
192+
'lingue_mancanti' => $lingue_mancanti,
193+
];
194+
}
195+
}
196+
}
197+
198+
// Aggiungi i risultati raggruppati
199+
foreach ($results_by_table as $table_data) {
200+
// Crea un record di riepilogo per la tabella
201+
$record_ids = array_column($table_data['records'], 'id');
202+
$record_names = array_column($table_data['records'], 'record_name');
203+
204+
$this->addResult([
205+
'id' => 'table_' . $table_data['main_table'],
206+
'main_table' => $table_data['main_table'],
207+
'lang_table' => $table_data['lang_table'],
208+
'total_missing' => $table_data['total_missing'],
209+
'record_ids' => $record_ids,
210+
'nome' => tr('Tabella: _TABLE_', ['_TABLE_' => $table_data['main_table']]),
211+
'descrizione' => tr('_COUNT_ record con traduzioni mancanti: _NAMES_', [
212+
'_COUNT_' => $table_data['total_missing'],
213+
'_NAMES_' => implode(', ', array_slice($record_names, 0, 5)) . (count($record_names) > 5 ? '...' : '')
214+
]),
215+
]);
216+
}
217+
}
218+
219+
/**
220+
* Determina il campo da usare per il nome del record
221+
*/
222+
private function getNameField($table_name, $columns)
223+
{
224+
// Campi comuni per i nomi
225+
$name_fields = ['name', 'nome', 'title', 'descrizione', 'ragione_sociale', 'codice'];
226+
227+
$available_fields = array_column($columns, 'Field');
228+
229+
foreach ($name_fields as $field) {
230+
if (in_array($field, $available_fields)) {
231+
return $field;
232+
}
233+
}
234+
235+
return null;
236+
}
237+
238+
public function execute($record, $params = [])
239+
{
240+
$database = database();
241+
$main_table = $record['main_table'];
242+
$lang_table = $record['lang_table'];
243+
244+
// Se è un record raggruppato per tabella, correggi tutti i record della tabella
245+
if (isset($record['record_ids']) && is_array($record['record_ids'])) {
246+
$record_ids = $record['record_ids'];
247+
} else {
248+
// Singolo record (per compatibilità)
249+
$record_ids = [$record['id']];
250+
}
251+
252+
// Ottieni tutte le lingue disponibili
253+
$languages = Locale::all();
254+
255+
// Ottieni i campi della tabella _lang (esclusi id, id_record, id_lang)
256+
$lang_columns = $database->fetchArray("SHOW COLUMNS FROM `{$lang_table}`");
257+
$fields_to_populate = [];
258+
259+
foreach ($lang_columns as $column) {
260+
$field_name = $column['Field'];
261+
if (!in_array($field_name, ['id', 'id_record', 'id_lang'])) {
262+
$fields_to_populate[] = $field_name;
263+
}
264+
}
265+
266+
$corrected_count = 0;
267+
268+
// Per ogni record ID da correggere
269+
foreach ($record_ids as $record_id) {
270+
// Per ogni lingua, inserisci il record se non esiste
271+
foreach ($languages as $language) {
272+
$existing = $database->fetchOne("
273+
SELECT id FROM `{$lang_table}`
274+
WHERE id_record = " . prepare($record_id) . "
275+
AND id_lang = " . prepare($language->id)
276+
);
277+
278+
if (!$existing) {
279+
// Prepara i dati per l'inserimento
280+
$insert_data = [
281+
'id_record' => $record_id,
282+
'id_lang' => $language->id
283+
];
284+
285+
// Cerca di ottenere valori di default dalla tabella principale
286+
$main_record = $database->fetchOne("SELECT * FROM `{$main_table}` WHERE id = " . prepare($record_id));
287+
288+
if ($main_record) {
289+
foreach ($fields_to_populate as $field) {
290+
// Cerca campi corrispondenti nella tabella principale
291+
$default_value = '';
292+
293+
// Mappature comuni per i campi
294+
$field_mappings = [
295+
'name' => ['nome', 'name', 'descrizione', 'title'],
296+
'title' => ['title', 'nome', 'name', 'descrizione'],
297+
'description' => ['descrizione', 'description', 'nome', 'name']
298+
];
299+
300+
if (isset($field_mappings[$field])) {
301+
foreach ($field_mappings[$field] as $possible_field) {
302+
if (isset($main_record[$possible_field]) && !empty($main_record[$possible_field])) {
303+
$default_value = $main_record[$possible_field];
304+
break;
305+
}
306+
}
307+
} elseif (isset($main_record[$field])) {
308+
$default_value = $main_record[$field];
309+
}
310+
311+
$insert_data[$field] = $default_value;
312+
}
313+
}
314+
315+
// Inserisci il record
316+
$database->table($lang_table)->insert($insert_data);
317+
$corrected_count++;
318+
}
319+
}
320+
}
321+
322+
return $corrected_count > 0;
323+
}
324+
325+
/**
326+
* Esegue la correzione globale per tutti i record trovati
327+
*/
328+
public function solveGlobal($params = [])
329+
{
330+
$results = [];
331+
foreach ($this->results as $record) {
332+
$results[$record['id']] = $this->execute($record, $params);
333+
}
334+
335+
return $results;
336+
}
337+
}

0 commit comments

Comments
 (0)