Files
trf_certest/public/userarea/routines/_engine.php
T
2026-09-05 13:41:26 +02:00

297 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Routine motore generico (_engine.php)
* -------------------------------------
* File UNICO condiviso da tutte le routine con engine = 1.
*
* Espone la stessa firma delle routine legacy:
*
* applyRoutine(&$excelData, $routineData)
*
* così apply_routine.php lo include allo stesso modo. La differenza è che qui
* NON c'è logica hardcoded: gli step vengono letti dalla tabella routine_step
* (in base a routineData['idroutine']) ed eseguiti in ordine.
*
* Ogni step ha una `operation` (verbo del vocabolario) e `params` JSON.
* Le colonne nei params possono essere indici zero-based (3) o lettere Excel ("D").
*/
if (!function_exists('applyRoutine')) {
/**
* Converte un riferimento colonna in indice zero-based.
* Accetta int/indici numerici (3) o lettere Excel ("D", "AA", ...).
*/
function routineEngineColToIndex($ref): int
{
if (is_int($ref)) {
return $ref;
}
$ref = trim((string)$ref);
if ($ref === '') {
return 0;
}
// Numerico puro -> indice diretto
if (ctype_digit($ref)) {
return (int)$ref;
}
// Lettere Excel -> indice zero-based (A=0, B=1, ..., Z=25, AA=26, ...)
$ref = strtoupper($ref);
$index = 0;
$len = strlen($ref);
for ($i = 0; $i < $len; $i++) {
$c = $ref[$i];
if ($c < 'A' || $c > 'Z') {
continue;
}
$index = $index * 26 + (ord($c) - ord('A') + 1);
}
return $index - 1;
}
/** Normalizza una lista di riferimenti colonna in indici zero-based. */
function routineEngineColsToIndexes(array $refs): array
{
return array_map('routineEngineColToIndex', $refs);
}
/**
* Carica gli step attivi di una routine dal DB, ordinati per step_order.
* Ritorna array di ['operation' => string, 'params' => array].
*/
function routineEngineLoadSteps(int $idroutine): array
{
// Riusa la connessione PDO del progetto.
// db-functions.php sta in .../class/ rispetto alla cartella routines/.
// Aggiusta il require se nel tuo albero il path differisce.
$dbFile = dirname(__DIR__) . '/class/db-functions.php';
if (!class_exists('DBHandlerSelect') && file_exists($dbFile)) {
require_once $dbFile;
}
if (!class_exists('DBHandlerSelect')) {
throw new Exception("Motore routine: classe DBHandlerSelect non trovata (path db-functions.php da verificare).");
}
$pdo = DBHandlerSelect::getInstance()->getConnection();
$stmt = $pdo->prepare(
"SELECT operation, params
FROM routine_step
WHERE idroutine = :id AND active = 1
ORDER BY step_order ASC, idstep ASC"
);
$stmt->execute([':id' => $idroutine]);
$rows = $stmt->fetchAll();
$steps = [];
foreach ($rows as $r) {
$params = [];
if (!empty($r['params'])) {
$decoded = json_decode($r['params'], true);
if (is_array($decoded)) {
$params = $decoded;
} else {
error_log("Motore routine: params JSON non valido per operazione {$r['operation']} (routine {$idroutine}).");
}
}
$steps[] = ['operation' => strtolower(trim($r['operation'])), 'params' => $params];
}
return $steps;
}
/* ------------------------------------------------------------------ *
* HANDLERS – ogni operazione modifica $excelData in place.
* Aggiungere una capacità nuova = aggiungere un handler qui, una volta.
* ------------------------------------------------------------------ */
/**
* merge: unisce N colonne sorgente in una destinazione.
* params: source_columns [], target_column, separator=" ", skip_empty=true
*/
function routineOpMerge(array &$excelData, array $params): void
{
$sources = routineEngineColsToIndexes($params['source_columns'] ?? []);
$target = routineEngineColToIndex($params['target_column'] ?? 0);
$sep = array_key_exists('separator', $params) ? (string)$params['separator'] : ' ';
$skip = $params['skip_empty'] ?? true;
foreach ($excelData as $rowIndex => &$row) {
if (!isset($row['data']) || !is_array($row['data'])) {
error_log("merge: struttura riga non valida all'indice {$rowIndex}.");
continue;
}
$parts = [];
foreach ($sources as $col) {
$val = trim((string)($row['data'][$col] ?? ''));
if ($skip && $val === '') {
continue;
}
$parts[] = $val;
}
$row['data'][$target] = implode($sep, $parts);
}
unset($row);
}
/**
* copy: copia una colonna sorgente in una destinazione.
* params: source_column, target_column
*/
function routineOpCopy(array &$excelData, array $params): void
{
$src = routineEngineColToIndex($params['source_column'] ?? 0);
$dst = routineEngineColToIndex($params['target_column'] ?? 0);
foreach ($excelData as &$row) {
if (!isset($row['data']) || !is_array($row['data'])) {
continue;
}
$row['data'][$dst] = $row['data'][$src] ?? '';
}
unset($row);
}
/**
* clear: svuota una o più colonne.
* params: columns [] (oppure column singola)
*/
function routineOpClear(array &$excelData, array $params): void
{
$cols = $params['columns'] ?? (isset($params['column']) ? [$params['column']] : []);
$cols = routineEngineColsToIndexes($cols);
foreach ($excelData as &$row) {
if (!isset($row['data']) || !is_array($row['data'])) {
continue;
}
foreach ($cols as $c) {
$row['data'][$c] = '';
}
}
unset($row);
}
/**
* trim: rimuove spazi (o caratteri indicati) da una o più colonne.
* params: columns [] (o column), chars (opzionale)
*/
function routineOpTrim(array &$excelData, array $params): void
{
$cols = $params['columns'] ?? (isset($params['column']) ? [$params['column']] : []);
$cols = routineEngineColsToIndexes($cols);
$chars = $params['chars'] ?? null;
foreach ($excelData as &$row) {
if (!isset($row['data']) || !is_array($row['data'])) {
continue;
}
foreach ($cols as $c) {
$v = (string)($row['data'][$c] ?? '');
$row['data'][$c] = $chars === null ? trim($v) : trim($v, $chars);
}
}
unset($row);
}
/**
* replace: sostituzione testo in una o più colonne.
* params: columns [] (o column), search, replace="", regex=false
*/
function routineOpReplace(array &$excelData, array $params): void
{
$cols = $params['columns'] ?? (isset($params['column']) ? [$params['column']] : []);
$cols = routineEngineColsToIndexes($cols);
$search = $params['search'] ?? '';
$replace = $params['replace'] ?? '';
$regex = $params['regex'] ?? false;
foreach ($excelData as &$row) {
if (!isset($row['data']) || !is_array($row['data'])) {
continue;
}
foreach ($cols as $c) {
$v = (string)($row['data'][$c] ?? '');
if ($regex) {
$out = @preg_replace($search, $replace, $v);
$row['data'][$c] = $out === null ? $v : $out;
} else {
$row['data'][$c] = str_replace($search, $replace, $v);
}
}
}
unset($row);
}
/** uppercase: maiuscolo su una o più colonne. params: columns [] (o column) */
function routineOpUppercase(array &$excelData, array $params): void
{
$cols = $params['columns'] ?? (isset($params['column']) ? [$params['column']] : []);
$cols = routineEngineColsToIndexes($cols);
foreach ($excelData as &$row) {
if (!isset($row['data']) || !is_array($row['data'])) {
continue;
}
foreach ($cols as $c) {
$row['data'][$c] = mb_strtoupper((string)($row['data'][$c] ?? ''), 'UTF-8');
}
}
unset($row);
}
/** lowercase: minuscolo su una o più colonne. params: columns [] (o column) */
function routineOpLowercase(array &$excelData, array $params): void
{
$cols = $params['columns'] ?? (isset($params['column']) ? [$params['column']] : []);
$cols = routineEngineColsToIndexes($cols);
foreach ($excelData as &$row) {
if (!isset($row['data']) || !is_array($row['data'])) {
continue;
}
foreach ($cols as $c) {
$row['data'][$c] = mb_strtolower((string)($row['data'][$c] ?? ''), 'UTF-8');
}
}
unset($row);
}
/**
* Entry point richiamato da apply_routine.php.
* Stessa firma delle routine legacy.
*/
function applyRoutine(&$excelData, $routineData = [])
{
$idroutine = isset($routineData['idroutine']) ? (int)$routineData['idroutine'] : 0;
if ($idroutine <= 0) {
throw new Exception("Motore routine: idroutine mancante in routineData.");
}
$steps = routineEngineLoadSteps($idroutine);
if (empty($steps)) {
error_log("Motore routine: nessuno step attivo per routine {$idroutine}.");
return;
}
// Dispatch table verbo -> handler
$handlers = [
'merge' => 'routineOpMerge',
'copy' => 'routineOpCopy',
'clear' => 'routineOpClear',
'trim' => 'routineOpTrim',
'replace' => 'routineOpReplace',
'uppercase' => 'routineOpUppercase',
'lowercase' => 'routineOpLowercase',
];
foreach ($steps as $i => $step) {
$op = $step['operation'];
if (!isset($handlers[$op])) {
error_log("Motore routine: operazione sconosciuta '{$op}' (routine {$idroutine}, step " . ($i + 1) . ") — saltata.");
continue;
}
$handlers[$op]($excelData, $step['params']);
error_log("Motore routine: applicata operazione '{$op}' (routine {$idroutine}, step " . ($i + 1) . ").");
}
error_log("Motore routine {$idroutine} completato (" . count($steps) . " step).");
}
}