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 @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Fix administrators losing access to a block's configuration after setting a profile to "no access" on that block.
- Fix dependency conflict with GLPI core by no longer vendoring symfony/deprecation-contracts and symfony/polyfill-ctype.
- Fix default field values not being applied when fields are empty on creation
- Fix a field's default value not being applied to existing items and not being shown in search results for items with no dedicated row in the container table

## [1.24.5] - 2026-09-11

Expand Down
4 changes: 4 additions & 0 deletions inc/abstractcontainerinstance.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ public static function getSpecificValueToDisplay($field, $values, array $options
return ''; // Itemtype not exists (maybe a deactivated plugin)
}

if (empty($values[$field]) && !empty($field_specs->fields['default_value'])) {
$values[$field] = $field_specs->fields['default_value'];
}

if (empty($values[$field])) {
return ''; // Value not defined
}
Expand Down
44 changes: 44 additions & 0 deletions inc/container.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
*/

use Glpi\DBAL\QueryExpression;
use Glpi\DBAL\QueryFunction;
use Glpi\Features\Clonable;

class PluginFieldsContainer extends CommonDBTM
Expand Down Expand Up @@ -2197,6 +2198,7 @@ public static function getAddSearchOptions($itemtype, $containers_id = false)
'glpi_plugin_fields_fields.is_readonly',
'glpi_plugin_fields_fields.allowed_values',
'glpi_plugin_fields_fields.multiple',
'glpi_plugin_fields_fields.default_value',
'glpi_plugin_fields_containers.id AS container_id',
'glpi_plugin_fields_containers.name AS container_name',
'glpi_plugin_fields_containers.label AS container_label',
Expand Down Expand Up @@ -2304,6 +2306,21 @@ public static function getAddSearchOptions($itemtype, $containers_id = false)
$opt[$i]['datatype'] = 'string';
}

if (
(string) $data['default_value'] !== ''
&& !in_array($data['type'], ['dropdown', 'glpi_item'], true)
&& !preg_match('/^dropdown-.+$/i', (string) $data['type'])
) {
$default_expression = in_array($data['type'], ['date', 'datetime'], true) && $data['default_value'] === 'now'
? QueryFunction::now()
: new QueryExpression($DB::quoteValue($data['default_value']));

$opt[$i]['computation'] = QueryFunction::coalesce([
'TABLE.' . $data['field_name'],
$default_expression,
]);
}

$dropdown_matches = [];
if ($data['type'] === 'dropdown') {
$field_name = 'plugin_fields_' . $data['field_name'] . 'dropdowns_id';
Expand All @@ -2324,6 +2341,8 @@ public static function getAddSearchOptions($itemtype, $containers_id = false)
$opt[$i]['joinparams']['jointype'] = '';
$opt[$i]['joinparams']['beforejoin']['table'] = $tablename;
$opt[$i]['joinparams']['beforejoin']['joinparams']['jointype'] = 'itemtype_item';

self::addDropdownDefaultValueComputation($opt[$i], (string) $data['default_value']);
}
} elseif (
preg_match('/^dropdown-(?<class>.+)$/i', (string) $data['type'], $dropdown_matches)
Expand All @@ -2346,6 +2365,8 @@ public static function getAddSearchOptions($itemtype, $containers_id = false)
$opt[$i]['joinparams']['jointype'] = '';
$opt[$i]['joinparams']['beforejoin']['table'] = $tablename;
$opt[$i]['joinparams']['beforejoin']['joinparams']['jointype'] = 'itemtype_item';

self::addDropdownDefaultValueComputation($opt[$i], (string) $data['default_value']);
}
} elseif ($data['type'] === 'glpi_item') {
$itemtype_field = sprintf('itemtype_%s', $data['field_name']);
Expand Down Expand Up @@ -2377,6 +2398,29 @@ public static function getAddSearchOptions($itemtype, $containers_id = false)
return $opt;
}

/**
* Add a computation to the search option for a dropdown field to use a default value if the field is null.
*/
private static function addDropdownDefaultValueComputation(array &$searchoption, string $default_value): void
{
/** @var DBmysql $DB */
global $DB;

if ($default_value === '') {
return;
}

$default_name = Dropdown::getDropdownName($searchoption['table'], (int) $default_value);
if ($default_name === '') {
return;
}

$searchoption['computation'] = QueryFunction::coalesce([
'TABLE.' . $searchoption['field'],
new QueryExpression($DB::quoteValue($default_name)),
]);
}

/**
* Get subtypes for specified itemtype.
* Was previously retrieved using $item::defineTabs() but
Expand Down
61 changes: 61 additions & 0 deletions inc/field.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -1500,6 +1500,67 @@ public function post_addItem()
if (!isset($this->input['clone']) || !$this->input['clone']) {
PluginFieldsLabelTranslation::createForItem($this);
}

$this->applyDefaultValueToExistingItems();
}

/**
* Fill existing items with the default value of this field if it is set.
*/
private function applyDefaultValueToExistingItems(): void
{
/** @var DBmysql $DB */
global $DB;

if ($this->fields['type'] === 'header') {
return;
}

if ($this->fields['multiple']) {
$decoded = json_decode((string) $this->fields['default_value'], true);
if (!is_array($decoded) || $decoded === []) {
return;
}
} elseif ((string) $this->fields['default_value'] === '') {
return;
}

$value = self::getDefaultValue($this->fields);
if ($value === null) {
return;
}

$sql_fields = PluginFieldsMigration::getSQLFields(
$this->fields['name'],
$this->fields['type'],
['multiple' => (bool) $this->fields['multiple']],
);

if (count($sql_fields) !== 1) {
return;
}

$column = array_key_first($sql_fields);

$container = new PluginFieldsContainer();
if (!$container->getFromDB($this->fields['plugin_fields_containers_id'])) {
return;
}

foreach (PluginFieldsToolbox::decodeJSONItemtypes($container->fields['itemtypes']) as $itemtype) {
if (!class_exists($itemtype)) {
continue;
}

$classname = PluginFieldsContainer::getClassname($itemtype, $container->fields['name']);
$table = $classname::getTable();

if (!$DB->tableExists($table)) {
continue;
}

$DB->update($table, [$column => $value], [1]);
}
}

public function rawSearchOptions()
Expand Down
Loading
Loading