diff --git a/hook.php b/hook.php index 2835d88a..4c5ed68e 100644 --- a/hook.php +++ b/hook.php @@ -72,6 +72,7 @@ function plugin_fields_install() PluginFieldsStatusOverride::class, ]; + // First, install base data foreach ($classesToInstall as $class) { if (method_exists($class, 'installBaseData')) { diff --git a/inc/container.class.php b/inc/container.class.php index 9900305c..0f909524 100644 --- a/inc/container.class.php +++ b/inc/container.class.php @@ -28,8 +28,6 @@ * ------------------------------------------------------------------------- */ -use Glpi\Toolbox\Sanitizer; - class PluginFieldsContainer extends CommonDBTM { use Glpi\Features\Clonable; @@ -149,6 +147,72 @@ 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.', + ); + } + + $migration_genericobject_itemtype = []; + $result = $DB->request(['FROM' => 'glpi_plugin_genericobject_types']); + foreach ($result as $type) { + $migration_genericobject_itemtype[$type['itemtype']] = [ + 'genericobject_itemtype' => $type['itemtype'], + 'itemtype' => 'Glpi\CustomAsset\\' . $type['name'] . 'Asset', + 'genericobject_name' => $type['name'], + 'name' => $type['name'] . 'Asset', + ]; + } + + // Get containers with PluginGenericobject itemtype + $result = $DB->request([ + 'FROM' => $table, + 'WHERE' => [ + new Glpi\DBAL\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]) && + strpos($old_table, 'glpi_plugin_fields_plugingenericobject' . $migration_genericobject_itemtype[$itemtype]['genericobject_name']) !== false + ) { + $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; } @@ -487,7 +551,7 @@ public static function getSpecificValueToDisplay($field, $values, array $options return $types[$values[$field]]; case 'itemtypes': - $types = json_decode($values[$field]); + $types = PluginFieldsToolbox::decodeJSONItemtypes($values[$field]); $obj = ''; $count = count($types); $i = 1; @@ -650,7 +714,7 @@ public static function create($fields) return false; } - foreach (json_decode($fields['itemtypes']) as $itemtype) { + foreach (PluginFieldsToolbox::decodeJSONItemtypes($fields['itemtypes']) as $itemtype) { //install table for receive field $classname = self::getClassname($itemtype, $fields['name']); $classname::install(); @@ -660,7 +724,7 @@ public static function create($fields) public static function generateTemplate($fields) { $itemtypes = strlen($fields['itemtypes']) > 0 - ? json_decode($fields['itemtypes'], true) + ? PluginFieldsToolbox::decodeJSONItemtypes($fields['itemtypes'], true) : []; foreach ($itemtypes as $itemtype) { // prevent usage of plugin class if not loaded @@ -1102,7 +1166,7 @@ public static function getEntries($type = 'tab', $full = false): array continue; } - $jsonitemtypes = json_decode($item['itemtypes']); + $jsonitemtypes = PluginFieldsToolbox::decodeJSONItemtypes($item['itemtypes']); //show more info or not foreach ($jsonitemtypes as $v) { if ($full) { @@ -1142,8 +1206,10 @@ public static function getUsedItemtypes($type = 'all', $must_be_active = false) ]); foreach ($iterator as $data) { - $jsonitemtype = json_decode($data['itemtypes']); - $itemtypes = array_merge($itemtypes, $jsonitemtype); + $jsonitemtype = PluginFieldsToolbox::decodeJSONItemtypes($data['itemtypes']); + if (is_array($jsonitemtype)) { + $itemtypes = array_merge($itemtypes, $jsonitemtype); + } } return $itemtypes; @@ -1603,7 +1669,7 @@ public static function findContainer($itemtype, $type = 'tab', $subtype = '') } foreach ($itemtypes as $data) { - $dataitemtypes = json_decode($data['itemtypes']); + $dataitemtypes = PluginFieldsToolbox::decodeJSONItemtypes($data['itemtypes']); if (in_array($itemtype, $dataitemtypes) != false) { $id = $data['id']; } diff --git a/inc/toolbox.class.php b/inc/toolbox.class.php index 5e26de19..8f4e6da0 100644 --- a/inc/toolbox.class.php +++ b/inc/toolbox.class.php @@ -361,4 +361,14 @@ public static function getGlpiItemtypes(): array return $all_itemtypes; } + + public static function decodeJSONItemtypes(string $itemtypes, ?bool $associative = null) + { + $jsonitemtype = json_decode($itemtypes, $associative); + if ($jsonitemtype === null && json_last_error() !== JSON_ERROR_NONE) { + $fixed_json = str_replace('\\', '\\\\', $itemtypes); + $jsonitemtype = json_decode($fixed_json, $associative); + } + return $jsonitemtype; + } } diff --git a/templates/container.class.tpl b/templates/container.class.tpl index daa87766..5fb10fd2 100644 --- a/templates/container.class.tpl +++ b/templates/container.class.tpl @@ -51,7 +51,7 @@ class %%CLASSNAME%% extends PluginFieldsAbstractContainerInstance * This block ensures that the 'entities_id' field is created and populated if it * associated item type requires entity assignment */ - if (getItemForItemtype("%%ITEMTYPE%%")->isEntityAssign() && !$DB->fieldExists($table, 'entities_id')) { + if (getItemForItemtype('%%ITEMTYPE%%')->isEntityAssign() && !$DB->fieldExists($table, 'entities_id')) { $migration->addField($table, 'entities_id', 'fkey', ['after' => 'plugin_fields_containers_id']); $migration->addKey($table, 'entities_id'); $migration->executeMigration(); @@ -107,7 +107,7 @@ class %%CLASSNAME%% extends PluginFieldsAbstractContainerInstance * associated item type requires recursive assignment */ if ( - getItemForItemtype("%%ITEMTYPE%%")->maybeRecursive() + getItemForItemtype('%%ITEMTYPE%%')->maybeRecursive() && !$DB->fieldExists($table, 'is_recursive') && $DB->fieldExists($table, 'entities_id')) { $migration->addField($table, 'is_recursive', 'bool', ['after' => 'entities_id']);