149 lines
5.4 KiB
PHP
149 lines
5.4 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) 2020 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
|
|
*
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace oat\taoQtiItem\model\compile\QtiAssetCompiler;
|
|
|
|
use InvalidArgumentException;
|
|
use oat\oatbox\config\ConfigurationService;
|
|
use oat\oatbox\filesystem\Directory;
|
|
use oat\tao\model\media\sourceStrategy\HttpSource;
|
|
use oat\taoItems\model\media\ItemMediaResolver;
|
|
use oat\taoQtiItem\model\compile\QtiAssetReplacer\QtiItemAssetReplacer;
|
|
use oat\taoQtiItem\model\compile\QtiItemCompilerAssetBlacklist;
|
|
use oat\taoQtiItem\model\pack\QtiAssetPacker\PackedAsset;
|
|
use oat\taoQtiItem\model\qti\AssetParser;
|
|
use oat\taoQtiItem\model\qti\exception\XIncludeException;
|
|
use oat\taoQtiItem\model\qti\Item;
|
|
use oat\taoQtiItem\model\qti\XIncludeLoader;
|
|
|
|
class QtiItemAssetCompiler extends ConfigurationService
|
|
{
|
|
/**
|
|
* @param Item $qtiItem
|
|
* @param Directory $publicDirectory
|
|
* @param ItemMediaResolver $resolver
|
|
* @return PackedAsset[]
|
|
* @throws XIncludeException
|
|
*/
|
|
public function extractAndCopyAssetFiles(
|
|
Item $qtiItem,
|
|
Directory $publicDirectory,
|
|
ItemMediaResolver $resolver
|
|
): array {
|
|
$assetParser = new AssetParser($qtiItem, $publicDirectory);
|
|
$assetParser->setGetSharedLibraries(false);
|
|
$assetParser->setGetXinclude(true);
|
|
|
|
$xincludeLoader = new XIncludeLoader($qtiItem, $resolver);
|
|
$xincludeLoader->load();
|
|
|
|
$packedAssets = [];
|
|
foreach ($assetParser->extract() as $type => $assets) {
|
|
foreach ($assets as $key => $assetUrl) {
|
|
if ($this->isBlacklisted($assetUrl)) {
|
|
continue;
|
|
}
|
|
$packedAsset = $this->resolve($resolver, $assetUrl, $type);
|
|
$replacement = $this->getReplacementName($packedAsset);
|
|
$packedAsset->setReplacedBy($replacement);
|
|
|
|
if ($type != 'xinclude') {
|
|
if ($this->getQtiItemAssetReplacer()->shouldBeReplaced($packedAsset)) {
|
|
$packedAsset = $this->replaceWithExternalSource($packedAsset, $qtiItem);
|
|
} else {
|
|
$this->copyAssetFileToPublicDirectory($publicDirectory, $packedAsset);
|
|
}
|
|
}
|
|
$packedAssets[$assetUrl] = $packedAsset;
|
|
}
|
|
}
|
|
|
|
return $packedAssets;
|
|
}
|
|
|
|
private function replaceWithExternalSource(PackedAsset $packedAsset, Item $qtiItem): PackedAsset
|
|
{
|
|
$qtiItemAssetReplacer = $this->getQtiItemAssetReplacer();
|
|
return $qtiItemAssetReplacer->replace(
|
|
$packedAsset,
|
|
$qtiItem->getIdentifier()
|
|
);
|
|
}
|
|
|
|
private function isBlacklisted(string $assetUrl): bool
|
|
{
|
|
return $this->getServiceLocator()
|
|
->get(QtiItemCompilerAssetBlacklist::SERVICE_ID)
|
|
->isBlacklisted($assetUrl);
|
|
}
|
|
|
|
private function resolve(ItemMediaResolver $resolver, string $assetUrl, string $type): PackedAsset
|
|
{
|
|
$mediaAsset = $resolver->resolve($assetUrl);
|
|
$mediaSource = $mediaAsset->getMediaSource();
|
|
|
|
if ($mediaSource instanceof HttpSource) {
|
|
return new PackedAsset($type, $mediaAsset, $assetUrl);
|
|
}
|
|
|
|
$fileInfo = $mediaSource->getFileInfo($mediaAsset->getMediaIdentifier());
|
|
if (isset($fileInfo['link'])) {
|
|
$link = $fileInfo['link'];
|
|
} elseif (isset($fileInfo['filePath'])) {
|
|
$link = $fileInfo['filePath'];
|
|
} else {
|
|
throw new InvalidArgumentException(sprintf('Item asset %s cannot be resolved.', $assetUrl));
|
|
}
|
|
|
|
return new PackedAsset($type, $mediaAsset, $link);
|
|
}
|
|
|
|
private function getReplacementName(PackedAsset $packedAsset): string
|
|
{
|
|
$link = $packedAsset->getMediaAsset()->getMediaIdentifier();
|
|
return uniqid() . '_' . $packedAsset->getMediaAsset()->getMediaSource()->getBaseName($link);
|
|
}
|
|
|
|
private function copyAssetFileToPublicDirectory(Directory $publicDirectory, PackedAsset $packedAsset): bool
|
|
{
|
|
$mediaAsset = $packedAsset->getMediaAsset();
|
|
$mediaSource = $mediaAsset->getMediaSource();
|
|
|
|
$content = $mediaSource->getFileStream($mediaAsset->getMediaIdentifier());
|
|
|
|
$this->logInfo(sprintf(
|
|
'Copying %s reference %s to file %s',
|
|
$packedAsset->getType(),
|
|
$mediaAsset->getMediaIdentifier(),
|
|
$packedAsset->getReplacedBy()
|
|
));
|
|
|
|
return $publicDirectory->getFile($packedAsset->getReplacedBy())->write($content);
|
|
}
|
|
|
|
private function getQtiItemAssetReplacer(): QtiItemAssetReplacer
|
|
{
|
|
return $this->getServiceLocator()->get(QtiItemAssetReplacer::SERVICE_ID);
|
|
}
|
|
}
|