Skip to content

Commit 7f9e866

Browse files
authored
Fix dropdown custom field search options
1 parent daa142c commit 7f9e866

File tree

6 files changed

+141
-12
lines changed

6 files changed

+141
-12
lines changed

src/Glpi/Asset/CustomFieldType/DropdownType.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,21 +143,21 @@ public function getSearchOption(): ?array
143143
if (!$multiple) {
144144
$opt['joinparams']['condition'] = [
145145
new QueryExpression(
146-
'NEWTABLE.' . $DB->quoteName('id') . ' = ' . QueryFunction::jsonUnquote(
146+
'NEWTABLE.' . $DB::quoteName('id') . ' = ' . QueryFunction::jsonUnquote(
147147
expression: QueryFunction::jsonExtract([
148-
'glpi_assets_assets.custom_fields',
148+
'REFTABLE.custom_fields',
149149
new QueryExpression($DB::quoteValue('$."' . $this->custom_field->fields['id'] . '"')),
150150
])
151151
)
152152
),
153153
];
154154
} else {
155155
$opt['joinparams']['condition'] = [
156-
QueryFunction::jsonContains([
157-
'glpi_assets_assets.custom_fields',
158-
QueryFunction::cast('NEWTABLE.id', 'JSON'),
159-
new QueryExpression($DB::quoteValue('$."' . $this->custom_field->fields['id'] . '"')),
160-
]),
156+
QueryFunction::jsonContains(
157+
'REFTABLE.custom_fields',
158+
'NEWTABLE.id',
159+
'$."' . $this->custom_field->fields['id'] . '"'
160+
),
161161
];
162162
$opt['forcegroupby'] = true;
163163
$opt['usehaving'] = true;

src/Glpi/DBAL/QueryFunction.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
* @method static QueryExpression concat(array $params, ?string $alias = null) Build a 'CONCAT' SQL function call
5656
* @method static QueryExpression floor(string|QueryExpression $expression, ?string $alias = null) Build a 'FLOOR' function call
5757
* @method static QueryExpression greatest(array $params, ?string $alias = null) Build a 'GREATEST' function call
58-
* @method static QueryExpression jsonContains(array $params, ?string $alias = null) Build a 'JSON_CONTAINS' function call
5958
* @method static QueryExpression jsonExtract(array $params, ?string $alias = null) Build a 'JSON_EXTRACT' function call
6059
* @method static QueryExpression jsonUnquote(string|QueryExpression $expression, ?string $alias = null) Build a 'JSON_UNQUOTE' function call
6160
* @method static QueryExpression jsonRemove(array $params, ?string $alias = null) Build a 'JSON_REMOVE' function call
@@ -454,4 +453,24 @@ public static function concat_ws(string|QueryExpression $separator, array $param
454453
$separator = $separator instanceof QueryExpression ? $separator : $DB::quoteName($separator);
455454
return new QueryExpression('CONCAT_WS(' . $separator . ', ' . implode(', ', $params) . ')', $alias);
456455
}
456+
457+
public static function jsonContains(string|QueryExpression $target, string|QueryExpression $candidate, string $path, ?string $alias = null): QueryExpression
458+
{
459+
global $DB;
460+
461+
if (is_string($target)) {
462+
$target = new QueryExpression($DB::quoteName($target));
463+
}
464+
465+
if (is_string($candidate)) {
466+
$candidate = preg_match('/-MariaDB/', $DB->getVersion())
467+
? new QueryExpression($DB::quoteName($candidate))
468+
: QueryFunction::cast($candidate, 'JSON')
469+
;
470+
}
471+
472+
$path = new QueryExpression($DB::quoteValue($path));
473+
474+
return self::getExpression('JSON_CONTAINS', [$target, $candidate, $path], $alias);
475+
}
457476
}

tests/functional/Glpi/Api/HL/Controller/CustomAssetControllerTest.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,11 @@ public function testSearch(string $schema, array $filters, array $expected): voi
101101
public function testCRUD(): void
102102
{
103103
$this->api->autoTestCRUD('/Assets/Custom/Test01', [
104-
'custom_fields' => ['teststring' => 'Test String A'],
105-
], [
106-
'custom_fields' => ['teststring' => 'Test String A'],
104+
'custom_fields' => [
105+
'teststring' => 'Test String A',
106+
'customtagmulti' => null,
107+
'customtagsingle' => null,
108+
],
107109
]);
108110
}
109111

tests/functional/Glpi/Asset/CustomFieldDefinitionTest.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
use Glpi\Asset\CustomFieldType\URLType;
5050
use Glpi\DBAL\QueryExpression;
5151
use Glpi\DBAL\QueryFunction;
52+
use Glpi\Search\SearchEngine;
53+
use Glpi\Search\SearchOption;
5254
use PHPUnit\Framework\Attributes\DataProvider;
5355

5456
class CustomFieldDefinitionTest extends DbTestCase
@@ -631,4 +633,70 @@ public function testTypeUpdate(): void
631633
$this->assertFalse($updated);
632634
$this->hasSessionMessages(ERROR, ['The field type cannot be changed.']);
633635
}
636+
637+
public function testSearchDropdownField(): void
638+
{
639+
$this->login();
640+
641+
$opts = SearchOption::getOptionsForItemtype('Glpi\\CustomAsset\\Test01Asset');
642+
$single_dropdown_opt = null;
643+
$multiple_dropdown_opt = null;
644+
645+
foreach ($opts as $num => $opt) {
646+
if (!is_array($opt)) {
647+
continue;
648+
}
649+
if ($opt['name'] === 'Single Custom Tag') {
650+
$single_dropdown_opt = $num;
651+
} elseif ($opt['name'] === 'Multi Custom Tag') {
652+
$multiple_dropdown_opt = $num;
653+
}
654+
}
655+
$this->assertNotNull($single_dropdown_opt);
656+
$this->assertNotNull($multiple_dropdown_opt);
657+
658+
$this->createItem('Glpi\\CustomAsset\\Test01Asset', [
659+
'entities_id' => $this->getTestRootEntity(true),
660+
'name' => __FUNCTION__,
661+
'custom_customtagsingle' => getItemByTypeName('Glpi\\CustomDropdown\\CustomTagDropdown', 'Tag01', true),
662+
'custom_customtagmulti' => [
663+
getItemByTypeName('Glpi\\CustomDropdown\\CustomTagDropdown', 'Tag01', true),
664+
getItemByTypeName('Glpi\\CustomDropdown\\CustomTagDropdown', 'Tag02', true),
665+
],
666+
], ['custom_customtagsingle', 'custom_customtagmulti']);
667+
668+
$data = SearchEngine::getData('Glpi\\CustomAsset\\Test01Asset', [
669+
'criteria' => [
670+
[
671+
'link' => 'AND',
672+
'field' => 'name',
673+
'searchtype' => 'equals',
674+
'value' => __FUNCTION__,
675+
],
676+
[
677+
'link' => 'OR',
678+
'field' => $single_dropdown_opt,
679+
'searchtype' => 'contains',
680+
'value' => 'Tag',
681+
],
682+
[
683+
'link' => 'OR',
684+
'field' => $multiple_dropdown_opt,
685+
'searchtype' => 'contains',
686+
'value' => 'Tag',
687+
],
688+
],
689+
], [$single_dropdown_opt, $multiple_dropdown_opt]);
690+
691+
$this->assertCount(1, $data['data']['rows']);
692+
$row = reset($data['data']['rows'])['raw'];
693+
$this->assertEquals(
694+
'Tag01',
695+
$row['ITEM_Glpi\\CustomAsset\\Test01Asset_' . $single_dropdown_opt]
696+
);
697+
$this->assertEquals(
698+
'Tag01$#$1$$##$$Tag02$#$2',
699+
$row['ITEM_Glpi\\CustomAsset\\Test01Asset_' . $multiple_dropdown_opt]
700+
);
701+
}
634702
}

