*/ namespace oat\taoQtiTest\models\runner; use oat\oatbox\service\ConfigurableService; use oat\taoQtiTest\models\runner\map\RunnerMap; /** * Service class for the offline version of Qti Test Runner */ class OfflineQtiRunnerService extends ConfigurableService { const SERVICE_ID = 'taoQtiTest/OfflineQtiRunnerService'; /** * Returns an array of items, containing also confident data, like branching and response processing rules * * @param RunnerServiceContext $serviceContext * @return array * @throws \common_Exception * @throws \common_exception_Error * @throws \common_exception_InconsistentData * @throws \common_exception_InvalidArgumentType */ public function getItems(RunnerServiceContext $serviceContext) { $this->getRunnerService()->assertQtiRunnerServiceContext($serviceContext); $runnerService = $this->getRunnerService(); $testMap = $runnerService->getTestMap($serviceContext); $items = []; foreach ($this->getItemIdentifiersFromTestMap($testMap) as $itemIdentifier) { $itemRef = $runnerService->getItemHref($serviceContext, $itemIdentifier); $itemState = $runnerService->getItemState($serviceContext, $itemIdentifier); if (is_array($itemState) && (0 === count($itemState))) { $itemState = null; } /** @var QtiRunnerServiceContext $serviceContext */ $items[$itemIdentifier] = [ 'baseUrl' => $runnerService->getItemPublicUrl($serviceContext, $itemRef), 'itemData' => $this->getItemData($serviceContext, $itemRef), 'itemState' => $itemState, 'itemIdentifier' => $itemIdentifier, 'portableElements' => $runnerService->getItemPortableElements($serviceContext, $itemRef), ]; } return $items; } /** * Returns the itemData, extending with the variable elements * * @param RunnerServiceContext $context * @param string $itemRef * @return array * @throws \common_exception_InvalidArgumentType * @throws \common_Exception */ private function getItemData(RunnerServiceContext $context, $itemRef) { $this->getRunnerService()->assertQtiRunnerServiceContext($context); $itemData = $this->getRunnerService()->getItemData($context, $itemRef); $itemDataVariable = $this->getRunnerService()->getItemVariableElementsData($context, $itemRef); $responses = $itemData['data']['responses']; foreach (array_keys($responses) as $responseId) { if (array_key_exists($responseId, $itemDataVariable)) { $itemData['data']['responses'][$responseId] = array_merge(...[ $responses[$responseId], $itemDataVariable[$responseId], ]); } } return $itemData; } /** * Returns the item identifiers * * @param array $testMap * @return array */ private function getItemIdentifiersFromTestMap($testMap) { return $this->getSubIdentifiersRecursively($testMap, [ RunnerMap::MAP_ATTRIBUTE_PARTS, RunnerMap::MAP_ATTRIBUTE_SECTIONS, RunnerMap::MAP_ATTRIBUTE_ITEMS, ]); } /** * Calls itself recursively to return identifiers from nested arrays * * @param $array * @param $identifiers * @return array */ private function getSubIdentifiersRecursively($array, $identifiers) { $identifier = array_shift($identifiers); if (count($identifiers) > 0) { $result = []; foreach ($array[$identifier] as $key => $value) { $result[] = $this->getSubIdentifiersRecursively( $array[$identifier][$key], $identifiers ); } return array_merge(...$result); } return array_keys($array[$identifier]); } /** * @return ConfigurableService|QtiRunnerService */ private function getRunnerService() { return $this->getServiceLocator()->get(QtiRunnerService::SERVICE_ID); } }