Skip to content

Commit 01e2676

Browse files
committed
Feat(Core): Implement HL API
1 parent ee80f83 commit 01e2676

2 files changed

Lines changed: 223 additions & 90 deletions

File tree

hook.php

Lines changed: 125 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,126 @@ 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+
$itemtype = $schema['x-itemtype'];
462+
$schema_name = $itemtype . '_CustomFields';
463+
//Note PluginFieldsContainer::findContainer already checks permissions
464+
$container_id = PluginFieldsContainer::findContainer($schema['x-itemtype'], 'dom');
465+
if ($container_id !== null) {
466+
$it = $DB->request([
467+
'SELECT' => [
468+
'glpi_plugin_fields_fields.*',
469+
'glpi_plugin_fields_containers.name AS container_name',
470+
],
471+
'FROM' => 'glpi_plugin_fields_fields',
472+
'LEFT JOIN' => [
473+
'glpi_plugin_fields_containers' => [
474+
'ON' => [
475+
'glpi_plugin_fields_fields' => 'plugin_fields_containers_id',
476+
'glpi_plugin_fields_containers' => 'id'
477+
]
478+
]
479+
],
480+
'WHERE' => [
481+
'plugin_fields_containers_id' => $container_id,
482+
'glpi_plugin_fields_fields.is_active' => 1
483+
]
484+
]);
485+
if (count($it)) {
486+
foreach ($it as $field) {
487+
if (!isset($new_schemas[$schema_name])) {
488+
$new_schemas[$schema_name] = [
489+
'type' => Schema::TYPE_OBJECT,
490+
'properties' => []
491+
];
492+
}
493+
$type_format = $fn_fieldTypeToAPIType($field['type']);
494+
$table = strtolower("glpi_plugin_fields_{$schema['x-itemtype']}{$field['container_name']}s");
495+
$sql_field = $field['name'];
496+
if (str_starts_with($field['type'], 'dropdown')) {
497+
if (str_starts_with($field['type'], 'dropdown-')) {
498+
$dropdown_type = explode('-', $field['type'], 2)[1];
499+
} else {
500+
$dropdown_type = 'PluginFields' . ucfirst($field['name']) . 'Dropdown';
501+
}
502+
$is_tree = is_subclass_of($dropdown_type, CommonTreeDropdown::class);
503+
$dropdown_fk = $field['type'] === 'dropdown' ? $dropdown_type::getForeignKeyField() : $field['name'];
504+
$new_schemas[$schema_name]['properties'][$field['name']] = [
505+
'type' => Schema::TYPE_OBJECT,
506+
'x-join' => [
507+
'table' => $dropdown_type::getTable(), // This is the table with the desired values
508+
'field' => 'id',
509+
'fkey' => $dropdown_fk,
510+
'ref_join' => [
511+
'table' => $table,
512+
'fkey' => 'id',
513+
'field' => 'items_id',
514+
'condition' => [
515+
'itemtype' => $schema['x-itemtype'],
516+
]
517+
],
518+
],
519+
'properties' => [
520+
'id' => [
521+
'type' => Schema::TYPE_INTEGER,
522+
'format' => Schema::FORMAT_INTEGER_INT64,
523+
'x-readonly' => true,
524+
],
525+
'value' => [
526+
'type' => Schema::TYPE_STRING,
527+
'x-field' => $is_tree ? 'completename' : 'name',
528+
]
529+
]
530+
];
531+
} else {
532+
$new_schemas[$schema_name]['properties'][$field['name']] = [
533+
'type' => $type_format[0],
534+
'format' => $type_format[1],
535+
'x-join' => [
536+
// This is the table with the desired values
537+
'table' => $table,
538+
'fkey' => 'id',
539+
'field' => 'items_id',
540+
'condition' => [
541+
'itemtype' => $schema['x-itemtype'],
542+
]
543+
],
544+
'x-field' => $sql_field,
545+
'x-readonly' => true
546+
];
547+
}
548+
}
549+
if (isset($new_schemas[$schema_name]) && count($new_schemas[$schema_name]['properties']) > 0) {
550+
$schema['properties']['custom_fields'] = [
551+
'type' => Schema::TYPE_OBJECT,
552+
'x-full-schema' => $schema_name,
553+
'properties' => $new_schemas[$schema_name]['properties'],
554+
];
555+
}
556+
}
557+
}
558+
}
559+
$data['schemas'] = array_merge($data['schemas'], $new_schemas);
560+
return $data;
561+
}

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)