tests/functional/Glpi/Migration/GenericobjectPluginMigrationTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public function setUp(): void
9393
parent::setUp();
9494

9595
$DB->delete(AssetDefinition::getTable(), [new QueryExpression('true')]);
96+
$DB->delete(DropdownDefinition::getTable(), [new QueryExpression('true')]);
9697

9798
// Load it inside the test DB transaction to not have to clean it manually
9899
$queries = $DB->getQueriesFromFile(sprintf('%s/tests/fixtures/genericobject-migration/glpi-data.sql', GLPI_ROOT));

tests/src/autoload/functions.php

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,27 @@ function loadDataset()
721721
'profiles' => ['4' => ALLSTANDARDRIGHT | READ_ASSIGNED | UPDATE_ASSIGNED | READ_OWNED | UPDATE_OWNED],
722722
],
723723
],
724+
'Glpi\\Dropdown\\DropdownDefinition' => [
725+
[
726+
'system_name' => 'CustomTag',
727+
'icon' => 'ti ti-tag',
728+
'name' => 'Custom Tag',
729+
'is_active' => 1,
730+
'profiles' => ['4' => ALLSTANDARDRIGHT],
731+
],
732+
],
733+
'Glpi\\CustomDropdown\\CustomTagDropdown' => [
734+
[
735+
'id' => 1,
736+
'name' => 'Tag01',
737+
'entities_id' => '_test_root_entity',
738+
],
739+
[
740+
'id' => 2,
741+
'name' => 'Tag02',
742+
'entities_id' => '_test_root_entity',
743+
],
744+
],
724745
'Glpi\\CustomAsset\\Test02AssetType' => [
725746
[
726747
'name' => 'Test02Type01',
@@ -747,19 +768,37 @@ function loadDataset()
747768
'assets_assetdefinitions_id' => 'Test01',
748769
'label' => 'Test String',
749770
'type' => 'Glpi\\Asset\\CustomFieldType\\StringType',
750-
'field_options' => '{"full_width":"0","readonly":"0","required":"0"}',
771+
'field_options' => ["full_width" => "0", "readonly" => "0", "required" => "0"],
772+
],
773+
[
774+
'system_name' => 'customtagsingle',
775+
'assets_assetdefinitions_id' => 'Test01',
776+
'label' => 'Single Custom Tag',
777+
'type' => 'Glpi\\Asset\\CustomFieldType\\DropdownType',
778+
'itemtype' => 'Glpi\\CustomDropdown\\CustomTagDropdown',
779+
'field_options' => ["full_width" => "0", "readonly" => "0", "required" => "0"],
780+
],
781+
[
782+
'system_name' => 'customtagmulti',
783+
'assets_assetdefinitions_id' => 'Test01',
784+
'label' => 'Multi Custom Tag',
785+
'type' => 'Glpi\\Asset\\CustomFieldType\\DropdownType',
786+
'itemtype' => 'Glpi\\CustomDropdown\\CustomTagDropdown',
787+
'field_options' => ["full_width" => "0", "readonly" => "0", "required" => "0", "multiple" => "1"],
751788
],
752789
],
753790
'Glpi\\CustomAsset\\Test01Asset' => [
754791
[
755792
'name' => 'TestA',
756793
'entities_id' => '_test_root_entity',
757794
'custom_teststring' => 'Test String A',
795+
'custom_customtagsingle' => "1",
758796
],
759797
[
760798
'name' => 'TestB',
761799
'entities_id' => '_test_root_entity',
762800
'custom_teststring' => 'Test String B',
801+
'custom_customtagmulti' => [0 => "1", 1 => "2"],
763802
],
764803
],
765804
'Glpi\\CustomAsset\\Test02Asset' => [

0 commit comments

Comments
 (0)