Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.73% covered (success)
97.73%
43 / 44
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
OfflineQtiRunnerService
97.73% covered (success)
97.73%
43 / 44
80.00% covered (warning)
80.00%
4 / 5
12
0.00% covered (danger)
0.00%
0 / 1
 getItems
94.12% covered (success)
94.12%
16 / 17
0.00% covered (danger)
0.00%
0 / 1
4.00
 getItemData
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
3
 getItemIdentifiersFromTestMap
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getSubIdentifiersRecursively
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 getRunnerService
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; under version 2
7 * of the License (non-upgradable).
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 *
18 * Copyright (c) 2019 (original work) Open Assessment Technologies SA ;
19 */
20
21/**
22 * @author Péter Halász <peter@taotesting.com>
23 */
24
25namespace oat\taoQtiTest\models\runner;
26
27use oat\oatbox\service\ConfigurableService;
28use oat\taoQtiTest\models\runner\map\RunnerMap;
29
30/**
31 * Service class for the offline version of Qti Test Runner
32 */
33class OfflineQtiRunnerService extends ConfigurableService
34{
35    public const SERVICE_ID = 'taoQtiTest/OfflineQtiRunnerService';
36
37    /**
38     * Returns an array of items, containing also confident data, like branching and response processing rules
39     *
40     * @param RunnerServiceContext $serviceContext
41     * @return array
42     * @throws \common_Exception
43     * @throws \common_exception_Error
44     * @throws \common_exception_InconsistentData
45     * @throws \common_exception_InvalidArgumentType
46     */
47    public function getItems(RunnerServiceContext $serviceContext)
48    {
49        $this->getRunnerService()->assertQtiRunnerServiceContext($serviceContext);
50
51        $runnerService = $this->getRunnerService();
52        $testMap = $runnerService->getTestMap($serviceContext);
53        $items = [];
54
55        foreach ($this->getItemIdentifiersFromTestMap($testMap) as $itemIdentifier) {
56            $itemRef = $runnerService->getItemHref($serviceContext, $itemIdentifier);
57
58            $itemState = $runnerService->getItemState($serviceContext, $itemIdentifier);
59
60            if (is_array($itemState) && (0 === count($itemState))) {
61                $itemState = null;
62            }
63
64            /** @var QtiRunnerServiceContext $serviceContext */
65            $items[$itemIdentifier] = [
66                'baseUrl' => $runnerService->getItemPublicUrl($serviceContext, $itemRef),
67                'itemData' => $this->getItemData($serviceContext, $itemRef),
68                'itemState' => $itemState,
69                'itemIdentifier' => $itemIdentifier,
70                'portableElements' => $runnerService->getItemPortableElements($serviceContext, $itemRef),
71            ];
72        }
73
74        return $items;
75    }
76
77    /**
78     * Returns the itemData, extending with the variable elements
79     *
80     * @param RunnerServiceContext $context
81     * @param string $itemRef
82     * @return array
83     * @throws \common_exception_InvalidArgumentType
84     * @throws \common_Exception
85     */
86    private function getItemData(RunnerServiceContext $context, $itemRef)
87    {
88        $this->getRunnerService()->assertQtiRunnerServiceContext($context);
89
90        $itemData = $this->getRunnerService()->getItemData($context, $itemRef);
91        $itemDataVariable = $this->getRunnerService()->getItemVariableElementsData($context, $itemRef);
92        $responses = $itemData['data']['responses'];
93
94        foreach (array_keys($responses) as $responseId) {
95            if (array_key_exists($responseId, $itemDataVariable)) {
96                $itemData['data']['responses'][$responseId] = array_merge(...[
97                    $responses[$responseId],
98                    $itemDataVariable[$responseId],
99                ]);
100            }
101        }
102
103        return $itemData;
104    }
105
106    /**
107     * Returns the item identifiers
108     *
109     * @param array $testMap
110     * @return array
111     */
112    private function getItemIdentifiersFromTestMap($testMap)
113    {
114        return $this->getSubIdentifiersRecursively($testMap, [
115            RunnerMap::MAP_ATTRIBUTE_PARTS,
116            RunnerMap::MAP_ATTRIBUTE_SECTIONS,
117            RunnerMap::MAP_ATTRIBUTE_ITEMS,
118        ]);
119    }
120
121    /**
122     * Calls itself recursively to return identifiers from nested arrays
123     *
124     * @param $array
125     * @param $identifiers
126     * @return array
127     */
128    private function getSubIdentifiersRecursively($array, $identifiers)
129    {
130        $identifier = array_shift($identifiers);
131        if (count($identifiers) > 0) {
132            $result = [];
133
134            foreach ($array[$identifier] as $key => $value) {
135                $result[] = $this->getSubIdentifiersRecursively(
136                    $array[$identifier][$key],
137                    $identifiers
138                );
139            }
140
141            return array_merge(...$result);
142        }
143
144        return array_keys($array[$identifier]);
145    }
146
147    /**
148     * @return ConfigurableService|QtiRunnerService
149     */
150    private function getRunnerService()
151    {
152        return $this->getServiceLocator()->get(QtiRunnerService::SERVICE_ID);
153    }
154}