From 8594d2b383f788a1725d095f280cbd4883294ec2 Mon Sep 17 00:00:00 2001 From: regisoc Date: Wed, 1 Jul 2026 17:40:26 -0400 Subject: [PATCH 1/5] redcap client - automatic record_id field name registering for data export --- .../php/client/redcaphttpclient.class.inc | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/modules/redcap/php/client/redcaphttpclient.class.inc b/modules/redcap/php/client/redcaphttpclient.class.inc index 5ab3518730..3ab44b784b 100644 --- a/modules/redcap/php/client/redcaphttpclient.class.inc +++ b/modules/redcap/php/client/redcaphttpclient.class.inc @@ -67,6 +67,13 @@ class RedcapHttpClient */ private array $_cache; + /** + * The record_id field name. + * + * @var string|null + */ + private ?string $_record_id_field_name; + /** * Create a new REDCap Client for a specific REDCap instance and project. * @@ -85,6 +92,9 @@ class RedcapHttpClient $this->_token = $project_api_token; $this->_client = new Client($api_url); $this->_verbose = $verbose; + + // needs to be init + $this->_initRecordIDFieldName(); } /** @@ -817,7 +827,7 @@ class RedcapHttpClient 'forms' => $instrument_names, // The 'record_id' parameter adds both the 'record_id' and // 'redcap_event_name' fields to the REDCap records. - 'fields' => ['record_id'], + 'fields' => [$this->_record_id_field_name], 'events' => $unique_event_names, 'records' => $record_ids, 'rawOrLabel' => 'raw', @@ -830,4 +840,49 @@ class RedcapHttpClient // send request return json_decode($this->_sendRequest($data), true); } + + /** + * Initialize the record ID field name from REDCap project. + * By default, it is defined as "record_id", but it can vary and be user-defined. + * The current documentation rule seems to be: "the record ID field name is + * accessible as the first field of the first instrument." + * + * @return void + */ + private function _initRecordIDFieldName(): void + { + // get the REDCap instrument list + $instruments = $this->getInstruments(); + if (empty($instruments)) { + throw new \LorisException("[redcap] no instrument in the project"); + } + + // get the first instrument name + $first_instrument_name = $instruments[0]->name ?? null; + if ($first_instrument_name === null) { + throw new \LorisException("[redcap] cannot get the first instrument"); + } + + // get the dictionary of that instrument + $first_instrument_dictionary = $this->getDataDictionary( + [$first_instrument_name] + ); + if (empty($first_instrument_dictionary)) { + throw new \LorisException("[redcap] cannot get the first instrument dictionary"); + } + + // get the dictionary item of "Record ID" field + $record_id_field = array_values( + array_filter( + $first_instrument_dictionary, + fn($dict_item) => $dict_item->field_label === "Record ID" + ) + )[0] ?? null; + if ($record_id_field === null) { + throw new \LorisException("[redcap] no 'record_id' designed field on REDCap"); + } + + // init the record id field name + $this->_record_id_field_name = $record_id_field->field_name; + } } From af3a4517e94a45fc155af15cdffd805fc0a3f3cd Mon Sep 17 00:00:00 2001 From: regisoc Date: Wed, 1 Jul 2026 18:03:19 -0400 Subject: [PATCH 2/5] redcap - doc update - unique identifier field --- modules/redcap/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/modules/redcap/README.md b/modules/redcap/README.md index af8248af00..4f5eef1cdf 100644 --- a/modules/redcap/README.md +++ b/modules/redcap/README.md @@ -96,3 +96,16 @@ To be importable, the LORIS version of a REDCap instrument must: Because the REDCap module imports REDCap instruments as LORIS LINST instruments, REDCap instruments must adhere to a few naming requirements to be LINST-compatible: - A field name should not finish with `_status`. + +## REDCap unique idnetifier field + +REDCap defines a unique idnetifier field, sometimes called `Record ID` field. This field uniquely identifies records and can be renamed for each project. +As state in the current REDCap documentation, it is defined as _"the first field of the first instrument, and if not using a template, the default is 'Record ID' [record_id]"_. + +When exporting REDCap form data, it is also used to unlock a "hidden" feature, which adds several other metadata fields in the response, including: + +- `redcap_event_name`: REDCap unique event name. +- `redcap_repeat_instrument`: in the case of repeated instruments, the instrument name. +- `redcap_repeat_instance`: in the case of repeated instruments, the instrument repeated instance number. + +This is automatically set up during the client initialization and does not need any other set up. From 961936689a90dcf33ac0d04a8f47f46ba2058da6 Mon Sep 17 00:00:00 2001 From: regisoc Date: Wed, 1 Jul 2026 18:05:28 -0400 Subject: [PATCH 3/5] redcap - lint --- modules/redcap/php/client/redcaphttpclient.class.inc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/redcap/php/client/redcaphttpclient.class.inc b/modules/redcap/php/client/redcaphttpclient.class.inc index 3ab44b784b..bb58504f86 100644 --- a/modules/redcap/php/client/redcaphttpclient.class.inc +++ b/modules/redcap/php/client/redcaphttpclient.class.inc @@ -868,7 +868,9 @@ class RedcapHttpClient [$first_instrument_name] ); if (empty($first_instrument_dictionary)) { - throw new \LorisException("[redcap] cannot get the first instrument dictionary"); + throw new \LorisException( + "[redcap] cannot get the first instrument dictionary" + ); } // get the dictionary item of "Record ID" field @@ -879,7 +881,9 @@ class RedcapHttpClient ) )[0] ?? null; if ($record_id_field === null) { - throw new \LorisException("[redcap] no 'record_id' designed field on REDCap"); + throw new \LorisException( + "[redcap] no 'record_id' designed field on REDCap" + ); } // init the record id field name From 8c03fc94fc33e36bd91dc817ca1be844239f3de9 Mon Sep 17 00:00:00 2001 From: regisoc Date: Wed, 1 Jul 2026 18:18:21 -0400 Subject: [PATCH 4/5] redcap - doc update - unique identifier field --- modules/redcap/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/redcap/README.md b/modules/redcap/README.md index 4f5eef1cdf..aa7e744c81 100644 --- a/modules/redcap/README.md +++ b/modules/redcap/README.md @@ -99,8 +99,8 @@ Because the REDCap module imports REDCap instruments as LORIS LINST instruments, ## REDCap unique idnetifier field -REDCap defines a unique idnetifier field, sometimes called `Record ID` field. This field uniquely identifies records and can be renamed for each project. -As state in the current REDCap documentation, it is defined as _"the first field of the first instrument, and if not using a template, the default is 'Record ID' [record_id]"_. +REDCap defines a unique identifier field, sometimes called `Record ID` field. This field uniquely identifies a record and its name can be changed for each project. +As stated in the current REDCap documentation, it is defined as _"the first field of the first instrument, and if not using a template, the default is 'Record ID' [record_id]"_. When exporting REDCap form data, it is also used to unlock a "hidden" feature, which adds several other metadata fields in the response, including: From 6a8ae54c2ce9a881e611079c2ab7943b1546fdf8 Mon Sep 17 00:00:00 2001 From: regisoc Date: Thu, 2 Jul 2026 08:51:57 -0400 Subject: [PATCH 5/5] redcap - first field from first instrument as unqieu record id field --- .../redcap/php/client/redcaphttpclient.class.inc | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/modules/redcap/php/client/redcaphttpclient.class.inc b/modules/redcap/php/client/redcaphttpclient.class.inc index bb58504f86..9605e1935d 100644 --- a/modules/redcap/php/client/redcaphttpclient.class.inc +++ b/modules/redcap/php/client/redcaphttpclient.class.inc @@ -873,20 +873,15 @@ class RedcapHttpClient ); } - // get the dictionary item of "Record ID" field - $record_id_field = array_values( - array_filter( - $first_instrument_dictionary, - fn($dict_item) => $dict_item->field_label === "Record ID" - ) - )[0] ?? null; - if ($record_id_field === null) { + // get the first dictionary item + $first_field = $first_instrument_dictionary[0] ?? null; + if ($first_field === null) { throw new \LorisException( "[redcap] no 'record_id' designed field on REDCap" ); } // init the record id field name - $this->_record_id_field_name = $record_id_field->field_name; + $this->_record_id_field_name = $first_field->field_name; } }