tao-test/app/taoTests/models/classes/class.TestsService.php

344 lines
12 KiB
PHP
Raw Normal View History

2022-08-29 20:14:13 +02:00
<?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) 2002-2008 (original work) Public Research Centre Henri Tudor & University of Luxembourg (under the project TAO & TAO2);
* 2008-2010 (update and modification) Deutsche Institut für Internationale Pädagogische Forschung (under the project TAO-TRANSFER);
* 2009-2012 (update and modification) Public Research Centre Henri Tudor (under the project TAO-SUSTAIN & TAO-DEV);
* 2012-2021 (original work) Open Assessment Technologies SA;
*/
use oat\generis\model\OntologyRdf;
use oat\tao\model\TaoOntology;
use oat\taoTests\models\event\TestCreatedEvent;
use oat\taoTests\models\event\TestDuplicatedEvent;
use oat\taoTests\models\event\TestRemovedEvent;
use oat\generis\model\fileReference\FileReferenceSerializer;
use oat\tao\model\service\ServiceFileStorage;
use oat\taoTests\models\TestModel;
use oat\taoTests\models\MissingTestmodelException;
use oat\tao\model\OntologyClassService;
/**
* Service methods to manage the Tests business models using the RDF API.
*
* @author Joel Bout, <joel.bout@tudor.lu>
*/
class taoTests_models_classes_TestsService extends OntologyClassService
{
public const CLASS_TEST_MODEL = 'http://www.tao.lu/Ontologies/TAOTest.rdf#TestModel';
public const PROPERTY_TEST_MODEL_IMPLEMENTATION = 'http://www.tao.lu/Ontologies/TAOTest.rdf#TestModelImplementation';
public const PROPERTY_TEST_TESTMODEL = 'http://www.tao.lu/Ontologies/TAOTest.rdf#TestTestModel';
/** @deprecated self::PROPERTY_TEST_CONTENT should be used */
public const TEST_TESTCONTENT_PROP = 'http://www.tao.lu/Ontologies/TAOTest.rdf#TestContent';
public const PROPERTY_TEST_CONTENT = 'http://www.tao.lu/Ontologies/TAOTest.rdf#TestContent';
/**
* @author Joel Bout, <joel.bout@tudor.lu>
*/
public function deleteTest(core_kernel_classes_Resource $test): bool
{
$returnValue = false;
if (!is_null($test)) {
try {
//delete the associated content
$model = $this->getTestModel($test);
$impl = $this->getTestModelImplementation($model);
$impl->deleteContent($test);
} catch (MissingTestmodelException $e) {
// no content present, skip
}
$returnValue = $test->delete();
$this->getEventManager()->trigger(new TestRemovedEvent($test->getUri()));
}
return (bool) $returnValue;
}
public function deleteResource(core_kernel_classes_Resource $resource): bool
{
return $this->deleteTest($resource);
}
/**
* @author Joel Bout, <joel@taotesting.com>
*/
public function getRootClass(): core_kernel_classes_Class
{
return $this->getClass(TaoOntology::CLASS_URI_TEST);
}
/**
* Check if the Class in parameter is a subclass of Test
*
* @author Joel Bout, <joel.bout@tudor.lu>
*/
public function isTestClass(core_kernel_classes_Class $clazz): bool
{
if ($clazz->getUri() == $this->getClass(TaoOntology::CLASS_URI_TEST)->getUri()) {
return true;
}
foreach ($this->getClass(TaoOntology::CLASS_URI_TEST)->getSubClasses(true) as $subclass) {
if ($clazz->getUri() == $subclass->getUri()) {
return true;
}
}
return false;
}
/**
* @author Joel Bout, <joel.bout@tudor.lu>
* @deprecated use $this->deleteClass instead
*/
public function deleteTestClass(core_kernel_classes_Class $clazz): bool
{
return $this->deleteClass($clazz);
}
/**
* @author Joel Bout, <joel.bout@tudor.lu>
*/
public function getAllItems(): array
{
$returnValue = [];
$itemClazz = $this->getClass(TaoOntology::CLASS_URI_ITEM);
foreach ($itemClazz->getInstances(true) as $instance) {
$returnValue[$instance->getUri()] = $instance->getLabel();
}
return $returnValue;
}
/**
* Used to be called whenever the label of the Test changed
* Deprecated in favor of eventmanager
*
* @author Joel Bout, <joel.bout@tudor.lu>
* @deprecated
*/
public function onChangeTestLabel(core_kernel_classes_Resource $test = null)
{
common_Logger::w('Call to deprecated ' . __FUNCTION__);
return false;
}
/**
* @author Joel Bout, <joel.bout@tudor.lu>
*/
public function cloneInstance(core_kernel_classes_Resource $instance, core_kernel_classes_Class $clazz = null): ?core_kernel_classes_Resource
{
$returnValue = null;
//call the parent create instance to prevent useless process test to be created:
$label = $instance->getLabel();
$cloneLabel = "$label bis";
$clone = parent::createInstance($clazz, $cloneLabel);
if (!is_null($clone)) {
$noCloningProperties = [
self::PROPERTY_TEST_CONTENT,
OntologyRdf::RDF_TYPE
];
foreach ($clazz->getProperties(true) as $property) {
if (!in_array($property->getUri(), $noCloningProperties)) {
//allow clone of every property value but the deliverycontent, which is a process:
foreach ($instance->getPropertyValues($property) as $propertyValue) {
$clone->setPropertyValue($property, $propertyValue);
}
}
}
//Fix label
if (preg_match("/bis/", $label)) {
$cloneNumber = (int)preg_replace("/^(.?)*bis/", "", $label);
$cloneNumber++;
$cloneLabel = preg_replace("/bis(.?)*$/", "", $label) . "bis $cloneNumber" ;
}
$clone->setLabel($cloneLabel);
$impl = $this->getTestModelImplementation($this->getTestModel($instance));
$impl->cloneContent($instance, $clone);
$this->getEventManager()->trigger(new TestDuplicatedEvent($instance->getUri(), $clone->getUri()));
$returnValue = $clone;
}
return $returnValue;
}
/**
* @author Lionel Lecaque, lionel@taotesting.com
*/
protected function setDefaultModel(core_kernel_classes_Resource $test)
{
$testModelClass = $this->getClass(self::CLASS_TEST_MODEL);
$models = $testModelClass->getInstances();
if (count($models) > 0) {
$this->setTestModel($test, current($models));
}
}
/**
* @author Joel Bout, <joel.bout@tudor.lu>
*/
public function createInstance(core_kernel_classes_Class $clazz, $label = ''): core_kernel_classes_Resource
{
$test = parent::createInstance($clazz, $label);
$this->setDefaultModel($test);
$this->getEventManager()->trigger(new TestCreatedEvent($test->getUri()));
return $test;
}
/**
* @author Joel Bout, <joel.bout@tudor.lu>
*/
public function getTestItems(core_kernel_classes_Resource $test): array
{
try {
$model = $this->getTestModel($test);
$returnValue = $this->getTestModelImplementation($model)->getItems($test);
} catch (MissingTestmodelException $e) {
$returnValue = [];
}
return $returnValue;
}
/**
* Changes the model of the test, while trying
* to carry over the items of the test
*/
public function setTestModel(core_kernel_classes_Resource $test, core_kernel_classes_Resource $testModel): void
{
$current = $test->getOnePropertyValue($this->getProperty(self::PROPERTY_TEST_TESTMODEL));
// did the model change?
if (is_null($current) || !$current->equals($testModel)) {
$items = [];
if (!is_null($current)) {
$former = $this->getTestModelImplementation($current);
if (!empty($former)) {
$items = $former->getItems($test);
$former->deleteContent($test);
}
}
$test->editPropertyValues($this->getProperty(self::PROPERTY_TEST_TESTMODEL), $testModel);
$newImpl = $this->getTestModelImplementation($testModel);
if (!empty($newImpl)) {
$newImpl->prepareContent($test, $items);
}
}
}
/**
* Returns a compiler instance for a given test
*/
public function getCompiler(core_kernel_classes_Resource $test, ServiceFileStorage $storage): tao_models_classes_Compiler
{
$testModel = $this->getTestModelImplementation($this->getTestModel($test));
if ($testModel instanceof TestModel) {
$compiler = $testModel->getCompiler($test, $storage);
} else {
$testCompilerClass = $testModel->getCompilerClass();
$compiler = new $testCompilerClass($test, $storage);
$compiler->setServiceLocator($storage->getServiceLocator());
}
return $compiler;
}
/**
* Returns the class of the compiler
* @deprecated $this->getCompiler should be used
*/
public function getCompilerClass(core_kernel_classes_Resource $test): string
{
$testModel = $this->getTestModel($test);
return $this->getTestModelImplementation($testModel)->getCompilerClass();
}
/**
* Returns the model of the current test
*
* @throws MissingTestmodelException
*/
public function getTestModel(core_kernel_classes_Resource $test): core_kernel_classes_Resource
{
$testModel = $test->getOnePropertyValue($this->getPropertyByUri(self::PROPERTY_TEST_TESTMODEL));
if (is_null($testModel)) {
throw new MissingTestmodelException('Undefined testmodel for test ' . $test->getUri());
}
return $testModel;
}
/**
* Returns the implementation of an items test model
*/
public function getTestModelImplementation(core_kernel_classes_Resource $testModel): taoTests_models_classes_TestModel
{
$serviceId = (string)$testModel->getOnePropertyValue($this->getPropertyByUri(self::PROPERTY_TEST_MODEL_IMPLEMENTATION));
if (empty($serviceId)) {
throw new common_exception_NoImplementation('No implementation found for testmodel ' . $testModel->getUri());
}
try {
$testModelService = $this->getServiceManager()->get($serviceId);
} catch (\oat\oatbox\service\ServiceNotFoundException $e) {
if (!class_exists($serviceId)) {
throw new common_exception_Error('Test model service ' . $serviceId . ' not found');
}
// for backward compatibility support classname instead of a serviceid
common_Logger::w('Outdated model definition "' . $serviceId . '", please use test model service');
$testModelService = new $serviceId();
}
if (!$testModelService instanceof \taoTests_models_classes_TestModel) {
throw new common_exception_Error('Test model service ' . get_class($testModelService) . ' not compatible for test model ' . $testModel->getUri());
}
return $testModelService;
}
/**
* @deprecated $this->getProperty should be used
*/
public function getPropertyByUri(string $uri): core_kernel_classes_Property
{
return $this->getProperty($uri);
}
/**
* Get serializer to persist filesystem object
*/
protected function getFileReferenceSerializer(): FileReferenceSerializer
{
return $this->getServiceManager()->get(FileReferenceSerializer::SERVICE_ID);
}
public function hasItems(core_kernel_classes_Resource $test): bool
{
return !empty($this->getTestItems($test));
}
}