221 lines
8.1 KiB
PHP
221 lines
8.1 KiB
PHP
|
<?php
|
||
|
|
||
|
/*
|
||
|
* This program is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU General Public License
|
||
|
* as published by the Free Software Foundation; under version 2
|
||
|
* of the License (non-upgradable).
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
|
*
|
||
|
* Copyright (c) 2017-2020 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
namespace oat\taoResultServer\models\classes;
|
||
|
|
||
|
use core_kernel_classes_Class;
|
||
|
use oat\taoDeliveryRdf\model\DeliveryAssemblyService;
|
||
|
use oat\taoResultServer\models\Formatter\ItemResponseCollectionNormalizer;
|
||
|
use oat\taoResultServer\models\Formatter\ItemResponseVariableSplitter;
|
||
|
use tao_models_classes_CrudService;
|
||
|
use taoResultServer_models_classes_ReadableResultStorage;
|
||
|
use taoResultServer_models_classes_ResponseVariable;
|
||
|
|
||
|
/**
|
||
|
* Crud services implements basic CRUD services, originally intended for REST controllers/ HTTP exception handlers
|
||
|
* Consequently the signatures and behaviors is closer to REST and throwing HTTP like exceptions
|
||
|
*/
|
||
|
class CrudResultsService extends tao_models_classes_CrudService
|
||
|
{
|
||
|
|
||
|
public const GROUP_BY_DELIVERY = 0;
|
||
|
public const GROUP_BY_TEST = 1;
|
||
|
public const GROUP_BY_ITEM = 2;
|
||
|
|
||
|
/** @var core_kernel_classes_Class */
|
||
|
protected $resultClass;
|
||
|
|
||
|
public function __construct()
|
||
|
{
|
||
|
parent::__construct();
|
||
|
$this->resultClass = new core_kernel_classes_Class(ResultService::DELIVERY_RESULT_CLASS_URI);
|
||
|
}
|
||
|
|
||
|
public function getRootClass()
|
||
|
{
|
||
|
return $this->resultClass;
|
||
|
}
|
||
|
|
||
|
public function get($uri, $groupBy = self::GROUP_BY_DELIVERY)
|
||
|
{
|
||
|
$resultService = $this->getServiceLocator()->get(ResultServerService::SERVICE_ID);
|
||
|
$implementation = $resultService->getResultStorage();
|
||
|
return $this->format($implementation, $uri);
|
||
|
}
|
||
|
|
||
|
public function format(
|
||
|
taoResultServer_models_classes_ReadableResultStorage $resultStorage,
|
||
|
$resultIdentifier,
|
||
|
int $groupBy = self::GROUP_BY_DELIVERY,
|
||
|
bool $fetchOnlyLastAttemptResult = false,
|
||
|
bool $splitByAttempt = false
|
||
|
): array {
|
||
|
$groupedData = [];
|
||
|
if ($groupBy === self::GROUP_BY_DELIVERY || $groupBy === self::GROUP_BY_ITEM) {
|
||
|
$calls = $resultStorage->getRelatedItemCallIds($resultIdentifier);
|
||
|
} else {
|
||
|
$calls = $resultStorage->getRelatedTestCallIds($resultIdentifier);
|
||
|
$fetchOnlyLastAttemptResult = false;
|
||
|
}
|
||
|
|
||
|
foreach ($calls as $callId) {
|
||
|
$results = $resultStorage->getVariables($callId);
|
||
|
$results = $this->getNormalizer()->normalize($results);
|
||
|
$lastData = [];
|
||
|
foreach ($results as $result) {
|
||
|
$result = array_pop($result);
|
||
|
if (isset($result->variable)) {
|
||
|
$resource = $this->getFormResource($result->variable);
|
||
|
if (!$fetchOnlyLastAttemptResult) {
|
||
|
$lastData[] = $resource;
|
||
|
} else {
|
||
|
$currentResTime = preg_replace('/0(\.\d*)\s(\d*)/', '$2$1', $resource['epoch']);
|
||
|
$previousResTime = preg_replace(
|
||
|
'/0(\.\d*)\s(\d*)/',
|
||
|
'$2$1',
|
||
|
$lastData[$resource['identifier']]['epoch'] ?? '0.0 0'
|
||
|
);
|
||
|
if ($currentResTime > $previousResTime) {
|
||
|
$lastData[$resource['identifier']] = $resource;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
$groupKey = $groupBy === self::GROUP_BY_DELIVERY ? $resultIdentifier : $callId;
|
||
|
$groupedData[$groupKey][] = $splitByAttempt ? $this->splitByAttempt($lastData) : $lastData;
|
||
|
}
|
||
|
foreach ($groupedData as $groupKey => $items) {
|
||
|
$returnData[$groupKey] = array_merge(...$items);
|
||
|
}
|
||
|
return $returnData ?? [];
|
||
|
}
|
||
|
|
||
|
public function getAll()
|
||
|
{
|
||
|
$resources = [];
|
||
|
$deliveryService = DeliveryAssemblyService::singleton();
|
||
|
foreach ($deliveryService->getAllAssemblies() as $assembly) {
|
||
|
// delivery uri
|
||
|
$delivery = $assembly->getUri();
|
||
|
|
||
|
$resultService = $this->getServiceLocator()->get(ResultServerService::SERVICE_ID);
|
||
|
$implementation = $resultService->getResultStorage();
|
||
|
|
||
|
// get delivery executions
|
||
|
|
||
|
//get all info
|
||
|
foreach ($implementation->getResultByDelivery([$delivery]) as $result) {
|
||
|
$result = array_merge($result, [RDFS_LABEL => $assembly->getLabel()]);
|
||
|
$properties = [];
|
||
|
foreach ($result as $key => $value) {
|
||
|
$property = [];
|
||
|
$type = 'resource';
|
||
|
switch ($key) {
|
||
|
case 'deliveryResultIdentifier':
|
||
|
$property['predicateUri'] = "http://www.tao.lu/Ontologies/TAOResult.rdf#Identifier";
|
||
|
break;
|
||
|
case 'testTakerIdentifier':
|
||
|
$property['predicateUri'] = "http://www.tao.lu/Ontologies/TAOResult.rdf#resultOfSubject";
|
||
|
break;
|
||
|
case 'deliveryIdentifier':
|
||
|
$property['predicateUri'] = "http://www.tao.lu/Ontologies/TAOResult.rdf#resultOfDelivery";
|
||
|
break;
|
||
|
default:
|
||
|
$property['predicateUri'] = $key;
|
||
|
$type = 'literal';
|
||
|
break;
|
||
|
}
|
||
|
$property['values'] = ['valueType' => $type, 'value' => $value];
|
||
|
|
||
|
$properties[] = $property;
|
||
|
}
|
||
|
$resources[] = [
|
||
|
'uri' => $result['deliveryResultIdentifier'],
|
||
|
'properties' => $properties
|
||
|
];
|
||
|
}
|
||
|
}
|
||
|
return $resources;
|
||
|
}
|
||
|
|
||
|
|
||
|
public function delete($resource)
|
||
|
{
|
||
|
throw new \common_exception_NoImplementation();
|
||
|
}
|
||
|
|
||
|
public function deleteAll()
|
||
|
{
|
||
|
throw new \common_exception_NoImplementation();
|
||
|
}
|
||
|
|
||
|
|
||
|
public function update($uri = null, $propertiesValues = [])
|
||
|
{
|
||
|
throw new \common_exception_NoImplementation();
|
||
|
}
|
||
|
|
||
|
public function isInScope($uri)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @author Patrick Plichart, patrick@taotesting.com
|
||
|
* return tao_models_classes_ClassService
|
||
|
*/
|
||
|
protected function getClassService()
|
||
|
{
|
||
|
// TODO: Implement getClassService() method.
|
||
|
}
|
||
|
|
||
|
private function getFormResource($variable): array
|
||
|
{
|
||
|
$resource['value'] = $variable->getValue();
|
||
|
$resource['identifier'] = $variable->getIdentifier();
|
||
|
if ($variable instanceof taoResultServer_models_classes_ResponseVariable) {
|
||
|
$resource['type'] = $this->getClass(QtiResultsService::CLASS_RESPONSE_VARIABLE);
|
||
|
} else {
|
||
|
$resource['type'] = $this->getClass(QtiResultsService::CLASS_OUTCOME_VARIABLE);
|
||
|
}
|
||
|
$resource['epoch'] = $variable->getEpoch();
|
||
|
$resource['cardinality'] = $variable->getCardinality();
|
||
|
$resource['basetype'] = $variable->getBaseType();
|
||
|
return $resource;
|
||
|
}
|
||
|
|
||
|
private function splitByAttempt(array $itemVariables): array
|
||
|
{
|
||
|
return $this->getItemVariableSplitter()->splitByAttempt($itemVariables);
|
||
|
}
|
||
|
|
||
|
private function getItemVariableSplitter(): ItemResponseVariableSplitter
|
||
|
{
|
||
|
return $this->getServiceLocator()->get(ItemResponseVariableSplitter::class);
|
||
|
}
|
||
|
|
||
|
private function getNormalizer(): ItemResponseCollectionNormalizer
|
||
|
{
|
||
|
return $this->getServiceLocator()->get(ItemResponseCollectionNormalizer::class);
|
||
|
}
|
||
|
}
|