Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
RemoteScaleListService
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 5
132
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 create
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
2
 isRemoteListEnabled
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
20
 hasRequiredRemoteListProperties
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 setupRemoteList
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
12
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) 2025 (original work) Open Assessment Technologies SA;
19 */
20
21declare(strict_types=1);
22
23namespace oat\taoQtiItem\model\QtiCreator\Scales;
24
25use core_kernel_classes_Class;
26use core_kernel_persistence_Exception;
27use oat\generis\model\data\Ontology;
28use oat\oatbox\log\LoggerService;
29use oat\tao\model\Lists\Business\Service\RemoteSourcedListOntology;
30use oat\taoBackOffice\model\lists\RemoteListService;
31use RuntimeException;
32use Throwable;
33
34class RemoteScaleListService
35{
36    public const SCALES_URI = 'http://www.tao.lu/Ontologies/TAO.rdf#Scales';
37    public const REMOTE_LIST_SCALE = 'REMOTE_LIST_SCALE';
38    private const DEFAULT_URI_PATH = '$[*].uri';
39    private const DEFAULT_LABEL_PATH = '$[*].label';
40    private Ontology $ontology;
41    private ?string $remoteListScaleUrl;
42    private RemoteListService $remoteListService;
43    private LoggerService $loggerService;
44
45    public function __construct(
46        Ontology $ontology,
47        RemoteListService $remoteListService,
48        LoggerService $loggerService,
49        ?string $remoteListScaleUrl = ''
50    ) {
51        $this->ontology = $ontology;
52        $this->remoteListScaleUrl = $remoteListScaleUrl;
53        $this->remoteListService = $remoteListService;
54        $this->loggerService = $loggerService;
55    }
56
57    public function create(string $labelPath, string $uriPath): void
58    {
59        $remoteListClass = $this->ontology->getClass(self::SCALES_URI);
60        $remoteListClass->setPropertyValue(
61            $remoteListClass->getProperty(RemoteSourcedListOntology::PROPERTY_LIST_TYPE),
62            RemoteSourcedListOntology::LIST_TYPE_REMOTE
63        );
64
65        $remoteListClass->setPropertyValue(
66            $remoteListClass->getProperty(RemoteSourcedListOntology::PROPERTY_SOURCE_URI),
67            $this->remoteListScaleUrl
68        );
69
70        $remoteListClass->setPropertyValue(
71            $remoteListClass->getProperty(RemoteSourcedListOntology::PROPERTY_ITEM_LABEL_PATH),
72            $labelPath
73        );
74
75        $remoteListClass->setPropertyValue(
76            $remoteListClass->getProperty(RemoteSourcedListOntology::PROPERTY_ITEM_URI_PATH),
77            $uriPath
78        );
79    }
80
81    /**
82     * Check if the remote list functionality is enabled for scales
83     *
84     * @return bool True if remote list functionality is enabled and properly configured
85     */
86    public function isRemoteListEnabled(): bool
87    {
88        if (empty($this->remoteListScaleUrl)) {
89            $this->loggerService->debug('Remote list scale URL is not configured');
90            return false;
91        }
92
93        try {
94            $scalesList = $this->ontology->getClass(self::SCALES_URI);
95
96            $hasRequiredProperties = $this->hasRequiredRemoteListProperties($scalesList);
97
98            if (!$hasRequiredProperties) {
99                return $this->setupRemoteList($scalesList);
100            }
101
102            return true;
103        } catch (Throwable $e) {
104            $this->loggerService->error(
105                sprintf('Error checking remote list enabled status: %s', $e->getMessage()),
106                ['exception' => $e]
107            );
108            return false;
109        }
110    }
111
112    /**
113     * Check if the scales list has the required remote list properties
114     *
115     * @param core_kernel_classes_Class $scalesList The scales list class
116     * @return bool True if all required properties exist
117     * @throws core_kernel_persistence_Exception
118     */
119    private function hasRequiredRemoteListProperties(core_kernel_classes_Class $scalesList): bool
120    {
121        $remoteListProperty = $scalesList->getOnePropertyValue(
122            $scalesList->getProperty(RemoteSourcedListOntology::LIST_TYPE_REMOTE)
123        );
124
125        $remoteScaleListUri = $scalesList->getOnePropertyValue(
126            $scalesList->getProperty(RemoteSourcedListOntology::PROPERTY_DEPENDENCY_ITEM_URI_PATH)
127        );
128
129        return $remoteListProperty !== null && $remoteScaleListUri !== null;
130    }
131
132    /**
133     * Set up the remote list with default values
134     *
135     * @param core_kernel_classes_Class $scalesList The scales list class
136     * @return bool True if setup was successful
137     */
138    private function setupRemoteList(core_kernel_classes_Class $scalesList): bool
139    {
140        try {
141            $this->create(self::DEFAULT_LABEL_PATH, self::DEFAULT_URI_PATH);
142
143            $this->remoteListService->sync($scalesList, false);
144
145            $this->loggerService->info('Successfully set up remote list for scales');
146            return true;
147        } catch (RuntimeException $e) {
148            $this->loggerService->warning(
149                sprintf('Could not sync remote list scale: %s', $e->getMessage())
150            );
151            return false;
152        } catch (Throwable $e) {
153            $this->loggerService->error(
154                sprintf('Unexpected error setting up remote list: %s', $e->getMessage()),
155                ['exception' => $e]
156            );
157            return false;
158        }
159    }
160}