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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Fixed

- Fix slow display and save of items with additional fields when the values tables are large

## [1.24.7] - 2026-10-28

### Fixed
Expand Down
10 changes: 5 additions & 5 deletions inc/container.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -1050,7 +1050,7 @@ public static function preItemPurge($item)
}

$fields = new $classname();
$fields->deleteByCriteria(['items_id' => $item->fields['id']], true);
$fields->deleteByCriteria(['itemtype' => $itemtype, 'items_id' => $item->fields['id']], true);
}
}

Expand Down Expand Up @@ -1767,7 +1767,7 @@ public function updateFieldsValues($data, $itemtype, $massiveaction = false)

$obj = new $classname();

$exist = $obj->getFromDBByCrit(['items_id' => $items_id]);
$exist = $obj->getFromDBByCrit(['itemtype' => $itemtype, 'items_id' => $items_id]);

// Convert "multiple" values into a JSON string
$multiple_fields_iterator = $DB->request([
Expand Down Expand Up @@ -1812,7 +1812,7 @@ public function updateFieldsValues($data, $itemtype, $massiveaction = false)
$obj = $dbu->getItemForItemtype($classname);

if ($obj !== false) {
if ($obj->getFromDBByCrit(['items_id' => $items_id]) === false) {
if ($obj->getFromDBByCrit(['itemtype' => $itemtype, 'items_id' => $items_id]) === false) {
// add fields data
$obj->add($data);
} else {
Expand Down Expand Up @@ -2266,7 +2266,7 @@ private static function getStoredValues(self $container, string $itemtype, int $
}

$values_obj = (new DbUtils())->getItemForItemtype(self::getClassname($itemtype, $container->fields['name']));
if ($values_obj === false || !$values_obj->getFromDBByCrit(['items_id' => $items_id])) {
if ($values_obj === false || !$values_obj->getFromDBByCrit(['itemtype' => $itemtype, 'items_id' => $items_id])) {
return [];
}

Expand Down Expand Up @@ -2659,7 +2659,7 @@ private static function checkContainerMandatory(CommonDBTM $item, PluginFieldsCo
$classname = self::getClassname($item::getType(), $loc_c->fields['name']);
$dbu = new DbUtils();
$obj = $dbu->getItemForItemtype($classname);
if ($obj !== false && $obj->getFromDBByCrit(['items_id' => $item->getID()])) {
if ($obj !== false && $obj->getFromDBByCrit(['itemtype' => $item::getType(), 'items_id' => $item->getID()])) {
$data += $obj->fields;
}
}
Expand Down
1 change: 1 addition & 0 deletions inc/field.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -1280,6 +1280,7 @@ public static function prepareHtmlFields(
if ($obj instanceof CommonDBTM) {
$found_values = $obj->find(
[
'itemtype' => $item::getType(),
'plugin_fields_containers_id' => $first_field['plugin_fields_containers_id'],
'items_id' => $item->getID(),
],
Expand Down
60 changes: 60 additions & 0 deletions tests/Units/ContainerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1108,4 +1108,64 @@ public function testRenameOversizedContainerFailsOnNameCollision(): void
$this->assertTrue($reloaded->getFromDB($container->getID()));
$this->assertSame(0, (int) $reloaded->fields['is_active']);
}

public function testValuesAreReadAndPurgedForTheirItemtypeOnly(): void
{
$container = $this->createFieldContainer([
'label' => 'Itemtype values ' . $this->getUniqueString(),
'type' => 'tab',
'itemtypes' => [Computer::class],
'is_active' => 1,
'entities_id' => 0,
'is_recursive' => 1,
]);

$field = $this->createField([
'label' => 'Itemtype text ' . str_replace('-', '', $this->getUniqueString()),
'type' => 'text',
PluginFieldsContainer::getForeignKeyField() => $container->getID(),
'ranking' => 1,
'is_active' => 1,
'is_readonly' => 0,
]);
$field_name = $field->fields['name'];

$computer = $this->createItem(Computer::class, [
'name' => 'Computer with itemtype values',
'entities_id' => 0,
]);
$this->assertTrue((new Computer())->update([
'id' => $computer->getID(),
$field_name => 'computer value',
]));

// Values row of another itemtype sharing the same items_id
/** @var DBmysql $DB */
global $DB;
$table = getTableForItemType(PluginFieldsContainer::getClassname(Computer::class, $container->fields['name']));
$DB->insert($table, [
'items_id' => $computer->getID(),
'itemtype' => Monitor::class,
PluginFieldsContainer::getForeignKeyField() => $container->getID(),
$field_name => 'monitor value',
]);

$this->assertTrue((new Computer())->update([
'id' => $computer->getID(),
$field_name => 'updated computer value',
]));

$values = [];
foreach ($DB->request(['FROM' => $table, 'WHERE' => ['items_id' => $computer->getID()]]) as $row) {
$values[$row['itemtype']] = $row[$field_name];
}

$this->assertSame([Computer::class => 'updated computer value', Monitor::class => 'monitor value'], $values);

$this->assertTrue((new Computer())->delete(['id' => $computer->getID()], true));

$rows = $DB->request(['FROM' => $table, 'WHERE' => ['items_id' => $computer->getID()]]);
$this->assertCount(1, $rows);
$this->assertSame(Monitor::class, $rows->current()['itemtype']);
}
}