Skip to content
Merged
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 @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Fixed

- Fix mandatory fields of a block hidden by its display conditions blocking the save of an item
- Fix fields values updates not applying the expected checks in some cases
- Fix ticket observers being able to edit and save additional fields they are not allowed to modify

## [1.25.0] - 2026-10-06
Expand Down
21 changes: 21 additions & 0 deletions inc/abstractcontainerinstance.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,27 @@ abstract class PluginFieldsAbstractContainerInstance extends CommonDBChild

public static string $items_id = 'items_id';

// Values are only written through the parent item or the container form
public static function canCreate(): bool
{
return false;
}

public static function canUpdate(): bool
{
return false;
}

public static function canDelete(): bool
{
return false;
}

public static function canPurge(): bool
{
return false;
}

/**
* This function relies on the static property `static::$plugins_forward_entity`,
* which should be populated using the following method (from setup):
Expand Down
47 changes: 47 additions & 0 deletions tests/Units/ContainerItemRightTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,53 @@ public function testShowDomContainerRendersReadOnlyFieldsWithoutUpdateRight(): v
);
}

public function testContainerValuesCanOnlyBeWrittenThroughContainer(): void
{
$this->login();
$entity_id = getItemByTypeName(Entity::class, '_test_root_entity', true);
$this->setEntity($entity_id, true);

$container = $this->createFieldContainer([
'label' => 'Tab container ' . $this->getUniqueString(),
'type' => 'tab',
'itemtypes' => [Computer::class],
'is_active' => 1,
'entities_id' => $entity_id,
'is_recursive' => 1,
]);
$field = $this->createField([
'label' => 'Tab field',
'type' => 'text',
PluginFieldsContainer::getForeignKeyField() => $container->getID(),
'ranking' => 1,
'is_active' => 1,
'is_readonly' => 0,
]);
$computer = $this->createItem(Computer::class, [
'name' => 'Computer ' . $this->getUniqueString(),
'entities_id' => $entity_id,
]);

$this->assertTrue($container->updateFieldsValues([
'plugin_fields_containers_id' => $container->getID(),
'itemtype' => Computer::class,
'items_id' => $computer->getID(),
$field->fields['name'] => 'value',
], Computer::class, false));

$classname = PluginFieldsContainer::getClassname(Computer::class, $container->fields['name']);
$values = new $classname();
$this->assertTrue($values->getFromDBByCrit(['items_id' => $computer->getID()]));
$this->assertSame('value', $values->fields[$field->fields['name']]);

$this->assertTrue($values->can($values->getID(), READ));
$this->assertFalse($values->can($values->getID(), UPDATE));
$this->assertFalse($values->can($values->getID(), DELETE));
$this->assertFalse($values->can($values->getID(), PURGE));
$input = ['itemtype' => Computer::class, 'items_id' => $computer->getID()];
$this->assertFalse($values->can(-1, CREATE, $input));
}

private function renderDomContainer(int $containers_id, Computer $computer): string
{
ob_start();
Expand Down
Loading