3 namespace OpenEMR\Services
;
6 use OpenEMR\FHIR\R4\FHIRDomainResource\FHIRQuestionnaireResponse
;
7 use OpenEMR\FHIR\R4\FHIRElement\FHIRCanonical
;
8 use OpenEMR\FHIR\R4\FHIRElement\FHIRId
;
9 use OpenEMR\FHIR\R4\FHIRElement\FHIRReference
;
10 use OpenEMR\FHIR\R4\FHIRElement\FHIRString
;
11 use OpenEMR\FHIR\R4\PHPFHIRResponseParser
;
13 trait QuestionnaireTraits
19 * @return mixed|string|null
21 public function getInstrumentName($group, $item = null, $displayName = true)
23 if ($item && $this->isRepeating($item)) {
27 $name = $this->getText($group);
32 $linkId = $this->getLinkId($group) ??
'';
45 public function isRepeating($item): bool
47 if ($item->get_fhirElementName() !== 'Questionnaire.Item') {
50 $repeats = $item->getRepeats();
52 return $repeats && $repeats->getValue();
59 public function getValue($o)
64 while (method_exists((object)$o, 'getValue')) {
75 public function getText($item)
77 $text = $item->getText();
78 if ($text && method_exists($text, "getValue")) {
79 return $text->getValue();
87 public function getLinkId($item)
89 if (!in_array($item->get_fhirElementName(), ['Questionnaire.Item', 'QuestionnaireResponse.Item'])) {
93 return $item->getLinkId()->getValue();
101 public function getInstrumentPath($group, $item = null)
103 if ($item && $this->isRepeating($item)) {
107 return $this->getLinkId($group);
112 * @return mixed|void|null
114 public function getType($item)
116 if ($item->get_fhirElementName() === 'Questionnaire.Item') {
117 $type = $this->getValue($item->getType());
124 * @return array|object|string
127 public function parse($data, $autoLoad = false)
129 $parser = new PHPFHIRResponseParser($autoLoad);
130 if (is_array($data) ||
is_object($data)) {
131 // this is so the parser can set up necessary namespaces
132 $data = $this->jsonSerialize($data);
134 return $parser->parse($data);
138 * @param $fhirObjectOrArray
139 * @return false|string
142 public function jsonSerialize($fhirObjectOrArray): mixed
144 $a = $this->fhirObjectToArray($fhirObjectOrArray);
145 return json_encode($a, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
);
149 * @param $fhirObjectOrArray
150 * @return array|mixed
153 public function fhirObjectToArray($fhirObjectOrArray)
155 if (is_array($fhirObjectOrArray)) {
156 return $fhirObjectOrArray;
157 } elseif (is_object($fhirObjectOrArray)) {
158 $a = $fhirObjectOrArray->jsonSerialize();
159 $a = json_decode(json_encode($a), true);
160 $handle = function (&$a) use (&$handle) {
161 foreach ($a as $key => &$value) {
162 if (gettype($key) === 'string' && $key[0] === '_') {
166 if (is_array($value)) {
174 throw new Exception(xlt('A valid FHIR object or array must be specified.'));
180 * @return false|string
182 public function xmlSerialize($FHIRObject)
184 $dom = dom_import_simplexml($FHIRObject->xmlSerialize())->ownerDocument
;
185 $dom->formatOutput
= true;
187 return $dom->saveXML();
192 * @return array|mixed|string
195 public function getTypedValue($mixed)
198 $vs = $this->fhirObjectToArray($mixed);
199 foreach ($vs as $k => $v) {
201 $arr = $this->parseAnswer($a, true);
210 * @return array|mixed
212 private function parseAnswer($answer, $display = false)
215 $type = key($answer);
218 $obv['type'] = 'boolean';
219 $obv['display'] = $answer[$type];
222 $obv['type'] = 'decimal';
223 $obv['display'] = $answer[$type];
226 $obv['type'] = 'integer';
227 $obv['display'] = $answer[$type];
230 $obv['type'] = 'date';
231 $obv['display'] = $answer[$type];
233 case "valueDateTime":
234 $obv['type'] = 'datetime';
235 $obv['display'] = $answer[$type];
238 $obv['type'] = 'time';
239 $obv['display'] = $answer[$type];
242 $obv['type'] = 'string';
243 $obv['display'] = $answer[$type];
246 $obv['type'] = 'uri';
247 $obv['display'] = $answer[$type];
252 'system' => $answer[$type]['system'] ??
null,
253 'code' => $answer[$type]['code'],
254 'display' => $answer[$type]['display'],
257 case "valueQuantity":
258 $obv['type'] = 'quantity';
259 $obv['display'] = $answer[$type];
261 case "valueAttachment":
264 case "valueReference":
268 return $obv['display'];
275 * @return mixed|string
277 public function getFieldName($item)
279 $n = $item->getLinkId()->getValue();
287 public function formatFHIRDateTime($timestamp)
289 return $this->getDateTime($timestamp)->format('Y-m-d\TH:i:sP');
294 * @return mixed|DateTime
296 private function getDateTime($mixed)
298 $type = gettype($mixed);
300 if ($type === 'string') {
301 return new \
DateTime($mixed);
302 } elseif ($type === 'integer') {
303 $d = new \
DateTime();
304 $d->setTimestamp($mixed);
307 // Assume this is already a DateTime object.
316 public function formatFHIRTime($timestamp)
318 return $this->getDateTime($timestamp)->format('H:i:s');
325 public function formatOeDateTime($mixed)
327 return $this->getDateTime($mixed)->format('Y-m-d H:i');
334 public function formatOeDateTimeWithSeconds($mixed)
336 return $this->getDateTime($mixed)->format('Y-m-d H:i:s');
343 public function formatOeTime($mixed)
345 return $this->getDateTime($mixed)->format('H:i');
350 * @param bool $encode
351 * @return array|false|string
354 public function extractResponseMetaData($response, bool $encode = false)
356 if (is_string($response)) {
357 $response = json_decode($response, true);
359 $fhirObj = new FHIRQuestionnaireResponse($response);
360 $meta['id'] = $fhirObj->getId();
361 $meta['encounter'] = $fhirObj->getEncounter();
362 $meta['qid'] = $this->getValue($fhirObj->getQuestionnaire());
364 return $this->jsonSerialize($meta);
375 public function insertResponseMetaData($response, $meta, bool $encode = true)
377 if (is_string($response)) {
378 $response = json_decode($response, true);
380 if (is_string($meta)) {
381 $meta = json_decode($meta, true);
383 $fhirObj = new FHIRQuestionnaireResponse($response);
384 $fhirObj->setId(new FHIRId($meta['id']));
385 $encRef = new FHIRReference();
386 $encRef->setReference(new FHIRString($meta['encounter']));
387 $fhirObj->setEncounter($encRef);
388 $fhirObj->setQuestionnaire(new FHIRCanonical($meta['qid']));
390 return $this->jsonSerialize($fhirObj);
397 * @param bool $display
398 * @return array|mixed
400 private function setAnswer($answer, bool $display = false)
403 if (count($answer ??
[]) > 1) {
404 foreach ($answer as $ans) {
405 $a = $this->parseAnswer($ans, $display);
408 } elseif (!empty($answer[0])) {
409 $a = $this->parseAnswer($answer[0], $display);
412 $a = $this->parseAnswer($answer, $display);