202 lines
10 KiB
PHP
202 lines
10 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) 2019 (original work) Open Assessment Technologies SA;
|
|
*/
|
|
|
|
namespace oat\taoDeliveryRdf\model\export;
|
|
|
|
use oat\taoDeliveryRdf\model\assembly\CompiledTestConverterFactory;
|
|
use ZipArchive;
|
|
use Exception;
|
|
use InvalidArgumentException;
|
|
use common_Exception;
|
|
use core_kernel_classes_EmptyProperty;
|
|
use tao_helpers_Display;
|
|
use tao_helpers_Export;
|
|
use tao_helpers_File;
|
|
use core_kernel_classes_Resource;
|
|
use common_ext_ExtensionsManager;
|
|
use tao_models_classes_service_ServiceCall;
|
|
use tao_models_classes_export_RdfExporter;
|
|
use oat\generis\model\OntologyAwareTrait;
|
|
use oat\oatbox\log\LoggerAwareTrait;
|
|
use oat\oatbox\service\ConfigurableService;
|
|
use oat\tao\model\service\ServiceFileStorage;
|
|
use oat\taoDeliveryRdf\model\assembly\AssemblyFilesReaderInterface;
|
|
use oat\taoDeliveryRdf\model\assembly\UnsupportedCompiledTestFormatException;
|
|
use oat\taoDeliveryRdf\model\DeliveryAssemblyService;
|
|
|
|
class AssemblyExporterService extends ConfigurableService
|
|
{
|
|
use LoggerAwareTrait;
|
|
use OntologyAwareTrait;
|
|
|
|
|
|
const SERVICE_ID = 'taoDeliveryRdf/AssemblyExporterService';
|
|
const OPTION_ASSEMBLY_FILES_READER = 'assembly_files_reader';
|
|
const OPTION_RDF_EXPORTER = 'rdf_exporter';
|
|
const MANIFEST_FILENAME = 'manifest.json';
|
|
const DELIVERY_RDF_FILENAME = 'delivery.rdf';
|
|
/**
|
|
* @var AssemblyFilesReaderInterface
|
|
*/
|
|
private $assemblyFilesReader;
|
|
/**
|
|
* @var tao_models_classes_export_RdfExporter
|
|
*/
|
|
private $rdfExporter;
|
|
/**
|
|
* AssemblyExporterService constructor.
|
|
* @param array $options
|
|
*/
|
|
public function __construct($options = [])
|
|
{
|
|
parent::__construct($options);
|
|
if (!$this->getOption(self::OPTION_ASSEMBLY_FILES_READER) instanceof AssemblyFilesReaderInterface) {
|
|
throw new InvalidArgumentException(sprintf('%s option value must be an instance of %s', self::OPTION_ASSEMBLY_FILES_READER, AssemblyFilesReaderInterface::class));
|
|
}
|
|
|
|
$this->rdfExporter = $this->getOption(self::OPTION_RDF_EXPORTER);
|
|
if (!$this->rdfExporter instanceof tao_models_classes_export_RdfExporter) {
|
|
throw new InvalidArgumentException('%s option value must be an instance of %s', self::OPTION_RDF_EXPORTER, tao_models_classes_export_RdfExporter::class);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Export Compiled Delivery
|
|
*
|
|
* Exports a delivery into its compiled form. In case of the $fsExportPath argument is set,
|
|
* the compiled delivery will be stored in the 'taoDelivery' shared file system, at $fsExportPath location.
|
|
*
|
|
* @param core_kernel_classes_Resource $compiledDelivery
|
|
* @param string $outputTestFormat Format compiled test file in output assembly package.
|
|
*
|
|
* @return string The path to the compiled delivery on the local file system OR the 'taoDelivery' shared file system, depending on whether $fsExportPath is set.
|
|
*
|
|
* @throws common_Exception
|
|
* @throws core_kernel_classes_EmptyProperty
|
|
*/
|
|
public function exportCompiledDelivery(core_kernel_classes_Resource $compiledDelivery, $outputTestFormat)
|
|
{
|
|
$this->logDebug("Exporting Delivery Assembly '" . $compiledDelivery->getUri() . "'...");
|
|
$fileName = tao_helpers_Display::textCleaner($compiledDelivery->getLabel()) . '.zip';
|
|
$path = tao_helpers_File::concat([tao_helpers_Export::getExportPath(), $fileName]);
|
|
if (!tao_helpers_File::securityCheck($path, true)) {
|
|
throw new Exception('Unauthorized file name');
|
|
}
|
|
|
|
// If such a target zip file exists, remove it from local filesystem. It prevents some synchronicity issues
|
|
// to occur while dealing with ZIP Archives (not explained yet).
|
|
if (file_exists($path)) {
|
|
unlink($path);
|
|
}
|
|
|
|
$zipArchive = new ZipArchive();
|
|
if ($zipArchive->open($path, ZipArchive::CREATE) !== true) {
|
|
throw new Exception('Unable to create archive at ' . $path);
|
|
}
|
|
|
|
$this->setupCompiledTestConverter($outputTestFormat);
|
|
$this->doExportCompiledDelivery($path, $compiledDelivery, $zipArchive);
|
|
$zipArchive->close();
|
|
return $path;
|
|
}
|
|
|
|
/**
|
|
* Do Export Compiled Delivery
|
|
*
|
|
* Method containing the main behavior of exporting a compiled delivery into a ZIP archive.
|
|
*
|
|
* For developers wanting to override this method, the following information has to be taken into account:
|
|
*
|
|
* - The value of the $zipArgive argument is an already open ZipArchive object.
|
|
* - The method must keep the archive open after its execution (calling code will take care of it).
|
|
*
|
|
* @param $path
|
|
* @param core_kernel_classes_Resource $compiledDelivery
|
|
* @param ZipArchive $zipArchive
|
|
* @throws common_Exception
|
|
* @throws core_kernel_classes_EmptyProperty
|
|
*/
|
|
protected function doExportCompiledDelivery($path, core_kernel_classes_Resource $compiledDelivery, ZipArchive $zipArchive)
|
|
{
|
|
$taoDeliveryVersion = common_ext_ExtensionsManager::singleton()->getInstalledVersion('taoDelivery');
|
|
$data = [
|
|
'dir' => [],
|
|
'label' => $compiledDelivery->getLabel(),
|
|
'version' => $taoDeliveryVersion
|
|
];
|
|
$directories = $compiledDelivery->getPropertyValues($this->getProperty(DeliveryAssemblyService::PROPERTY_DELIVERY_DIRECTORY));
|
|
foreach ($directories as $id) {
|
|
$directory = $this->getServiceLocator()->get(ServiceFileStorage::SERVICE_ID)->getDirectoryById($id);
|
|
foreach ($this->getAssemblyFilesReader()->getFiles($directory) as $filePath => $fileStream) {
|
|
tao_helpers_File::addFilesToZip($zipArchive, $fileStream, $filePath);
|
|
}
|
|
$data['dir'][$id] = $directory->getPrefix();
|
|
}
|
|
|
|
$runtime = $compiledDelivery->getOnePropertyValue(
|
|
$this->getProperty(DeliveryAssemblyService::PROPERTY_DELIVERY_RUNTIME)
|
|
);
|
|
$serviceCall = $runtime instanceof core_kernel_classes_Resource
|
|
? tao_models_classes_service_ServiceCall::fromResource($runtime)
|
|
: tao_models_classes_service_ServiceCall::fromString((string)$runtime);
|
|
$data['runtime'] = base64_encode(json_encode($serviceCall));
|
|
$rdfData = $this->rdfExporter->getRdfString([$compiledDelivery]);
|
|
if (!$zipArchive->addFromString(self::DELIVERY_RDF_FILENAME, $rdfData)) {
|
|
throw new common_Exception('Unable to add metadata to exported delivery assembly');
|
|
}
|
|
$data['meta'] = self::DELIVERY_RDF_FILENAME;
|
|
$content = json_encode($data);
|
|
if (!$zipArchive->addFromString(self::MANIFEST_FILENAME, $content)) {
|
|
$zipArchive->close();
|
|
unlink($path);
|
|
throw new common_Exception('Unable to add manifest to exported delivery assembly');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $outputTestFormat
|
|
* @return void
|
|
*
|
|
* @throws UnsupportedCompiledTestFormatException
|
|
*/
|
|
private function setupCompiledTestConverter($outputTestFormat)
|
|
{
|
|
/** @var CompiledTestConverterFactory $compiledTestConverterFactory */
|
|
$compiledTestConverterFactory = $this->getServiceLocator()->get(CompiledTestConverterFactory::class);
|
|
$converter = $compiledTestConverterFactory->createConverter($outputTestFormat);
|
|
|
|
if ($converter) {
|
|
$this->getAssemblyFilesReader()->setCompiledTestConverter($converter);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return AssemblyFilesReaderInterface
|
|
*/
|
|
private function getAssemblyFilesReader()
|
|
{
|
|
if (!$this->assemblyFilesReader instanceof AssemblyFilesReaderInterface) {
|
|
$this->assemblyFilesReader = $this->getOption(self::OPTION_ASSEMBLY_FILES_READER);
|
|
}
|
|
|
|
return $this->assemblyFilesReader;
|
|
}
|
|
}
|