Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Fix text area fields size and alignment
- Optimize container loading when there are a large number of entities
- Adding a verification in refreshContainer function for obj value which can be an empty string instead of an array
- Fix GenericObject type dropdowns migration
- Fix refreshContainer crash when a field is serialized both as a scalar and as an array
- Centralized label preparation and system name generation.

Expand Down
33 changes: 1 addition & 32 deletions inc/container.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,38 +163,7 @@ public static function installBaseData(Migration $migration, $version)

// 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) {
$customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'Asset';
if (str_ends_with((string) $type['itemtype'], 'Model')) {
$customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'AssetModel';
} elseif (str_ends_with((string) $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',
];
}
$migration_genericobject_itemtype = PluginFieldsMigration::getGenericObjectTypes();

// Get containers with PluginGenericobject itemtype
$result = $DB->request([
Expand Down
31 changes: 31 additions & 0 deletions inc/field.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,37 @@ public static function installBaseData(Migration $migration, $version)
$migration->addConfig(['stable_search_options' => 'yes'], 'plugin:fields');
}

// Update old genericobject_itemtype dropdown fields to customasset_itemtype dropdown fields
if ($DB->tableExists('glpi_plugin_genericobject_types')) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if ($DB->tableExists('glpi_plugin_genericobject_types')) {
// Update old genericobject_itemtype dropdown fields to customasset_itemtype dropdown fields
$has_genericobject_fields = $DB->tableExists('glpi_plugin_genericobject_types')
&& $DB->request([
'COUNT' => 'id',
'FROM' => self::getTable(),
'WHERE' => ['type' => ['LIKE', 'dropdown-PluginGenericobject%']],
])->current()['COUNT(id)'] > 0;
if ($has_genericobject_fields) {

getGenericObjectTypes() is called whenever glpi_plugin_genericobject_types exists, without first confirming that any fields actually reference GenericObject types. In container.class.php (line 162), the equivalent call is guarded by count($data) > 0, where $data queries for containers that contain a PluginGenericobject itemtype. If the table exists but GenericObject is uninstalled or at a version < 3.0.0, getGenericObjectTypes() throws RuntimeException (line 211-215 of migration.class.php). This exception is unhandled and will abort installBaseData() entirely, breaking the Fields plugin migration for any instance that has the leftover table but an outdated or absent GenericObject plugin.

// Get all types from PluginGenericobject
$migration_genericobject_itemtypes = PluginFieldsMigration::getGenericObjectTypes();

foreach ($migration_genericobject_itemtypes as $type) {
$itemtype = str_replace('\\\\', '\\', $type['itemtype']);
if (!class_exists($itemtype)) {
$migration->addDebugMessage(sprintf(
'The itemtype %s does not exist, please check if %s.class.php is present',
$itemtype,
$type['name'],
));
continue;
}

// If corresponding customasset_itemtype exists, update field type
$migration->addPostQuery(
$DB->buildUpdate(
self::getTable(),
[
'type' => 'dropdown-' . $itemtype,
],
[
'type' => ['LIKE', 'dropdown-' . $type['genericobject_itemtype']],
],
),
);
}
}

return true;
}

Expand Down
41 changes: 41 additions & 0 deletions inc/migration.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,45 @@ private static function getCustomFieldsInContainerTable(
fn(string $field) => !in_array($field, $basic_fields, true),
);
}

public static function getGenericObjectTypes(): array
{
/** @var DBmysql $DB */
global $DB;

// 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) {
$customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'Asset';
if (str_ends_with((string) $type['itemtype'], 'Model')) {
$customasset_classname = 'Glpi\\\\CustomAsset\\\\' . $type['name'] . 'AssetModel';
} elseif (str_ends_with((string) $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',
];
}

return $migration_genericobject_itemtype;
}
}