Skip to content

Commit 1652f65

Browse files
committed
Feat(Core): Implement HL API
1 parent ee80f83 commit 1652f65

2 files changed

Lines changed: 228 additions & 90 deletions

File tree

hook.php

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
* -------------------------------------------------------------------------
2929
*/
3030

31+
use Glpi\Api\HL\Doc\Schema;
32+
3133
/**
3234
* Plugin install process
3335
*
@@ -434,3 +436,131 @@ function plugin_fields_addWhere($link, $nott, $itemtype, $ID, $val, $searchtype)
434436

435437
return null;
436438
}
439+
440+
function plugin_fields_redefine_api_schemas(array $data): array
441+
{
442+
global $DB;
443+
444+
$fn_fieldTypeToAPIType = static function (string $type): array {
445+
$type = explode('-', $type)[0];
446+
return match ($type) {
447+
'number' => [Schema::TYPE_NUMBER, Schema::FORMAT_NUMBER_FLOAT],
448+
'yesno' => [Schema::TYPE_BOOLEAN, Schema::FORMAT_BOOLEAN_BOOLEAN],
449+
'date' => [Schema::TYPE_STRING, Schema::FORMAT_STRING_DATE],
450+
'datetime' => [Schema::TYPE_STRING, Schema::FORMAT_STRING_DATE_TIME],
451+
default => [Schema::TYPE_STRING, Schema::FORMAT_STRING_STRING],
452+
};
453+
};
454+
455+
$new_schemas = [];
456+
457+
foreach ($data['schemas'] as &$schema) {
458+
if (!isset($schema['x-itemtype'])) {
459+
continue;
460+
}
461+
462+
$itemtype = $schema['x-itemtype'];
463+
$schema_name = $itemtype . '_CustomFields';
464+
//Note PluginFieldsContainer::findContainer already checks permissions
465+
$container_id = PluginFieldsContainer::findContainer($schema['x-itemtype'], 'dom');
466+
if ($container_id !== null) {
467+
$it = $DB->request([
468+
'SELECT' => [
469+
'glpi_plugin_fields_fields.*',
470+
'glpi_plugin_fields_containers.name AS container_name',
471+
],
472+
'FROM' => 'glpi_plugin_fields_fields',
473+
'LEFT JOIN' => [
474+
'glpi_plugin_fields_containers' => [
475+
'ON' => [
476+
'glpi_plugin_fields_fields' => 'plugin_fields_containers_id',
477+
'glpi_plugin_fields_containers' => 'id',
478+
],
479+
],
480+
],
481+
'WHERE' => [
482+
'plugin_fields_containers_id' => $container_id,
483+
'glpi_plugin_fields_fields.is_active' => 1,
484+
],
485+
]);
486+
if (count($it) > 0) {
487+
foreach ($it as $field) {
488+
if (!isset($new_schemas[$schema_name])) {
489+
$new_schemas[$schema_name] = [
490+
'type' => Schema::TYPE_OBJECT,
491+
'properties' => [],
492+
];
493+
}
494+
495+
$type_format = $fn_fieldTypeToAPIType($field['type']);
496+
$table = strtolower(sprintf('glpi_plugin_fields_%s%ss', $schema['x-itemtype'], $field['container_name']));
497+
$sql_field = $field['name'];
498+
if (str_starts_with((string) $field['type'], 'dropdown')) {
499+
if (str_starts_with((string) $field['type'], 'dropdown-')) {
500+
$dropdown_type = explode('-', (string) $field['type'], 2)[1];
501+
} else {
502+
$dropdown_type = 'PluginFields' . ucfirst((string) $field['name']) . 'Dropdown';
503+
}
504+
505+
$is_tree = is_subclass_of($dropdown_type, CommonTreeDropdown::class);
506+
$dropdown_fk = $field['type'] === 'dropdown' ? $dropdown_type::getForeignKeyField() : $field['name'];
507+
$new_schemas[$schema_name]['properties'][$field['name']] = [
508+
'type' => Schema::TYPE_OBJECT,
509+
'x-join' => [
510+
'table' => $dropdown_type::getTable(), // This is the table with the desired values
511+
'field' => 'id',
512+
'fkey' => $dropdown_fk,
513+
'ref_join' => [
514+
'table' => $table,
515+
'fkey' => 'id',
516+
'field' => 'items_id',
517+
'condition' => [
518+
'itemtype' => $schema['x-itemtype'],
519+
],
520+
],
521+
],
522+
'properties' => [
523+
'id' => [
524+
'type' => Schema::TYPE_INTEGER,
525+
'format' => Schema::FORMAT_INTEGER_INT64,
526+
'x-readonly' => true,
527+
],
528+
'value' => [
529+
'type' => Schema::TYPE_STRING,
530+
'x-field' => $is_tree ? 'completename' : 'name',
531+
],
532+
],
533+
];
534+
} else {
535+
$new_schemas[$schema_name]['properties'][$field['name']] = [
536+
'type' => $type_format[0],
537+
'format' => $type_format[1],
538+
'x-join' => [
539+
// This is the table with the desired values
540+
'table' => $table,
541+
'fkey' => 'id',
542+
'field' => 'items_id',
543+
'condition' => [
544+
'itemtype' => $schema['x-itemtype'],
545+
],
546+
],
547+
'x-field' => $sql_field,
548+
'x-readonly' => true,
549+
];
550+
}
551+
}
552+
553+
if (isset($new_schemas[$schema_name])) {
554+
$schema['properties']['custom_fields'] = [
555+
'type' => Schema::TYPE_OBJECT,
556+
'x-full-schema' => $schema_name,
557+
'properties' => $new_schemas[$schema_name]['properties'],
558+
];
559+
}
560+
}
561+
}
562+
}
563+
564+
$data['schemas'] = array_merge($data['schemas'], $new_schemas);
565+
return $data;
566+
}

setup.php

Lines changed: 98 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
use Glpi\Form\Destination\FormDestinationTicket;
7777
use Glpi\Form\Migration\TypesConversionMapper;
7878
use Glpi\Form\QuestionType\QuestionTypesManager;
79+
use Glpi\Plugin\Hooks;
7980
use Symfony\Component\Yaml\Yaml;
8081

8182
/**
@@ -99,116 +100,123 @@ function plugin_init_fields()
99100
$pluginfields_autoloader = new PluginFieldsAutoloader([PLUGINFIELDS_CLASS_PATH]);
100101
$pluginfields_autoloader->register();
101102

102-
if ((Session::getLoginUserID() || isCommandLine()) && Plugin::isPluginActive('fields')) {
103-
// Init hook about itemtype(s) for plugin fields
104-
if (!isset($PLUGIN_HOOKS['plugin_fields'])) {
105-
$PLUGIN_HOOKS['plugin_fields'] = [];
106-
}
103+
if (Plugin::isPluginActive('fields')) {
104+
// This API integration cannot be done inside a login check since the plugin is initialized before the Router handles authentication
105+
$PLUGIN_HOOKS[Hooks::REDEFINE_API_SCHEMAS]['fields'] = 'plugin_fields_redefine_api_schemas';
106+
107+
if ((Session::getLoginUserID() || isCommandLine())) {
107108

108-
// When a Category is changed during ticket creation
109-
if (
110-
$_POST !== []
111-
&& isset($_POST['_plugin_fields_type'])
112-
&& ($_SERVER['REQUEST_URI'] == Ticket::getFormURL())
113-
) {
114-
foreach ($_POST as $key => $value) {
115-
if (!is_array($value)) {
116-
$_SESSION['plugin']['fields']['values_sent'][$key] = $value;
109+
// Init hook about itemtype(s) for plugin fields
110+
if (!isset($PLUGIN_HOOKS['plugin_fields'])) {
111+
$PLUGIN_HOOKS['plugin_fields'] = [];
112+
}
113+
114+
// When a Category is changed during ticket creation
115+
if (
116+
$_POST !== []
117+
&& isset($_POST['_plugin_fields_type'])
118+
&& ($_SERVER['REQUEST_URI'] == Ticket::getFormURL())
119+
) {
120+
foreach ($_POST as $key => $value) {
121+
if (!is_array($value)) {
122+
$_SESSION['plugin']['fields']['values_sent'][$key] = $value;
123+
}
117124
}
118125
}
119-
}
120126

121-
if (Plugin::isPluginActive('fusioninventory')) {
122-
$PLUGIN_HOOKS['fusioninventory_inventory']['fields']
123-
= ['PluginFieldsInventory', 'updateInventory'];
124-
}
127+
if (Plugin::isPluginActive('fusioninventory')) {
128+
$PLUGIN_HOOKS['fusioninventory_inventory']['fields']
129+
= ['PluginFieldsInventory', 'updateInventory'];
130+
}
125131

126-
// complete rule engine
127-
$PLUGIN_HOOKS['use_rules']['fields'] = ['PluginFusioninventoryTaskpostactionRule'];
128-
$PLUGIN_HOOKS['rule_matched']['fields'] = 'plugin_fields_rule_matched';
132+
// complete rule engine
133+
$PLUGIN_HOOKS['use_rules']['fields'] = ['PluginFusioninventoryTaskpostactionRule'];
134+
$PLUGIN_HOOKS['rule_matched']['fields'] = 'plugin_fields_rule_matched';
129135

130-
if (isset($_SESSION['glpiactiveentities'])) {
131-
// add link in plugin page
132-
$PLUGIN_HOOKS['config_page']['fields'] = 'front/container.php';
136+
if (isset($_SESSION['glpiactiveentities'])) {
137+
// add link in plugin page
138+
$PLUGIN_HOOKS['config_page']['fields'] = 'front/container.php';
133139

134-
// add entry to configuration menu (only if user has read access to config)
135-
if (Session::haveRight('config', READ)) {
136-
$PLUGIN_HOOKS['menu_toadd']['fields'] = ['config' => PluginFieldsMenu::class];
137-
}
140+
// add entry to configuration menu (only if user has read access to config)
141+
if (Session::haveRight('config', READ)) {
142+
$PLUGIN_HOOKS['menu_toadd']['fields'] = ['config' => PluginFieldsMenu::class];
143+
}
138144

139-
// add tabs to itemtypes
140-
$itemtypes = array_unique(PluginFieldsContainer::getEntries());
141-
if ($itemtypes !== []) {
142-
Plugin::registerClass(
143-
'PluginFieldsContainer',
144-
['addtabon' => $itemtypes],
145-
);
146-
}
145+
// add tabs to itemtypes
146+
$itemtypes = array_unique(PluginFieldsContainer::getEntries());
147+
if ($itemtypes !== []) {
148+
Plugin::registerClass(
149+
'PluginFieldsContainer',
150+
['addtabon' => $itemtypes],
151+
);
152+
}
147153

148-
//include js and css
149-
$debug = (isset($_SESSION['glpi_use_mode'])
150-
&& $_SESSION['glpi_use_mode'] == Session::DEBUG_MODE);
151-
if (!$debug && file_exists(__DIR__ . '/public/css/fields.min.css')) {
152-
$PLUGIN_HOOKS['add_css']['fields'][] = 'css/fields.min.css';
153-
} else {
154-
$PLUGIN_HOOKS['add_css']['fields'][] = 'css/fields.scss';
155-
}
154+
//include js and css
155+
$debug = (isset($_SESSION['glpi_use_mode'])
156+
&& $_SESSION['glpi_use_mode'] == Session::DEBUG_MODE);
157+
if (!$debug && file_exists(__DIR__ . '/public/css/fields.min.css')) {
158+
$PLUGIN_HOOKS['add_css']['fields'][] = 'css/fields.min.css';
159+
} else {
160+
$PLUGIN_HOOKS['add_css']['fields'][] = 'css/fields.scss';
161+
}
156162

157-
// Add/delete profiles to automaticaly to container
158-
$PLUGIN_HOOKS['item_add']['fields']['Profile'] = ['PluginFieldsProfile', 'addNewProfile'];
159-
$PLUGIN_HOOKS['pre_item_purge']['fields']['Profile'] = ['PluginFieldsProfile', 'deleteProfile'];
163+
// Add/delete profiles to automaticaly to container
164+
$PLUGIN_HOOKS['item_add']['fields']['Profile'] = ['PluginFieldsProfile', 'addNewProfile'];
165+
$PLUGIN_HOOKS['pre_item_purge']['fields']['Profile'] = ['PluginFieldsProfile', 'deleteProfile'];
160166

161-
//load drag and drop javascript library on Package Interface
167+
//load drag and drop javascript library on Package Interface
162168

163-
if (
164-
plugin_fields_script_endswith('container.form.php')
165-
) {
166-
$PLUGIN_HOOKS['add_javascript']['fields'][] = 'lib/redips-drag-min.js';
167-
if (!$debug && file_exists(__DIR__ . '/public/js/drag-field-row.min.js')) {
168-
$PLUGIN_HOOKS['add_javascript']['fields'][] = 'js/drag-field-row.min.js';
169-
} else {
170-
$PLUGIN_HOOKS['add_javascript']['fields'][] = 'js/drag-field-row.js';
169+
if (
170+
plugin_fields_script_endswith('container.form.php')
171+
) {
172+
$PLUGIN_HOOKS['add_javascript']['fields'][] = 'lib/redips-drag-min.js';
173+
if (!$debug && file_exists(__DIR__ . '/public/js/drag-field-row.min.js')) {
174+
$PLUGIN_HOOKS['add_javascript']['fields'][] = 'js/drag-field-row.min.js';
175+
} else {
176+
$PLUGIN_HOOKS['add_javascript']['fields'][] = 'js/drag-field-row.js';
177+
}
171178
}
172179
}
173-
}
174180

175-
// Add Fields to Datainjection
176-
if (Plugin::isPluginActive('datainjection')) {
177-
$PLUGIN_HOOKS['plugin_datainjection_populate']['fields'] = 'plugin_datainjection_populate_fields';
178-
}
181+
// Add Fields to Datainjection
182+
if (Plugin::isPluginActive('datainjection')) {
183+
$PLUGIN_HOOKS['plugin_datainjection_populate']['fields'] = 'plugin_datainjection_populate_fields';
184+
}
179185

180-
//Retrieve dom container
181-
$itemtypes = PluginFieldsContainer::getUsedItemtypes();
182-
if ($itemtypes !== false) {
183-
foreach ($itemtypes as $itemtype) {
184-
$PLUGIN_HOOKS['pre_item_update']['fields'][$itemtype] = [
185-
'PluginFieldsContainer',
186-
'preItemUpdate',
187-
];
188-
$PLUGIN_HOOKS['pre_item_add']['fields'][$itemtype] = [
189-
'PluginFieldsContainer',
190-
'preItem',
191-
];
192-
$PLUGIN_HOOKS['item_add']['fields'][$itemtype] = [
193-
'PluginFieldsContainer',
194-
'postItemAdd',
195-
];
196-
$PLUGIN_HOOKS['pre_item_purge'] ['fields'][$itemtype] = [
197-
'PluginFieldsContainer',
198-
'preItemPurge',
199-
];
186+
//Retrieve dom container
187+
$itemtypes = PluginFieldsContainer::getUsedItemtypes();
188+
if ($itemtypes !== false) {
189+
foreach ($itemtypes as $itemtype) {
190+
$PLUGIN_HOOKS['pre_item_update']['fields'][$itemtype] = [
191+
'PluginFieldsContainer',
192+
'preItemUpdate',
193+
];
194+
$PLUGIN_HOOKS['pre_item_add']['fields'][$itemtype] = [
195+
'PluginFieldsContainer',
196+
'preItem',
197+
];
198+
$PLUGIN_HOOKS['item_add']['fields'][$itemtype] = [
199+
'PluginFieldsContainer',
200+
'postItemAdd',
201+
];
202+
$PLUGIN_HOOKS['pre_item_purge'] ['fields'][$itemtype] = [
203+
'PluginFieldsContainer',
204+
'preItemPurge',
205+
];
206+
}
200207
}
201-
}
202208

203-
// Display fields in any existing tab
204-
$PLUGIN_HOOKS['post_item_form']['fields'] = [
205-
'PluginFieldsField',
206-
'showForTab',
207-
];
209+
// Display fields in any existing tab
210+
$PLUGIN_HOOKS['post_item_form']['fields'] = [
211+
'PluginFieldsField',
212+
'showForTab',
213+
];
208214

209-
// Register fields question type
210-
plugin_fields_register_plugin_types();
215+
// Register fields question type
216+
plugin_fields_register_plugin_types();
217+
}
211218
}
219+
212220
}
213221

214222

0 commit comments

Comments
 (0)