diff --git a/cms/lib/classes/AcaiAPI.php b/cms/lib/classes/AcaiAPI.php index c301438..0f987cb 100644 --- a/cms/lib/classes/AcaiAPI.php +++ b/cms/lib/classes/AcaiAPI.php @@ -2180,13 +2180,58 @@ class AcaiAPI $childNums[(int) $row['parentNum']][] = $row['num']; } + $before = $byNum; + self::_rebuildCategoryBranch([ 'branchParent' => 0, 'records' => &$byNum, 'childNodes' => $childNums, ]); + // Solo las filas que cambian, y todas en UNA transaccion. Antes era un + // UPDATE por fila de la tabla entera en autocommit: en InnoDB cada uno + // es un commit a disco (8.168 filas = 1,9 s; en una transaccion, 0,7 s), + // y mover un nodo deja casi siempre intacta buena parte del arbol. + // START TRANSACTION por SQL y no con PDO: `Db` no expone la conexion, y + // anadirle un metodo aqui romperia las webs con un Db.php propio (el + // sync de web-base respeta los ficheros personalizados). En MyISAM es + // inocuo. + $changed = []; foreach ($byNum as $num => $cat) { + if (self::_categoryRowChanged($before[$num], $cat)) $changed[$num] = $cat; + } + if (!$changed) return; + + $db->execute("START TRANSACTION"); + try { + self::_writeCategoryRows($db, $fullTable, $changed); + $db->execute("COMMIT"); + } catch (\Throwable $e) { + $db->execute("ROLLBACK"); + throw $e; + } + } + + /** ¿Cambia alguno de los campos que recalcula el arbol? PDO devuelve + * tipos nativos y el recalculo mezcla int y string: se compara como + * texto, salvo NULL, que solo es igual a NULL. */ + private static function _categoryRowChanged(array $before, array $after) + { + foreach (['globalOrder', 'siblingOrder', 'depth', 'lineage', 'breadcrumb'] as $field) { + $a = isset($before[$field]) ? $before[$field] : null; + $b = isset($after[$field]) ? $after[$field] : null; + if ($a === null || $b === null) { + if ($a !== $b) return true; + } elseif ((string) $a !== (string) $b) { + return true; + } + } + return false; + } + + private static function _writeCategoryRows($db, $fullTable, array $rows) + { + foreach ($rows as $num => $cat) { $db->execute( "UPDATE `$fullTable` SET globalOrder = ?,