diff --git a/cms/lib/classes/AcaiAPI.php b/cms/lib/classes/AcaiAPI.php index a8102fe..be26f53 100644 --- a/cms/lib/classes/AcaiAPI.php +++ b/cms/lib/classes/AcaiAPI.php @@ -15,6 +15,7 @@ class AcaiAPI private static $schemaCache = []; private static $queryCaches = []; // list/query relation results private static $requestGetCache = []; // unconditional per-request deduplication + private static $uploadsColumnsCache = []; // prefix => [columna => true] de {prefix}uploads // ── Public caches (mirror CocoDB interface) ─────────────────────── public static $getCaches = []; // in-memory result cache for get() @@ -855,7 +856,15 @@ class AcaiAPI $db = Db::getInstance(); $ph = implode(',', array_fill(0, count($nums), '?')); $fieldPh = implode(',', array_fill(0, count($uploadFields), '?')); + // width/height y las miniaturas (URL + dimensiones de los 4 huecos) van + // con cada foto: sin ellas el front no puede reservar el hueco (CLS) ni + // montar un srcset. Las rutas de disco (thumbFilePath*) no salen. Solo + // las que existan en la tabla: una web antigua sin alguna no se queda + // sin fotos por un SELECT roto. + $extra = self::existingUploadsColumns( + array_merge(['width', 'height'], self::uploadThumbColumns()), $prefix); $selectCols = 'num, `order`, tableName, fieldName, recordNum, filePath, urlPath, ' + . ($extra ? '`' . implode('`, `', $extra) . '`, ' : '') . 'info1, info2, info3, info4, info5, alt'; $params = array_merge(array_values($nums), [$tableName], array_values($uploadFields)); @@ -876,10 +885,12 @@ class AcaiAPI // Re-index for O(1) lookup $index = []; foreach ($uploads as $upload) { - if ($options['useAbsoluteUrls'] && isset($upload['urlPath']) - && strpos($upload['urlPath'], '/cms') === 0 - ) { - $upload['urlPath'] = 'https://' . $_SERVER['HTTP_HOST'] . $upload['urlPath']; + if ($options['useAbsoluteUrls']) { + foreach (array_merge(['urlPath'], self::uploadThumbUrlColumns()) as $col) { + if (isset($upload[$col]) && strpos($upload[$col], '/cms') === 0) { + $upload[$col] = 'https://' . $_SERVER['HTTP_HOST'] . $upload[$col]; + } + } } $field = $upload['fieldName']; $recNum = $upload['recordNum']; @@ -888,6 +899,47 @@ class AcaiAPI return $index; } + /** Sufijos de los 4 huecos de miniatura de `uploads` ('' = el primero). */ + const UPLOAD_THUMB_SLOTS = ['', '2', '3', '4']; + + /** Columnas de URL de las miniaturas: thumbUrlPath, thumbUrlPath2..4. */ + private static function uploadThumbUrlColumns() + { + return array_map(function ($n) { return "thumbUrlPath$n"; }, self::UPLOAD_THUMB_SLOTS); + } + + /** URL + ancho + alto de cada hueco de miniatura (sin rutas de disco). */ + private static function uploadThumbColumns() + { + $cols = []; + foreach (self::UPLOAD_THUMB_SLOTS as $n) { + array_push($cols, "thumbUrlPath$n", "thumbWidth$n", "thumbHeight$n"); + } + return $cols; + } + + /** + * De `$wanted`, las columnas que existen en `{$prefix}uploads` (en su + * orden). Un SHOW COLUMNS por prefijo y petición; si falla, ninguna: el + * SELECT vuelve a las columnas de siempre en vez de romperse. + */ + private static function existingUploadsColumns(array $wanted, $prefix) + { + if (!isset(self::$uploadsColumnsCache[$prefix])) { + $existing = []; + try { + foreach ((array) Db::getInstance()->executeS("SHOW COLUMNS FROM `{$prefix}uploads`") as $col) { + if (isset($col['Field'])) $existing[$col['Field']] = true; + } + } catch (Exception $e) { + error_log('[AcaiAPI] SHOW COLUMNS de ' . $prefix . 'uploads fallido: ' . $e->getMessage()); + } + self::$uploadsColumnsCache[$prefix] = $existing; + } + $cols = self::$uploadsColumnsCache[$prefix]; + return array_values(array_filter($wanted, function ($c) use ($cols) { return isset($cols[$c]); })); + } + /** * Injects upload arrays from the pre-built index into a single record row. * Each upload field becomes an array of upload objects (same as CocoDB).