Fix - Register CRUD hooks regardless of session state to support REST API#1154
Open
Fix - Register CRUD hooks regardless of session state to support REST API#1154
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Checklist before requesting a review
Please delete options that are not relevant.
Description
When GLPI is booted to serve a REST API request,
plugin_init_fields()runs before the API session is established (token auth happens after boot). Because thepre_item_update,pre_item_add,item_addandpre_item_purgehooks were registered inside theSession::getLoginUserID()guard, they were never registered for API calls. As a result, any PUT/POST toTicket(or any other Fields-enabled itemtype) silently ignored all plugin field values and only persisted native GLPI fields.A secondary issue in
PluginFieldsContainer::preItem()caused the same failure: theelse { return false; }branch on the profile rights check unconditionally rejected requests that had no active profile in session (cron, API token sessions).Fix
pre_item_update,pre_item_add,item_add,pre_item_purge),ITEM_TRANSFERandplugin_fields_register_plugin_types()outside the session guard. They are now registered as soon as the plugin is active, regardless of session state. Permission checks remain enforced inside the hook callbacks.return falseon missing session profile; the check is now skipped (not failed) when no profile is active in session.Tests
ContainerItemUpdateTest.php— 4 new tests :testCrudHooksRegisteredWithoutSession— asserts hooks are registered after a session-lessplugin_init_fields()calltestUpdateTicketInApiLikeContext— full API lifecycle simulation (boot without session → restore session → update ticket with plugin fields)testCreateTicketInApiLikeContext— same for ticket creationtestUpdateTicketWithExplicitCidInApiLikeContext— same with explicitc_id📄 Using the Fields Plugin via GLPI REST API
Table of Contents
Overview
The Fields plugin allows custom fields to be created and updated via the GLPI REST API. Custom fields are passed directly alongside native GLPI fields in the
inputobject of create (POST) and update (PUT) requests.Minimum versions required:
Prerequisites
Before making API calls, ensure:
Authentication
Init Session with credentials
Init Session with user token
Response
{ "session_token": "abc123def456" }Understanding Field Naming
When a field is created in the Fields plugin, its internal name (used as the API key) is derived from the label:
0→zero,1→one, etc.)fieldis appendedExamples:
Serial NumberserialnumberfieldCostcostfieldRef. 2024reftwozerotwofourfieldThe exact key to use depends on the field type — see Field Types Reference.
Container Types & Targeting
The Fields plugin supports three container types:
domdomcontainer per itemtype.tabtabcontainers are allowed.domtabAuto-detection (recommended for
domcontainers)When your itemtype has a single
domcontainer, the plugin automatically detects it. You don't need to specify any container identifier — just pass the field keys directly:{ "input": { "name": "My Ticket", "serialnumberfield": "SN-12345" } }Explicit container targeting with
c_idWhen targeting a
tabordomtabcontainer, or when multiple containers exist for the same itemtype, you must specify the container ID using thec_idkey:{ "input": { "c_id": 5, "serialnumberfield": "SN-12345" } }Updating multiple containers in one request
To update fields in multiple containers (e.g., one
dom+ onetab), you need separate API calls, one per container, each with its ownc_id.Creating Items with Custom Fields
Ticket with
domcontainer fields (auto-detect)Ticket with
tabcontainer fields (explicitc_id)Computer with custom fields
Response
{ "id": 42, "message": "" }Updating Items with Custom Fields
Update native + plugin fields together (dom, auto-detect)
Update only plugin fields (tab container, explicit
c_id)Update only native fields (plugin fields are NOT erased)
Bulk update
Field Types Reference
Text (
text)Single-line text field.
{ "input": { "id": 42, "mytextfield": "Hello World" } }Textarea (
textarea)Multi-line plain text field.
{ "input": { "id": 42, "descriptionfield": "Line 1\nLine 2\nLine 3" } }Rich Text (
richtext)HTML content field. Supports standard HTML tags.
{ "input": { "id": 42, "detailfield": "<p>This is <strong>rich</strong> text</p>" } }Number (
number)Numeric value stored as string. Commas are automatically converted to dots.
{ "input": { "id": 42, "costfield": "1500.50" } }URL (
url)URL field.
{ "input": { "id": 42, "documentationlinkfield": "https://wiki.example.com/kb/12345" } }Date (
date)Date in
YYYY-MM-DDformat.{ "input": { "id": 42, "deadlinefield": "2025-12-31" } }Date & Time (
datetime)Date and time in
YYYY-MM-DD HH:MM:SSformat.{ "input": { "id": 42, "scheduledatfield": "2025-06-15 14:30:00" } }Yes/No (
yesno)Boolean field.
0= No,1= Yes.{ "input": { "id": 42, "isurgentfield": 1 } }Custom Dropdown (
dropdown)A dropdown specific to the Fields plugin. The value is the ID of the dropdown entry in the plugin's own dropdown table (
glpi_plugin_fields_{fieldname}dropdowns).The API key uses the format:
plugin_fields_{fieldname}dropdowns_id{ "input": { "id": 42, "plugin_fields_criticalityfieldropdowns_id": 3 } }GLPI Dropdown (
dropdown-User,dropdown-Computer, etc.)A dropdown pointing to an existing GLPI itemtype. The value is the ID of the referenced item.
The API key uses the format:
{foreignkey}_{fieldname}Where
{foreignkey}is the standard GLPI foreign key for the itemtype:User→users_idComputer→computers_idLocation→locations_idGroup→groups_idSupplier→suppliers_idExample: dropdown-User field (label "Manager")
{ "input": { "id": 42, "users_id_managerfield": 5 } }Example: dropdown-Location field (label "Site")
{ "input": { "id": 42, "locations_id_sitefield": 12 } }Example: dropdown-Computer field (label "Related Asset")
{ "input": { "id": 42, "computers_id_relatedassetfield": 7 } }GLPI Item (
glpi_item)A polymorphic field that can reference any GLPI item. It requires two keys:
itemtype_{fieldname}— the class name of the referenced itemtypeitems_id_{fieldname}— the ID of the referenced item{ "input": { "id": 42, "itemtype_relateditemfield": "Computer", "items_id_relateditemfield": 15 } }Valid itemtype values include any
CommonDBTMsubclass:Computer,Monitor,NetworkEquipment,Printer,Phone,Software,User,Group, etc.Reading Custom Field Values
Via Search API (recommended)
Plugin fields are registered as search options on the parent itemtype. Use the
listSearchOptionsendpoint to discover them:Fields plugin options appear with IDs starting at 8100+. Example response excerpt:
{ "8101": { "name": "My Container > Serial Number", "table": "glpi_plugin_fields_ticketmycontainers", "field": "serialnumberfield", "datatype": "string", "nosearch": false } }Then use the
searchItemsendpoint withforcedisplayto retrieve those values:Via direct subitem query
The dynamically generated container class can be queried directly:
The class name follows the pattern:
PluginFields{Itemtype}{containername}(without trailing 's')Examples:
PluginFieldsTicketextrainfoPluginFieldsComputerassetdetailSearching Items by Custom Fields
Use the search option IDs discovered via
listSearchOptions:Multiple Values Fields
Fields marked as "multiple" accept arrays of IDs:
Custom dropdown (multiple)
{ "input": { "id": 42, "plugin_fields_tagfieldropdowns_id": [1, 3, 5] } }GLPI dropdown (multiple, e.g. dropdown-User)
{ "input": { "id": 42, "users_id_assignedtofield": [2, 7, 12] } }Values are stored as a JSON array internally. On update, by default, the new array replaces the existing values entirely.
Complete Workflow Examples
Example 1: Full lifecycle — Create and update a Ticket with all field types
Setup assumed:
dom, id5) onTicketwith fields:referencefield(text)costfield(number)isescalatedfield(yesno)duedatefield(date)plugin_fields_priorityfieldropdowns_id(custom dropdown)users_id_approverfield(dropdown-User)itemtype_relateditemfield+items_id_relateditemfield(glpi_item)Step 1: Init Session
Step 2: Create Ticket with all custom fields
Step 3: Update — escalate the ticket
Step 4: Kill Session
Example 2: Ticket with both
domandtabcontainer fieldsWhen your Ticket has:
domcontainer (id5): "Incident Details" withreferencefieldtabcontainer (id7): "SLA Info" withslatargetfieldYou need two separate update calls:
Example 3: Ticket with multiple
tabcontainersWhen your Ticket has several
tabcontainers, each must be updated with a separate API call using itsc_id:7): fieldsslatargetfield,slastatusfield9): fieldscostcenterfield,budgetcodefield12): fieldsvendorreffieldExample 4: Working with custom dropdown values
Step 1: List available dropdown values
Response:
[ { "id": 1, "name": "Low", "comment": "", "completename": "Low" }, { "id": 2, "name": "Medium", "comment": "", "completename": "Medium" }, { "id": 3, "name": "High", "comment": "", "completename": "High" }, { "id": 4, "name": "Critical", "comment": "", "completename": "Critical" } ]Step 2: Create a new dropdown value
Step 3: Use the value in a ticket
{ "input": { "id": 42, "plugin_fields_priorityfieldropdowns_id": 5 } }Troubleshooting
Custom fields are silently ignored
listSearchOptionsto verify the exact field namesError "field c_id is not allowed"
This error does not happen —
c_idis silently consumed by the plugin and removed from the input before GLPI processes it. If you see unexpected errors, verify the field names are spelled correctly.How to find the container ID (
c_id)Look for the
id,name,label,type, anditemtypesfields in the response.How to find the exact field key name
The
namecolumn in the response is the base key to use in API calls. For custom dropdown fields, prefix it asplugin_fields_{name}dropdowns_id.