From a831ca91772a3366cadb4f3bb6da4bf8b6fd3612 Mon Sep 17 00:00:00 2001 From: Stanislas Kita Date: Mon, 20 Oct 2025 16:43:35 +0200 Subject: [PATCH 1/7] Fix(Core): fix migration error when container are related to Genericobject Model or Type --- inc/container.class.php | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/inc/container.class.php b/inc/container.class.php index 1d92c4c8..ac9ee312 100644 --- a/inc/container.class.php +++ b/inc/container.class.php @@ -168,11 +168,27 @@ public static function installBaseData(Migration $migration, $version) } $migration_genericobject_itemtype = []; - $result = $DB->request(['FROM' => 'glpi_plugin_genericobject_types']); + $result = $DB->request([ + 'FROM' => 'glpi_plugin_genericobject_types', + 'WHERE' => [ + new QueryExpression( + $table . ".itemtypes LIKE '%PluginGenericobject%'", + ), + ], + ]); foreach ($result as $type) { + $customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'Asset'; + if (str_contains($type['itemtype'], 'Model')) { + $customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'AssetModel'; + } + + if (str_contains($type['itemtype'], 'Model')) { + $customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'AssetType'; + } + $migration_genericobject_itemtype[$type['itemtype']] = [ 'genericobject_itemtype' => $type['itemtype'], - 'itemtype' => 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'Asset', + 'itemtype' => $customasset_classname, 'genericobject_name' => $type['name'], 'name' => $type['name'] . 'Asset', ]; From 5c66344e5b3db70ef03a7593944e184c8e5acb14 Mon Sep 17 00:00:00 2001 From: Stanislas Date: Tue, 21 Oct 2025 09:24:46 +0200 Subject: [PATCH 2/7] Update inc/container.class.php Co-authored-by: Romain B. <8530352+Rom1-B@users.noreply.github.com> --- inc/container.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/container.class.php b/inc/container.class.php index ac9ee312..0e97cbf1 100644 --- a/inc/container.class.php +++ b/inc/container.class.php @@ -178,7 +178,7 @@ public static function installBaseData(Migration $migration, $version) ]); foreach ($result as $type) { $customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'Asset'; - if (str_contains($type['itemtype'], 'Model')) { + if (str_ends_with($type['itemtype'], 'Model')) { $customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'AssetModel'; } From afe197a203f7aec8c26520abbc7b829f32525836 Mon Sep 17 00:00:00 2001 From: Stanislas Date: Tue, 21 Oct 2025 09:24:52 +0200 Subject: [PATCH 3/7] Update inc/container.class.php Co-authored-by: Romain B. <8530352+Rom1-B@users.noreply.github.com> --- inc/container.class.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/inc/container.class.php b/inc/container.class.php index 0e97cbf1..9a86a00f 100644 --- a/inc/container.class.php +++ b/inc/container.class.php @@ -180,9 +180,7 @@ public static function installBaseData(Migration $migration, $version) $customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'Asset'; if (str_ends_with($type['itemtype'], 'Model')) { $customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'AssetModel'; - } - - if (str_contains($type['itemtype'], 'Model')) { + } elseif (str_ends_with($type['itemtype'], 'Type')) { $customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'AssetType'; } From 7a7671a3c7ffca7a1c031e552bd54ba09d38a8eb Mon Sep 17 00:00:00 2001 From: Stanislas Kita Date: Thu, 23 Oct 2025 10:12:06 +0200 Subject: [PATCH 4/7] check before process --- inc/container.class.php | 156 ++++++++++++++++++++++------------------ 1 file changed, 87 insertions(+), 69 deletions(-) diff --git a/inc/container.class.php b/inc/container.class.php index 9a86a00f..702df75f 100644 --- a/inc/container.class.php +++ b/inc/container.class.php @@ -150,86 +150,104 @@ public static function installBaseData(Migration $migration, $version) $migration->migrationOneTable($table); } - // Get itemtypes from PluginGenericobject - if ($DB->tableExists('glpi_plugin_genericobject_types')) { - // Check GenericObject version - $genericobject_info = Plugin::getInfo('genericobject'); - if (version_compare($genericobject_info['version'] ?? '0', '3.0.0', '<')) { - throw new RuntimeException( - 'GenericObject plugin cannot be migrated. Please update it to the latest version.', - ); - } - // Check glpi_plugin_genericobject_types table - if (!$DB->fieldExists('glpi_plugin_genericobject_types', 'itemtype')) { - throw new RuntimeException( - 'Integrity error on the glpi_plugin_genericobject_types table from the GenericObject plugin.', - ); - } + // Get containers with PluginGenericobject itemtype + $data = $DB->request([ + 'FROM' => $table, + 'WHERE' => [ + new QueryExpression( + $table . ".itemtypes LIKE '%PluginGenericobject%'", + ), + ], + ]); - $migration_genericobject_itemtype = []; - $result = $DB->request([ - 'FROM' => 'glpi_plugin_genericobject_types', - 'WHERE' => [ - new QueryExpression( - $table . ".itemtypes LIKE '%PluginGenericobject%'", - ), - ], - ]); - foreach ($result as $type) { - $customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'Asset'; - if (str_ends_with($type['itemtype'], 'Model')) { - $customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'AssetModel'; - } elseif (str_ends_with($type['itemtype'], 'Type')) { - $customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'AssetType'; - } + if (count($data) > 0) { - $migration_genericobject_itemtype[$type['itemtype']] = [ - 'genericobject_itemtype' => $type['itemtype'], - 'itemtype' => $customasset_classname, - 'genericobject_name' => $type['name'], - 'name' => $type['name'] . 'Asset', - ]; - } + // Get itemtypes from PluginGenericobject + if ($DB->tableExists('glpi_plugin_genericobject_types')) { + // Check GenericObject version + $genericobject_info = Plugin::getInfo('genericobject'); + if (version_compare($genericobject_info['version'] ?? '0', '3.0.0', '<')) { + throw new RuntimeException( + 'GenericObject plugin cannot be migrated. Please update it to the latest version.', + ); + } - // Get containers with PluginGenericobject itemtype - $result = $DB->request([ - 'FROM' => $table, - 'WHERE' => [ - new QueryExpression( - $table . ".itemtypes LIKE '%PluginGenericobject%'", - ), - ], - ]); + // Check glpi_plugin_genericobject_types table + if (!$DB->fieldExists('glpi_plugin_genericobject_types', 'itemtype')) { + throw new RuntimeException( + 'Integrity error on the glpi_plugin_genericobject_types table from the GenericObject plugin.', + ); + } - $container_class = new self(); - foreach ($result as $container) { - self::generateTemplate($container); - foreach (PluginFieldsToolbox::decodeJSONItemtypes($container['itemtypes']) as $itemtype) { - $classname = self::getClassname($itemtype, $container["name"]); - $old_table = $classname::getTable(); - // Rename genericobject container table - if ( - $DB->tableExists($old_table) && - isset($migration_genericobject_itemtype[$itemtype]) && - str_contains($old_table, 'glpi_plugin_fields_plugingenericobject' . $migration_genericobject_itemtype[$itemtype]['genericobject_name']) - ) { - $new_table = str_replace('plugingenericobject' . $migration_genericobject_itemtype[$itemtype]['genericobject_name'], 'glpicustomasset' . strtolower($migration_genericobject_itemtype[$itemtype]['name']), $old_table); - $migration->renameTable($old_table, $new_table); + $migration_genericobject_itemtype = []; + $result = $DB->request([ + 'FROM' => 'glpi_plugin_genericobject_types', + 'WHERE' => [ + new QueryExpression( + $table . ".itemtypes LIKE '%PluginGenericobject%'", + ), + ], + ]); + + foreach ($result as $type) { + $customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'Asset'; + if (str_ends_with($type['itemtype'], 'Model')) { + $customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'AssetModel'; + } elseif (str_ends_with($type['itemtype'], 'Type')) { + $customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'AssetType'; } + + $migration_genericobject_itemtype[$type['itemtype']] = [ + 'genericobject_itemtype' => $type['itemtype'], + 'itemtype' => $customasset_classname, + 'genericobject_name' => $type['name'], + 'name' => $type['name'] . 'Asset', + ]; } - // Update old genericobject itemtypes in container - $map = array_column($migration_genericobject_itemtype, 'itemtype', 'genericobject_itemtype'); - $itemtypes = strtr($container['itemtypes'], $map); - $container_class->update( - [ - 'id' => $container['id'], - 'itemtypes' => $itemtypes, + + // Get containers with PluginGenericobject itemtype + $result = $DB->request([ + 'FROM' => $table, + 'WHERE' => [ + new QueryExpression( + $table . ".itemtypes LIKE '%PluginGenericobject%'", + ), ], - ); + ]); + + $container_class = new self(); + foreach ($result as $container) { + self::generateTemplate($container); + foreach (json_decode($container['itemtypes']) as $itemtype) { + $classname = self::getClassname($itemtype, $container["name"]); + $old_table = $classname::getTable(); + // Rename genericobject container table + if ( + $DB->tableExists($old_table) && + isset($migration_genericobject_itemtype[$itemtype]) && + str_contains($old_table, 'glpi_plugin_fields_plugingenericobject' . $migration_genericobject_itemtype[$itemtype]['genericobject_name']) + ) { + $new_table = str_replace('plugingenericobject' . $migration_genericobject_itemtype[$itemtype]['genericobject_name'], 'glpicustomasset' . strtolower($migration_genericobject_itemtype[$itemtype]['name']), $old_table); + $migration->renameTable($old_table, $new_table); + } + } + // Update old genericobject itemtypes in container + $map = array_column($migration_genericobject_itemtype, 'itemtype', 'genericobject_itemtype'); + $itemtypes = strtr($container['itemtypes'], $map); + $container_class->update( + [ + 'id' => $container['id'], + 'itemtypes' => $itemtypes, + ], + ); + } } } + + + return true; } From b6f450e3f3b7ff1f15908f5c9de44d885693e9cb Mon Sep 17 00:00:00 2001 From: Stanislas Kita Date: Thu, 23 Oct 2025 10:20:13 +0200 Subject: [PATCH 5/7] add more check and debug --- inc/container.class.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/inc/container.class.php b/inc/container.class.php index 702df75f..feed78fa 100644 --- a/inc/container.class.php +++ b/inc/container.class.php @@ -242,6 +242,10 @@ public static function installBaseData(Migration $migration, $version) ], ); } + } else { + throw new RuntimeException( + 'The Fields plugin is referencing a GenericObject class, but the corresponding table glpi_plugin_genericobject_types could not be found in the database.', + ); } } From 006dc0927ede4b0bc5568c1adc9e387eba1d4bfe Mon Sep 17 00:00:00 2001 From: Stanislas Kita Date: Thu, 23 Oct 2025 10:48:39 +0200 Subject: [PATCH 6/7] remove useless empty line --- inc/container.class.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/inc/container.class.php b/inc/container.class.php index feed78fa..a820feb4 100644 --- a/inc/container.class.php +++ b/inc/container.class.php @@ -248,10 +248,6 @@ public static function installBaseData(Migration $migration, $version) ); } } - - - - return true; } From 2b8edfbbf73f9f2fac299b82cf7fd723576d5639 Mon Sep 17 00:00:00 2001 From: Stanislas Kita Date: Fri, 24 Oct 2025 10:02:53 +0200 Subject: [PATCH 7/7] adapt CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31379994..95936364 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed +- Fix `GenericObject` Model and Type migration - Fix `json_decode` using class with namespace - Fix drag and drop - Increased the maximum length of the language column to support longer locale codes