Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
70.97% covered (warning)
70.97%
22 / 31
60.00% covered (warning)
60.00%
3 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
AssessmentResultFileResponseResolver
70.97% covered (warning)
70.97%
22 / 31
60.00% covered (warning)
60.00%
3 / 5
18.80
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 resolve
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
6
 convertXmlTotAssessmentResul
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 resolveFileString
76.92% covered (warning)
76.92%
10 / 13
0.00% covered (danger)
0.00%
0 / 1
4.20
 encodeFile
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace oat\taoResultServer\models\AssessmentResultResolver;
4
5use GuzzleHttp\ClientInterface;
6use GuzzleHttp\Exception\GuzzleException;
7use InvalidArgumentException;
8use qtism\common\enums\BaseType;
9use qtism\data\results\AssessmentResult;
10use qtism\data\results\ItemResult;
11use qtism\data\results\ResultResponseVariable;
12use qtism\data\state\Value;
13use qtism\data\storage\xml\XmlResultDocument;
14use qtism\data\storage\xml\XmlStorageException;
15use tao_helpers_File;
16
17class AssessmentResultFileResponseResolver
18{
19    // phpcs:disable Generic.Files.LineLength
20    private const PATTERN = '/^(?<' . self::FILENAME_KEY . '>[^,]+).*download_url,(?<' . self::DOWNLOAD_URL_KEY . '>[^,]+)/';
21    // phpcs:enable Generic.Files.LineLength
22    private const FILENAME_KEY = 'fileName';
23    private const DOWNLOAD_URL_KEY = 'downloadUrl';
24
25    /** @var ClientInterface */
26    private $client;
27
28    public function __construct(ClientInterface $client)
29    {
30        $this->client = $client;
31    }
32
33    public function resolve(AssessmentResult $assessmentResult): AssessmentResult
34    {
35        /** @var ItemResult $itemResult */
36        foreach ($assessmentResult->getItemResults() as $itemResult) {
37            foreach ($itemResult->getItemVariables() as $itemVariable) {
38                if (
39                    $itemVariable instanceof ResultResponseVariable &&
40                    $itemVariable->getBaseType() === BaseType::FILE
41                ) {
42                    /** @var Value $value */
43                    foreach ($itemVariable->getCandidateResponse()->getValues() as $value) {
44                        $value->setValue($this->resolveFileString($value->getValue()));
45                    }
46                }
47            }
48        }
49
50        return $assessmentResult;
51    }
52
53    /**
54     * @throws XmlStorageException
55     */
56    private function convertXmlTotAssessmentResul(string $xml): AssessmentResult
57    {
58        $xmlResultDocument = new XmlResultDocument();
59        $xmlResultDocument->loadFromString($xml);
60        $assessmentResult = $xmlResultDocument->getDocumentComponent();
61        if (!$assessmentResult instanceof AssessmentResult) {
62            throw new InvalidArgumentException('Unsupported xml provided');
63        }
64        return $assessmentResult;
65    }
66
67    private function resolveFileString($value)
68    {
69        $matches = [];
70        preg_match(self::PATTERN, $value, $matches);
71        if (!array_key_exists(self::DOWNLOAD_URL_KEY, $matches)) {
72            return $value;
73        }
74        $downloadUrl = $matches[self::DOWNLOAD_URL_KEY];
75        $fileName = $matches[self::FILENAME_KEY];
76        $fileMimeType = tao_helpers_File::getMimeType($fileName);
77
78        try {
79            $response = $this->client->request('GET', $downloadUrl);
80            if ($response->getStatusCode() >= 400) {
81                return $fileName;
82            }
83        } catch (GuzzleException $e) {
84            return $fileName;
85        }
86
87        return $this->encodeFile($fileName, $fileMimeType, $response->getBody()->getContents());
88    }
89
90    private function encodeFile(string $fileName, string $mimeType, string $binaryContent): string
91    {
92        $packedUnsignedShortFileNameLen = pack('S', strlen($fileName));
93        $packedUnsignedShortMimeTypeLen = pack('S', strlen($mimeType));
94
95        return $packedUnsignedShortFileNameLen . $fileName . $packedUnsignedShortMimeTypeLen . $mimeType
96            . $binaryContent;
97    }
98}