Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb03ecd239 | ||
|
|
80b6541e30 | ||
|
|
775ae1c95d | ||
|
|
49522987dd |
@@ -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()
|
||||
@@ -33,6 +34,7 @@ class AcaiAPI
|
||||
// ── Cache flags (mirror CocoDB interface) ─────────────────────────
|
||||
public static $redis = null;
|
||||
public static $redis_expireTime = 0;
|
||||
public static $redis_no_disponible = false;
|
||||
public static $force_load_cache = false;
|
||||
public static $force_redis = false;
|
||||
public static $force_redis_module = false; // consumed by external cache layer
|
||||
@@ -646,14 +648,29 @@ class AcaiAPI
|
||||
/** Connect to Redis (idempotent). */
|
||||
static function initCache()
|
||||
{
|
||||
// Sin Redis (hosting propio sin el servicio o sin la extensión, o el
|
||||
// servicio caído) la web sigue SIN caché en vez de morir con un fatal:
|
||||
// cacheGet/cacheSet ya no hacen nada si no hay conexión. Se marca para
|
||||
// no reintentar en cada consulta de la misma petición.
|
||||
if (self::$redis_no_disponible) return;
|
||||
if (!class_exists('Redis')) {
|
||||
self::$redis_no_disponible = true;
|
||||
self::$redis = null;
|
||||
return;
|
||||
}
|
||||
|
||||
$redisHost = getenv('REDIS_HOST') ?: '127.0.0.1';
|
||||
$redisPort = (int)(getenv('REDIS_PORT') ?: 6379);
|
||||
|
||||
if (!self::$redis) {
|
||||
self::$redis = new Redis();
|
||||
self::$redis->connect($redisHost, $redisPort);
|
||||
} elseif (!self::$redis->isConnected()) {
|
||||
self::$redis->connect($redisHost, $redisPort);
|
||||
try {
|
||||
if (!self::$redis) self::$redis = new Redis();
|
||||
if (!self::$redis->isConnected() && !self::$redis->connect($redisHost, $redisPort)) {
|
||||
throw new RuntimeException("no se pudo conectar a $redisHost:$redisPort");
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
self::$redis_no_disponible = true;
|
||||
self::$redis = null;
|
||||
error_log('[cache] Redis no disponible, se sigue sin caché: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -855,7 +872,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 +901,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 +915,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).
|
||||
|
||||
@@ -14,6 +14,7 @@ class CocoDB
|
||||
public static $trackData = [];
|
||||
public static $redis = null;
|
||||
public static $redis_expireTime = 0;
|
||||
public static $redis_no_disponible = false;
|
||||
public static $force_load_cache = false;
|
||||
public static $force_redis = false;
|
||||
public static $force_redis_module = false;
|
||||
@@ -1176,14 +1177,29 @@ class CocoDB
|
||||
*/
|
||||
static function initCache()
|
||||
{
|
||||
// Sin Redis (hosting propio sin el servicio o sin la extensión, o el
|
||||
// servicio caído) la web sigue SIN caché en vez de morir con un fatal:
|
||||
// cacheGet/cacheSet ya no hacen nada si no hay conexión. Se marca para
|
||||
// no reintentar en cada consulta de la misma petición.
|
||||
if (self::$redis_no_disponible) return;
|
||||
if (!class_exists('Redis')) {
|
||||
self::$redis_no_disponible = true;
|
||||
self::$redis = null;
|
||||
return;
|
||||
}
|
||||
|
||||
$redisHost = getenv('REDIS_HOST') ?: '127.0.0.1';
|
||||
$redisPort = (int)(getenv('REDIS_PORT') ?: 6379);
|
||||
|
||||
if (!self::$redis) {
|
||||
self::$redis = new Redis();
|
||||
self::$redis->connect($redisHost, $redisPort);
|
||||
} else if (!self::$redis->isConnected()) {
|
||||
self::$redis->connect($redisHost, $redisPort);
|
||||
try {
|
||||
if (!self::$redis) self::$redis = new Redis();
|
||||
if (!self::$redis->isConnected() && !self::$redis->connect($redisHost, $redisPort)) {
|
||||
throw new RuntimeException("no se pudo conectar a $redisHost:$redisPort");
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
self::$redis_no_disponible = true;
|
||||
self::$redis = null;
|
||||
error_log('[cache] Redis no disponible, se sigue sin caché: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -7,8 +7,11 @@ $modulosCargados = array();
|
||||
$recursosCSS = array();
|
||||
// HASTA AUQI
|
||||
|
||||
if (!file_exists(__DIR__.'/'.CMS_FOLDER.'/uploads/webp/')) {
|
||||
mkdir(__DIR__.'/'.CMS_FOLDER.'/uploads/webp/');
|
||||
// Sin carrera: varias peticiones a la vez (el prerender de Astro las lanza en
|
||||
// paralelo) veian la carpeta sin crear y la segunda imprimia "mkdir(): File
|
||||
// exists" delante del JSON de action_ws, rompiendo el build de una web nueva.
|
||||
if (!is_dir(__DIR__.'/'.CMS_FOLDER.'/uploads/webp/')) {
|
||||
@mkdir(__DIR__.'/'.CMS_FOLDER.'/uploads/webp/', 0775, true);
|
||||
}
|
||||
global $configuracionTienda;
|
||||
$configuracionRecord = CocoDB::get("configuracion", "", null, 1);
|
||||
|
||||
Reference in New Issue
Block a user