Last active
October 12, 2018 12:04
-
-
Save katzueno/f7aa7aaba0afff0b0eeed57d5184d94c to your computer and use it in GitHub Desktop.
src/Entity/File/Version.php & src/File/Image/BasicThumbnailer.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Concrete\Core\File\Image; | |
use Concrete\Core\Application\ApplicationAwareInterface; | |
use Concrete\Core\Application\ApplicationAwareTrait; | |
use Concrete\Core\Entity\File\File; | |
use Concrete\Core\Entity\File\StorageLocation\StorageLocation; | |
use Concrete\Core\File\Image\Thumbnail\ThumbnailerInterface; | |
use Concrete\Core\File\Image\Thumbnail\Type\CustomThumbnail; | |
use Concrete\Core\File\StorageLocation\Configuration\LocalConfiguration; | |
use Concrete\Core\File\StorageLocation\StorageLocationInterface; | |
use Concrete\Core\Http\ResponseAssetGroup; | |
use Exception; | |
use Image; | |
use Imagine\Image\Box; | |
use Imagine\Image\ImageInterface; | |
use Imagine\Image\Point; | |
use Concrete\Core\File\Image\Thumbnail\ThumbnailFormatService; | |
class BasicThumbnailer implements ThumbnailerInterface, ApplicationAwareInterface | |
{ | |
use ApplicationAwareTrait; | |
/** | |
* The currently configured JPEG compression level. | |
* | |
* @var int|null | |
*/ | |
protected $jpegCompression = null; | |
/** | |
* The currently configured PNG compression level. | |
* | |
* @var int|null | |
*/ | |
protected $pngCompression = null; | |
/** | |
* The currently configured format of the generated thumbnails. | |
* | |
* @var string|null | |
*/ | |
protected $thumbnailsFormat = null; | |
/** | |
* @var StorageLocationInterface | |
*/ | |
private $storageLocation; | |
public function __construct(StorageLocationInterface $storageLocation = null) | |
{ | |
$this->storageLocation = $storageLocation; | |
} | |
/** | |
* {@inheritdoc} | |
* | |
* @see ThumbnailerInterface::getStorageLocation() | |
*/ | |
public function getStorageLocation() | |
{ | |
if ($this->storageLocation === null) { | |
$orm = $this->app['database/orm']->entityManager(); | |
/* @var \Doctrine\ORM\EntityManagerInterface $orm */ | |
$storageLocation = $orm->getRepository(StorageLocation::class)->findOneBy(['fslIsDefault' => true]); | |
if ($storageLocation) { | |
$this->storageLocation = $storageLocation; | |
} | |
} | |
return $this->storageLocation; | |
} | |
/** | |
* {@inheritdoc} | |
* | |
* @see ThumbnailerInterface::setStorageLocation() | |
*/ | |
public function setStorageLocation(StorageLocationInterface $storageLocation) | |
{ | |
$this->storageLocation = $storageLocation; | |
return $this; | |
} | |
/** | |
* {@inheritdoc} | |
* | |
* @see ThumbnailerInterface::setJpegCompression() | |
*/ | |
public function setJpegCompression($level) | |
{ | |
if (is_int($level) || is_float($level) || (is_string($level) && is_numeric($level))) { | |
$this->jpegCompression = min(max((int) $level, 0), 100); | |
} | |
return $this; | |
} | |
/** | |
* {@inheritdoc} | |
* | |
* @see ThumbnailerInterface::getJpegCompression() | |
*/ | |
public function getJpegCompression() | |
{ | |
if ($this->jpegCompression === null) { | |
$this->jpegCompression = $this->app->make(BitmapFormat::class)->getDefaultJpegQuality(); | |
} | |
return $this->jpegCompression; | |
} | |
/** | |
* {@inheritdoc} | |
* | |
* @see ThumbnailerInterface::setPngCompression() | |
*/ | |
public function setPngCompression($level) | |
{ | |
if (is_int($level) || is_float($level) || (is_string($level) && is_numeric($level))) { | |
$this->pngCompression = min(max((int) $level, 0), 9); | |
} | |
return $this; | |
} | |
/** | |
* {@inheritdoc} | |
* | |
* @see ThumbnailerInterface::getPngCompression() | |
*/ | |
public function getPngCompression() | |
{ | |
if ($this->pngCompression === null) { | |
$this->pngCompression = $this->app->make(BitmapFormat::class)->getDefaultPngCompressionLevel(); | |
} | |
return $this->pngCompression; | |
} | |
/** | |
* {@inheritdoc} | |
* | |
* @see ThumbnailerInterface::setThumbnailsFormat() | |
*/ | |
public function setThumbnailsFormat($thumbnailsFormat) | |
{ | |
$thumbnailsFormat = strtolower(trim((string) $thumbnailsFormat)); | |
if ($thumbnailsFormat !== ThumbnailFormatService::FORMAT_AUTO) { | |
if (!$this->app->make(BitmapFormat::class)->isFormatValid($thumbnailsFormat)) { | |
$thumbnailsFormat = BitmapFormat::FORMAT_JPEG; | |
} | |
} | |
$this->thumbnailsFormat = $thumbnailsFormat; | |
return $this; | |
} | |
/** | |
* {@inheritdoc} | |
* | |
* @see ThumbnailerInterface::getThumbnailsFormat() | |
*/ | |
public function getThumbnailsFormat() | |
{ | |
if ($this->thumbnailsFormat === null) { | |
$this->setThumbnailsFormat($this->app->make('config')->get('concrete.misc.default_thumbnail_format')); | |
} | |
return $this->thumbnailsFormat; | |
} | |
/** | |
* {@inheritdoc} | |
* | |
* @see ThumbnailerInterface::create() | |
*/ | |
public function create($mixed, $savePath, $width, $height, $fit = false, $format = false) | |
{ | |
if ($format === false) { | |
$format = $this->getThumbnailsFormat(); | |
} | |
switch ($format) { | |
case ThumbnailFormatService::FORMAT_AUTO: | |
$format = $this->app->make(ThumbnailFormatService::class)->getAutomaticFormatForFile($savePath); | |
break; | |
} | |
$thumbnailOptions = [ | |
'jpeg_quality' => $this->getJpegCompression(), | |
'png_compression_level' => $this->getPngCompression(), | |
]; | |
$filesystem = $this->getStorageLocation()->getFileSystemObject(); | |
if ($mixed instanceof ImageInterface) { | |
$image = $mixed; | |
} else { | |
$image = Image::open($mixed); | |
} | |
if ($fit) { | |
$thumb = $this->resizeInPlace($image, new Box($width, $height), ImageInterface::THUMBNAIL_OUTBOUND); | |
$filesystem->write( | |
$savePath, | |
$thumb->get($format, $thumbnailOptions) | |
); | |
} else { | |
if ($height < 1) { | |
$thumb = $this->resizeInPlace($image,$image->getSize()->widen($width)); | |
} elseif ($width < 1) { | |
$thumb = $this->resizeInPlace($image ,$image->getSize()->heighten($height)); | |
} else { | |
$thumb = $this->resizeInPlace($image ,new Box($width, $height)); | |
} | |
$filesystem->write( | |
$savePath, | |
$thumb->get($format, $thumbnailOptions) | |
); | |
} | |
unset($image); | |
unset($thumb); | |
} | |
/** | |
* This function is a copy of the core thumbnail() function, | |
* modified to allow thumbnailing without making a copy in memory first as it is not always needed depending on the context. | |
* | |
* @param ImageInterface $image The image to be resized | |
* @param Box $size The size of the image | |
* @param string $mode | |
* @param string $filter | |
* | |
* @throws InvalidArgumentException | |
* | |
* @return ImageInterface | |
*/ | |
public function resizeInPlace(ImageInterface $image, Box $size, $mode = ImageInterface::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED) | |
{ | |
if ($mode !== ImageInterface::THUMBNAIL_INSET && | |
$mode !== ImageInterface::THUMBNAIL_OUTBOUND) { | |
throw new InvalidArgumentException('Invalid mode specified'); | |
} | |
$imageSize = $image->getSize(); | |
$ratios = [ | |
$size->getWidth() / $imageSize->getWidth(), | |
$size->getHeight() / $imageSize->getHeight(), | |
]; | |
$image->strip(); | |
// if target width is larger than image width | |
// AND target height is longer than image height | |
if ($size->contains($imageSize)) { | |
return $image; | |
} | |
if ($mode === ImageInterface::THUMBNAIL_INSET) { | |
$ratio = min($ratios); | |
} else { | |
$ratio = max($ratios); | |
} | |
if ($mode === ImageInterface::THUMBNAIL_OUTBOUND) { | |
if (!$imageSize->contains($size)) { | |
$size = new Box( | |
min($imageSize->getWidth(), $size->getWidth()), | |
min($imageSize->getHeight(), $size->getHeight()) | |
); | |
} else { | |
$imageSize = $image->getSize()->scale($ratio); | |
$image->resize($imageSize, $filter); | |
} | |
$image->crop(new Point( | |
max(0, round(($imageSize->getWidth() - $size->getWidth()) / 2)), | |
max(0, round(($imageSize->getHeight() - $size->getHeight()) / 2)) | |
), $size); | |
} else { | |
if (!$imageSize->contains($size)) { | |
$imageSize = $imageSize->scale($ratio); | |
$image->resize($imageSize, $filter); | |
} else { | |
$imageSize = $image->getSize()->scale($ratio); | |
$image->resize($imageSize, $filter); | |
} | |
} | |
return $image; | |
} | |
/** | |
* Checks thumbnail resolver for filename, schedule for creation via ajax if necessary. | |
* | |
* @param File|string $obj file instance of path to a file | |
* @param int|null $maxWidth | |
* @param int|null $maxHeight | |
* @param bool $crop | |
* | |
* @return \stdClass | |
*/ | |
private function returnThumbnailObjectFromResolver($obj, $maxWidth, $maxHeight, $crop = false) | |
{ | |
return $this->processThumbnail(true, $obj, $maxWidth, $maxHeight, $crop); | |
} | |
/** | |
* Checks filesystem for thumbnail and if file doesn't exist will create it immediately. | |
* concrete5's default behavior from the beginning up to 8.1. | |
* | |
* @param File|string $obj file instance of path to a file | |
* @param int|null $maxWidth | |
* @param int|null $maxHeight | |
* @param bool $crop | |
* | |
* @return \stdClass | |
*/ | |
private function checkForThumbnailAndCreateIfNecessary($obj, $maxWidth, $maxHeight, $crop = false) | |
{ | |
return $this->processThumbnail(false, $obj, $maxWidth, $maxHeight, $crop); | |
} | |
/** | |
* @param bool $async | |
* @param File|string $obj | |
* @param int|null $maxWidth | |
* @param int|null $maxHeight | |
* @param bool $crop | |
* | |
* @return \stdClass | |
*/ | |
private function processThumbnail($async, $obj, $maxWidth, $maxHeight, $crop) | |
{ | |
if ($obj instanceof File) { | |
$storage = $obj->getFileStorageLocationObject(); | |
} else { | |
$storage = $this->getStorageLocation(); | |
} | |
$this->setStorageLocation($storage); | |
$filesystem = $storage->getFileSystemObject(); | |
$configuration = $storage->getConfigurationObject(); | |
$version = null; | |
$fh = $this->app->make('helper/file'); | |
if ($async) { | |
$assetGroup = ResponseAssetGroup::get(); | |
$assetGroup->requireAsset('core/frontend/thumbnail-builder'); | |
} | |
$baseFilename = ''; | |
$extension = ''; | |
if ($obj instanceof File) { | |
try { | |
$fr = $obj->getFileResource(); | |
$fID = $obj->getFileID(); | |
$extension = $fh->getExtension($fr->getPath()); | |
$baseFilename = md5(implode(':', [$fID, $maxWidth, $maxHeight, $crop, $fr->getTimestamp()])); | |
} catch (Exception $e) { | |
$result = new \stdClass(); | |
$result->src = ''; | |
return $result; | |
} | |
} else { | |
$extension = $fh->getExtension($obj); | |
// We hide the warning from filemtime() because it will only throw the warning on remote files, and we | |
// don't care too much about that | |
$baseFilename = md5(implode(':', [$obj, $maxWidth, $maxHeight, $crop, @filemtime($obj)])); | |
} | |
$thumbnailFormat = $this->getThumbnailsFormat(); | |
if ($thumbnailFormat === ThumbnailFormatService::FORMAT_AUTO) { | |
$thumbnailFormat = $this->app->make(ThumbnailFormatService::class)->getAutomaticFormatForFileExtension($extension); | |
} | |
$thumbnailExtension = $this->app->make(BitmapFormat::class)->getFormatFileExtension($thumbnailFormat); | |
$filename = $baseFilename . '.' . $thumbnailExtension; | |
$abspath = '/cache/thumbnails/' . $filename; | |
if ($async && $obj instanceof File) { | |
$customThumb = new CustomThumbnail($maxWidth, $maxHeight, $abspath, $crop); | |
$path_resolver = $this->app->make('Concrete\Core\File\Image\Thumbnail\Path\Resolver'); | |
$path_resolver->getPath($obj->getVersion(), $customThumb); | |
} else { | |
if (!$filesystem->has($abspath)) { | |
$created = false; | |
try { | |
if ($obj instanceof File) { | |
$image = !is_callable([$fr, 'exists']) || $fr->exists() ? \Image::load($fr->read()) : null; | |
} else { | |
$image = \Image::open($obj); | |
} | |
if ($image) { | |
$this->create( | |
$image, | |
$abspath, | |
$maxWidth, | |
$maxHeight, | |
$crop, | |
$thumbnailFormat | |
); | |
$created = true; | |
} | |
} catch (\Exception $e) { | |
} | |
if ($created === false) { | |
$result = new \stdClass(); | |
$result->src = ''; | |
return $result; | |
} | |
} | |
} | |
$thumb = new \stdClass(); | |
$thumb->src = $configuration->getPublicURLToFile($abspath); | |
// this is a hack, but we shouldn't go out on the network if we don't have to. We should probably | |
// add a method to the configuration to handle this. The file storage locations should be able to handle | |
// thumbnails. | |
if ($configuration instanceof LocalConfiguration) { | |
$dimensionsPath = $configuration->getRootPath() . $abspath; | |
} else { | |
$dimensionsPath = $thumb->src; | |
} | |
try { | |
$dimensions = @getimagesize($dimensionsPath); | |
} catch (Exception $e) { | |
$dimensions = false; | |
} | |
$thumb->width = ($dimensions === false) ? null : $dimensions[0]; | |
$thumb->height = ($dimensions === false) ? null : $dimensions[1]; | |
return $thumb; | |
} | |
/** | |
* {@inheritdoc} | |
* | |
* @see ThumbnailerInterface::getThumbnail() | |
*/ | |
public function getThumbnail($obj, $maxWidth, $maxHeight, $crop = false) | |
{ | |
$config = $this->app->make('config'); | |
if ($config->get('concrete.misc.basic_thumbnailer_generation_strategy') == 'async') { | |
return $this->returnThumbnailObjectFromResolver($obj, $maxWidth, $maxHeight, $crop); | |
} else { | |
return $this->checkForThumbnailAndCreateIfNecessary($obj, $maxWidth, $maxHeight, $crop); | |
} | |
} | |
/** | |
* @deprecated | |
*/ | |
public function outputThumbnail($mixed, $maxWidth, $maxHeight, $alt = null, $return = false, $crop = false) | |
{ | |
$thumb = $this->getThumbnail($mixed, $maxWidth, $maxHeight, $crop); | |
$html = '<img class="ccm-output-thumbnail" alt="' . $alt . '" src="' . $thumb->src . '" width="' . $thumb->width . '" height="' . $thumb->height . '" />'; | |
if ($return) { | |
return $html; | |
} else { | |
echo $html; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Concrete\Core\Entity\File; | |
use Concrete\Core\Attribute\AttributeKeyInterface; | |
use Concrete\Core\Attribute\Category\FileCategory; | |
use Concrete\Core\Attribute\ObjectInterface; | |
use Concrete\Core\Attribute\ObjectTrait; | |
use Concrete\Core\Database\Connection\Connection; | |
use Concrete\Core\Entity\Attribute\Value\FileValue; | |
use Concrete\Core\Entity\File\StorageLocation\StorageLocation; | |
use Concrete\Core\File\Event\FileVersion as FileVersionEvent; | |
use Concrete\Core\File\Exception\InvalidDimensionException; | |
use Concrete\Core\File\Image\BitmapFormat; | |
use Concrete\Core\File\Image\Thumbnail\Path\Resolver; | |
use Concrete\Core\File\Image\Thumbnail\Thumbnail; | |
use Concrete\Core\File\Image\Thumbnail\ThumbnailFormatService; | |
use Concrete\Core\File\Image\Thumbnail\Type\Type; | |
use Concrete\Core\File\Image\Thumbnail\Type\Version as ThumbnailTypeVersion; | |
use Concrete\Core\File\Importer; | |
use Concrete\Core\File\Menu; | |
use Concrete\Core\File\Type\TypeList as FileTypeList; | |
use Concrete\Core\Http\FlysystemFileResponse; | |
use Concrete\Core\Http\Request; | |
use Concrete\Core\Support\Facade\Application; | |
use Concrete\Core\Url\Resolver\Manager\ResolverManagerInterface; | |
use Concrete\Core\User\UserInfoRepository; | |
use DateTime; | |
use Doctrine\ORM\EntityManagerInterface; | |
use Doctrine\ORM\Mapping as ORM; | |
use Exception; | |
use Imagine\Exception\NotSupportedException; | |
use Imagine\Image\Box; | |
use Imagine\Image\ImageInterface; | |
use Imagine\Image\ImagineInterface; | |
use Imagine\Image\Metadata\ExifMetadataReader; | |
use League\Flysystem\AdapterInterface; | |
use League\Flysystem\Cached\CachedAdapter; | |
use League\Flysystem\FileNotFoundException; | |
use League\Flysystem\MountManager; | |
use League\Flysystem\Util; | |
use Page; | |
use Permissions; | |
use stdClass; | |
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | |
use Symfony\Component\HttpFoundation\ResponseHeaderBag; | |
use Throwable; | |
use User; | |
use Imagine\Image\Point; | |
/** | |
* Represents a version of a file. | |
* | |
* @ORM\Entity | |
* @ORM\Table( | |
* name="FileVersions", | |
* indexes={ | |
* @ORM\Index(name="fvFilename", columns={"fvFilename"}), | |
* @ORM\Index(name="fvExtension", columns={"fvExtension"}), | |
* @ORM\Index(name="fvType", columns={"fvType"}) | |
* } | |
* ) | |
*/ | |
class Version implements ObjectInterface | |
{ | |
use ObjectTrait; | |
/** | |
* Update type: file replaced. | |
* | |
* @var int | |
*/ | |
const UT_REPLACE_FILE = 1; | |
/** | |
* Update type: title updated. | |
* | |
* @var int | |
*/ | |
const UT_TITLE = 2; | |
/** | |
* Update type: description updated. | |
* | |
* @var int | |
*/ | |
const UT_DESCRIPTION = 3; | |
/** | |
* Update type: tags modified. | |
* | |
* @var int | |
*/ | |
const UT_TAGS = 4; | |
/** | |
* Update type: extended attributes changed. | |
* | |
* @var int | |
*/ | |
const UT_EXTENDED_ATTRIBUTE = 5; | |
/** | |
* Update type: contents changed. | |
* | |
* @var int | |
*/ | |
const UT_CONTENTS = 6; | |
/** | |
* Update type: file version renamed. | |
* | |
* @var int | |
*/ | |
const UT_RENAME = 7; | |
/** | |
* The associated File instance. | |
* | |
* @ORM\Id | |
* @ORM\ManyToOne(targetEntity="File", inversedBy="versions") | |
* @ORM\JoinColumn(name="fID", referencedColumnName="fID") | |
* | |
* @var \Concrete\Core\Entity\File\File | |
*/ | |
protected $file; | |
/** | |
* The progressive file version identifier. | |
* | |
* @ORM\Id | |
* @ORM\Column(type="integer") | |
* | |
* @var int | |
*/ | |
protected $fvID = 0; | |
/** | |
* The name of the file. | |
* | |
* @ORM\Column(type="string") | |
* | |
* @var string | |
*/ | |
protected $fvFilename = null; | |
/** | |
* The path prefix used to store the file in the file system. | |
* | |
* @ORM\Column(type="string", nullable=true) | |
* | |
* @var string | |
*/ | |
protected $fvPrefix; | |
/** | |
* The date/time when the file version has been added. | |
* | |
* @ORM\Column(type="datetime") | |
* | |
* @var \DateTime | |
*/ | |
protected $fvDateAdded; | |
/** | |
* The date/time when the file version has been approved. | |
* | |
* @ORM\Column(type="datetime") | |
* | |
* @var \DateTime | |
*/ | |
protected $fvActivateDateTime; | |
/** | |
* Is this version the approved one for the associated file? | |
* | |
* @ORM\Column(type="boolean") | |
* | |
* @var bool | |
*/ | |
protected $fvIsApproved = false; | |
/** | |
* The ID of the user that created the file version. | |
* | |
* @ORM\Column(type="integer") | |
* | |
* @var int | |
*/ | |
protected $fvAuthorUID = 0; | |
/** | |
* The ID of the user that approved the file version. | |
* | |
* @ORM\Column(type="integer") | |
* | |
* @var int | |
*/ | |
protected $fvApproverUID = 0; | |
/** | |
* The size (in bytes) of the file version. | |
* | |
* @ORM\Column(type="bigint") | |
* | |
* @var int | |
*/ | |
protected $fvSize = 0; | |
/** | |
* The title of the file version. | |
* | |
* @ORM\Column(type="string", nullable=true) | |
* | |
* @var string|null | |
*/ | |
protected $fvTitle = null; | |
/** | |
* The description of the file version. | |
* | |
* @ORM\Column(type="text", nullable=true) | |
* | |
* @var string|null | |
*/ | |
protected $fvDescription = null; | |
/** | |
* The extension of the file version. | |
* | |
* @ORM\Column(type="string", nullable=true) | |
* | |
* @var string|null | |
*/ | |
protected $fvExtension = null; | |
/** | |
* The tags assigned to the file version (separated by a newline character - '\n'). | |
* | |
* @ORM\Column(type="text", nullable=true) | |
* | |
* @var string|null | |
*/ | |
protected $fvTags = null; | |
/** | |
* The type of the file version. | |
* | |
* @ORM\Column(type="integer") | |
* | |
* @var int | |
*/ | |
protected $fvType = 0; | |
/** | |
* Does this file version has a thumbnail to be used for file listing? | |
* | |
* @ORM\Column(type="boolean") | |
* | |
* @var bool | |
*/ | |
protected $fvHasListingThumbnail = false; | |
/** | |
* Does this file version has a thumbnail to be used used for details? | |
* | |
* @ORM\Column(type="boolean") | |
* | |
* @var bool | |
*/ | |
protected $fvHasDetailThumbnail = false; | |
/** | |
* The currently loaded Image instance. | |
* | |
* @var \Imagine\Image\ImageInterface|false|null null: still not loaded; false: load failed; ImageInterface otherwise | |
*/ | |
private $imagineImage = null; | |
/** | |
* Initialize the instance. | |
*/ | |
public function __construct() | |
{ | |
$this->fvDateAdded = new DateTime(); | |
$this->fvActivateDateTime = new DateTime(); | |
} | |
/** | |
* Add a new file version. | |
* You should call refreshAttributes in order to update the size, extension, type and other attributes. | |
* | |
* @param \Concrete\Core\Entity\File\File $file the File instance associated to this version | |
* @param string $filename The name of the file | |
* @param string $prefix the path prefix used to store the file in the file system | |
* @param array $data Valid array keys are { | |
* | |
* @var int|null $uID the ID of the user that creates the file version (if not specified or empty: we'll assume the currently user logged in user) | |
* @var string $fvTitle the title of the file version | |
* @var string $fvDescription the description of the file version | |
* @var string $fvTags the tags to be assigned to the file version (separated by newlines and/or commas) | |
* @var bool $fvIsApproved Is this version the approved one for the associated file? (default: true) | |
* } | |
* | |
* @return static | |
*/ | |
public static function add(File $file, $filename, $prefix, $data = []) | |
{ | |
$data += [ | |
'uID' => 0, | |
'fvTitle' => '', | |
'fvDescription' => '', | |
'fvTags' => '', | |
'fvIsApproved' => true, | |
]; | |
$app = Application::getFacadeApplication(); | |
$em = $app->make(EntityManagerInterface::class); | |
$dh = $app->make('date'); | |
$date = new DateTime($dh->getOverridableNow()); | |
$uID = (int) $data['uID']; | |
if ($uID < 1) { | |
if (User::isLoggedIn()) { | |
$uID = (int) (new User())->getUserID(); | |
} else { | |
$uID = 0; | |
} | |
} | |
$fv = new static(); | |
$fv->file = $file; | |
$fv->fvID = 1; | |
$fv->fvFilename = (string) $filename; | |
$fv->fvPrefix = $prefix; | |
$fv->fvDateAdded = $date; | |
$fv->fvActivateDateTime = $date; | |
$fv->fvIsApproved = (bool) $data['fvIsApproved']; | |
$fv->fvAuthorUID = $uID; | |
$fv->fvApproverUID = $uID; | |
$fv->fvTitle = (string) $data['fvTitle']; | |
$fv->fvDescription = (string) $data['fvDescription']; | |
$fv->fvTags = self::cleanTags((string) $data['fvTags']); | |
$em->persist($fv); | |
$em->flush(); | |
$fve = new FileVersionEvent($fv); | |
$app->make(EventDispatcherInterface::class)->dispatch('on_file_version_add', $fve); | |
return $fv; | |
} | |
/** | |
* Normalize the tags separator, remove empty tags. | |
* | |
* @param string $tagsStr The list of tags, delimited by '\n', '\r' or ',' | |
* | |
* @return string | |
*/ | |
public static function cleanTags($tagsStr) | |
{ | |
$tagsArray = explode("\n", str_replace(["\r", ','], "\n", $tagsStr)); | |
$cleanTags = []; | |
foreach ($tagsArray as $tag) { | |
$tag = trim($tag); | |
if ($tag !== '') { | |
$cleanTags[] = $tag; | |
} | |
} | |
//the leading and trailing line break char is for searching: fvTag like %\ntag\n% | |
return isset($cleanTags[0]) ? "\n" . implode("\n", $cleanTags) . "\n" : ''; | |
} | |
/** | |
* Set the associated File instance. | |
* | |
* @param \Concrete\Core\Entity\File\File $file | |
*/ | |
public function setFile(File $file) | |
{ | |
$this->file = $file; | |
} | |
/** | |
* Get the associated File instance. | |
* | |
* @return \Concrete\Core\Entity\File\File | |
*/ | |
public function getFile() | |
{ | |
return $this->file; | |
} | |
/** | |
* Get the ID of the associated file instance. | |
* | |
* @return int | |
*/ | |
public function getFileID() | |
{ | |
return $this->file->getFileID(); | |
} | |
/** | |
* Set the progressive file version identifier. | |
* | |
* @param int $fvID | |
*/ | |
public function setFileVersionID($fvID) | |
{ | |
$this->fvID = (int) $fvID; | |
} | |
/** | |
* Get the progressive file version identifier. | |
* | |
* @return int | |
*/ | |
public function getFileVersionID() | |
{ | |
return $this->fvID; | |
} | |
/** | |
* Rename the file. | |
* | |
* @param string $filename | |
*/ | |
public function rename($filename) | |
{ | |
$storage = $this->getFile()->getFileStorageLocationObject(); | |
if ($storage !== null) { | |
$filename = (string) $filename; | |
$app = Application::getFacadeApplication(); | |
$cf = $app->make('helper/concrete/file'); | |
$oldFilename = $this->fvFilename; | |
$path = $cf->prefix($this->fvPrefix, $oldFilename); | |
$newPath = $cf->prefix($this->fvPrefix, $filename); | |
$filesystem = $storage->getFileSystemObject(); | |
if ($filesystem->has($path)) { | |
$filesystem->rename($path, $newPath); | |
} | |
$this->fvFilename = $filename; | |
if ($this->fvTitle == $oldFilename) { | |
$this->fvTitle = $filename; | |
} | |
$this->logVersionUpdate(self::UT_RENAME); | |
$this->save(); | |
$fve = new FileVersionEvent($this); | |
$app->make(EventDispatcherInterface::class)->dispatch('on_file_version_rename', $fve); | |
} | |
} | |
/** | |
* Update the filename and the path prefix of the file. | |
* | |
* @param string $filename The new name of file | |
* @param string $prefix The new path prefix | |
*/ | |
public function updateFile($filename, $prefix) | |
{ | |
$this->fvFilename = $filename; | |
$this->fvPrefix = $prefix; | |
$this->save(); | |
$this->logVersionUpdate(self::UT_REPLACE_FILE); | |
} | |
/** | |
* Set the name of the file. | |
* | |
* @param string $filename | |
*/ | |
public function setFilename($filename) | |
{ | |
$this->fvFilename = $filename; | |
} | |
/** | |
* Get the name of the file. | |
* | |
* @return string | |
*/ | |
public function getFileName() | |
{ | |
return $this->fvFilename; | |
} | |
/** | |
* Get the path prefix used to store the file in the file system. | |
* | |
* @return string | |
*/ | |
public function getPrefix() | |
{ | |
return $this->fvPrefix; | |
} | |
/** | |
* Get the date/time when the file version has been added. | |
* | |
* @return \DateTime | |
*/ | |
public function getDateAdded() | |
{ | |
return $this->fvDateAdded; | |
} | |
/** | |
* Get the date/time when the file version has been activated (or NULL if the file version is not approved). | |
* | |
* @return \DateTime|null | |
*/ | |
public function getActivateDateTime() | |
{ | |
return $this->fvIsApproved ? $this->fvActivateDateTime : null; | |
} | |
/** | |
* Mark this file version as approved (and disapprove all the other versions of the file). | |
* The currently logged in user (if any) will be stored as the approver. | |
*/ | |
public function approve() | |
{ | |
$app = Application::getFacadeApplication(); | |
foreach ($this->file->getFileVersions() as $fv) { | |
$fv->fvIsApproved = false; | |
$fv->save(false); | |
} | |
$this->fvIsApproved = true; | |
$this->fvActivateDateTime = new DateTime(); | |
if (User::isLoggedIn()) { | |
$uID = (int) (new User())->getUserID(); | |
if ($uID > 0) { | |
$this->fvApproverUID = $uID; | |
} | |
} | |
$this->save(); | |
$fve = new FileVersionEvent($this); | |
$app->make(EventDispatcherInterface::class)->dispatch('on_file_version_approve', $fve); | |
$fo = $this->getFile(); | |
$fo->reindex(); | |
$app->make('cache/request')->delete('file/version/approved/' . $this->getFileID()); | |
} | |
/** | |
* Mark this file version as not approved. | |
*/ | |
public function deny() | |
{ | |
$app = Application::getFacadeApplication(); | |
$this->fvIsApproved = false; | |
$this->save(); | |
$fve = new FileVersionEvent($this); | |
$app->make(EventDispatcherInterface::class)->dispatch('on_file_version_deny', $fve); | |
$app->make('cache/request')->delete('file/version/approved/' . $this->getFileID()); | |
} | |
/** | |
* Is this version the approved one for the associated file? | |
* | |
* @return bool | |
*/ | |
public function isApproved() | |
{ | |
return $this->fvIsApproved; | |
} | |
/** | |
* Get the ID of the user that created the file version. | |
* | |
* @return int | |
*/ | |
public function getAuthorUserID() | |
{ | |
return $this->fvAuthorUID; | |
} | |
/** | |
* Get the username of the user that created the file version (or "Unknown"). | |
* | |
* @return string | |
*/ | |
public function getAuthorName() | |
{ | |
if ($this->fvAuthorUID) { | |
$app = Application::getFacadeApplication(); | |
$ui = $app->make(UserInfoRepository::class)->getByID($this->fvAuthorUID); | |
} else { | |
$ui = null; | |
} | |
return $ui === null ? t('(Unknown)') : $ui->getUserDisplayName(); | |
} | |
/** | |
* Get the ID of the user that approved the file version. | |
* | |
* @return int | |
*/ | |
public function getApproverUserID() | |
{ | |
return $this->fvApproverUID; | |
} | |
/** | |
* Get the username of the user that approved the file version (or "Unknown"). | |
* | |
* @return string | |
*/ | |
public function getApproverName() | |
{ | |
if ($this->fvApproverUID) { | |
$app = Application::getFacadeApplication(); | |
$ui = $app->make(UserInfoRepository::class)->getByID($this->fvApproverUID); | |
} else { | |
$ui = null; | |
} | |
return $ui === null ? t('(Unknown)') : $ui->getUserDisplayName(); | |
} | |
/** | |
* Get the file size of the file (in bytes). | |
* | |
* @return int | |
*/ | |
public function getFullSize() | |
{ | |
return $this->fvSize; | |
} | |
/** | |
* Get the formatted file size. | |
* | |
* @return string | |
* | |
* @example 123 KB | |
*/ | |
public function getSize() | |
{ | |
$app = Application::getFacadeApplication(); | |
return $app->make('helper/number')->formatSize($this->fvSize, 'KB'); | |
} | |
/** | |
* Update the title of the file. | |
* | |
* @param string $title | |
*/ | |
public function updateTitle($title) | |
{ | |
$app = Application::getFacadeApplication(); | |
$this->fvTitle = $title; | |
$this->save(); | |
$this->logVersionUpdate(self::UT_TITLE); | |
$fve = new FileVersionEvent($this); | |
$app->make(EventDispatcherInterface::class)->dispatch('on_file_version_update_title', $fve); | |
} | |
/** | |
* Get the title of the file version. | |
* | |
* @return null|string | |
*/ | |
public function getTitle() | |
{ | |
return $this->fvTitle; | |
} | |
/** | |
* Update the description of the file. | |
* | |
* @param string $descr | |
*/ | |
public function updateDescription($descr) | |
{ | |
$app = Application::getFacadeApplication(); | |
$this->fvDescription = $descr; | |
$this->save(); | |
$this->logVersionUpdate(self::UT_DESCRIPTION); | |
$fve = new FileVersionEvent($this); | |
$app->make(EventDispatcherInterface::class)->dispatch('on_file_version_update_description', $fve); | |
} | |
/** | |
* Get the description of the file version. | |
* | |
* @return null|string | |
*/ | |
public function getDescription() | |
{ | |
return $this->fvDescription; | |
} | |
/** | |
* Get the extension of the file version. | |
* | |
* @return null|string | |
*/ | |
public function getExtension() | |
{ | |
return $this->fvExtension; | |
} | |
/** | |
* Update the tags associated to the file. | |
* | |
* @param string $tags List of tags separated by newlines and/or commas | |
*/ | |
public function updateTags($tags) | |
{ | |
$app = Application::getFacadeApplication(); | |
$tags = self::cleanTags($tags); | |
$this->fvTags = $tags; | |
$this->save(); | |
$this->logVersionUpdate(self::UT_TAGS); | |
$fve = new FileVersionEvent($this); | |
$app->make(EventDispatcherInterface::class)->dispatch('on_file_version_update_tags', $fve); | |
} | |
/** | |
* Get the tags assigned to the file version (as a list of strings). | |
* | |
* @return string[] | |
*/ | |
public function getTagsList() | |
{ | |
$tags = explode("\n", str_replace("\r", "\n", trim($this->getTags()))); | |
$clean_tags = []; | |
foreach ($tags as $tag) { | |
$tag = trim($tag); | |
if ($tag !== '') { | |
$clean_tags[] = $tag; | |
} | |
} | |
return $clean_tags; | |
} | |
/** | |
* Get the tags assigned to the file version (one tag per line - lines are separated by '\n'). | |
* | |
* @return null|string | |
*/ | |
public function getTags() | |
{ | |
return $this->fvTags; | |
} | |
/** | |
* Get the mime type of the file if known. | |
* | |
* @return string|false | |
*/ | |
public function getMimeType() | |
{ | |
try { | |
$fre = $this->getFileResource(); | |
$result = $fre->getMimetype(); | |
} catch (FileNotFoundException $x) { | |
$result = false; | |
} | |
return $result; | |
} | |
/** | |
* Get the type of the file. | |
* | |
* @return \Concrete\Core\File\Type\Type | |
*/ | |
public function getTypeObject() | |
{ | |
$app = Application::getFacadeApplication(); | |
$fh = $app->make('helper/file'); | |
$ext = $fh->getExtension($this->fvFilename); | |
$ftl = FileTypeList::getType($ext); | |
return $ftl; | |
} | |
/** | |
* Get the name of the file type. | |
* | |
* @return string | |
*/ | |
public function getType() | |
{ | |
$ftl = $this->getTypeObject(); | |
return $ftl->getName(); | |
} | |
/** | |
* Get the localized name of the file type. | |
* | |
* @return string | |
*/ | |
public function getDisplayType() | |
{ | |
$ftl = $this->getTypeObject(); | |
return $ftl->getDisplayName(); | |
} | |
/** | |
* Get the localized name of the generic category type. | |
* | |
* @return string | |
*/ | |
public function getGenericTypeText() | |
{ | |
$to = $this->getTypeObject(); | |
return $to->getGenericDisplayType(); | |
} | |
/** | |
* Log updates to files. | |
* | |
* @param int $updateTypeID One of the Version::UT_... constants | |
* @param int $updateTypeAttributeID the ID of the attribute that has been updated (if any - useful when $updateTypeID is UT_EXTENDED_ATTRIBUTE) | |
*/ | |
public function logVersionUpdate($updateTypeID, $updateTypeAttributeID = 0) | |
{ | |
$app = Application::getFacadeApplication(); | |
$db = $app->make(Connection::class); | |
$db->executeQuery( | |
'INSERT INTO FileVersionLog (fID, fvID, fvUpdateTypeID, fvUpdateTypeAttributeID) VALUES (?, ?, ?, ?)', | |
[ | |
$this->getFileID(), | |
$this->getFileVersionID(), | |
$updateTypeID, | |
$updateTypeAttributeID, | |
] | |
); | |
} | |
/** | |
* Get an array containing human-readable descriptions of everything that happened to this file version. | |
* | |
* @return string[] | |
*/ | |
public function getVersionLogComments() | |
{ | |
$app = Application::getFacadeApplication(); | |
$db = $app->make(Connection::class); | |
$updates = []; | |
$ga = $db->fetchAll( | |
'SELECT fvUpdateTypeID, fvUpdateTypeAttributeID FROM FileVersionLog WHERE fID = ? AND fvID = ? ORDER BY fvlID ASC', | |
[$this->getFileID(), $this->getFileVersionID()] | |
); | |
foreach ($ga as $a) { | |
switch ($a['fvUpdateTypeID']) { | |
case self::UT_REPLACE_FILE: | |
$updates[] = t('File'); | |
break; | |
case self::UT_TITLE: | |
$updates[] = t('Title'); | |
break; | |
case self::UT_DESCRIPTION: | |
$updates[] = t('Description'); | |
break; | |
case self::UT_TAGS: | |
$updates[] = t('Tags'); | |
break; | |
case self::UT_CONTENTS: | |
$updates[] = t('File Content'); | |
break; | |
case self::UT_RENAME: | |
$updates[] = t('File Name'); | |
break; | |
case self::UT_EXTENDED_ATTRIBUTE: | |
$val = $db->fetchColumn( | |
'SELECT akName FROM AttributeKeys WHERE akID = ?', | |
[$a['fvUpdateTypeAttributeID']] | |
); | |
if ($val !== false) { | |
$updates[] = $val; | |
} | |
break; | |
} | |
} | |
return array_values(array_unique($updates)); | |
} | |
/** | |
* Get the path to the file relative to the webroot (may not exist). | |
* Return NULL if the file storage location is invalid. | |
* If the storage location does not support relative paths, you'll get the URL to the file (or the download URL if the file is not directly accessible). | |
* | |
* @return string|null | |
* | |
* @example /application/files/0000/0000/0000/file.png | |
*/ | |
public function getRelativePath() | |
{ | |
$url = null; | |
$fsl = $this->getFile()->getFileStorageLocationObject(); | |
if ($fsl !== null) { | |
$app = Application::getFacadeApplication(); | |
$cf = $app->make('helper/concrete/file'); | |
$configuration = $fsl->getConfigurationObject(); | |
if ($configuration->hasRelativePath()) { | |
$url = $configuration->getRelativePathToFile($cf->prefix($this->fvPrefix, $this->fvFilename)); | |
} | |
if ($configuration->hasPublicURL() && !$url) { | |
$url = $configuration->getPublicURLToFile($cf->prefix($this->fvPrefix, $this->fvFilename)); | |
} | |
if (!$url) { | |
$url = (string) $this->getDownloadURL(); | |
} | |
} | |
return $url; | |
} | |
/** | |
* Get an URL that points to the file on disk (if not available, you'll get the result of the getDownloadURL method). | |
* Return NULL if the file storage location is invalid. | |
* If the file is not directly accessible, you'll get the download URL. | |
* | |
* @return string|null | |
*/ | |
public function getURL() | |
{ | |
$url = null; | |
$fsl = $this->getFile()->getFileStorageLocationObject(); | |
if ($fsl !== null) { | |
$app = Application::getFacadeApplication(); | |
$cf = $app->make('helper/concrete/file'); | |
$configuration = $fsl->getConfigurationObject(); | |
if ($configuration->hasPublicURL()) { | |
$url = $configuration->getPublicURLToFile($cf->prefix($this->fvPrefix, $this->fvFilename)); | |
} | |
if (!$url) { | |
$url = (string) $this->getDownloadURL(); | |
} | |
} | |
return $url; | |
} | |
/** | |
* Get an URL that can be used to download the file. | |
* This passes through the download_file single page. | |
* | |
* @return \League\URL\URLInterface | |
*/ | |
public function getDownloadURL() | |
{ | |
$app = Application::getFacadeApplication(); | |
$urlResolver = $app->make(ResolverManagerInterface::class); | |
$c = Page::getCurrentPage(); | |
$cID = $c instanceof Page && !$c->isError() ? $c->getCollectionID() : 0; | |
return $urlResolver->resolve(['/download_file', $this->getFileID(), $cID]); | |
} | |
/** | |
* Get an URL that can be used to download the file (it will force the download of all file types, even if the browser can display them). | |
* | |
* @return \League\URL\URLInterface | |
*/ | |
public function getForceDownloadURL() | |
{ | |
$app = Application::getFacadeApplication(); | |
$c = Page::getCurrentPage(); | |
$cID = $c instanceof Page && !$c->isError() ? $c->getCollectionID() : 0; | |
$urlResolver = $app->make(ResolverManagerInterface::class); | |
return $urlResolver->resolve(['/download_file', 'force', $this->getFileID(), $cID]); | |
} | |
/** | |
* Get a Response instance that will force the browser to download the file, even if the browser can display it. | |
* | |
* @return \Concrete\Core\Http\Response | |
*/ | |
public function buildForceDownloadResponse() | |
{ | |
$app = Application::getFacadeApplication(); | |
$fre = $this->getFileResource(); | |
$fs = $this->getFile()->getFileStorageLocationObject()->getFileSystemObject(); | |
$response = new FlysystemFileResponse($fre->getPath(), $fs); | |
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT); | |
return $response; | |
} | |
/** | |
* Check if there is a viewer for the type of the file. | |
* | |
* @return bool | |
*/ | |
public function canView() | |
{ | |
$to = $this->getTypeObject(); | |
return (string) $to->getView() !== ''; | |
} | |
/** | |
* Check if there is an editor for the type of the file. | |
* | |
* @return bool | |
*/ | |
public function canEdit() | |
{ | |
$to = $this->getTypeObject(); | |
return (string) $to->getEditor() !== ''; | |
} | |
/** | |
* Create a new (unapproved) copy of this file version. | |
* The new Version instance will have the current user as the author (if available), and a new version ID. | |
* | |
* @return Version | |
*/ | |
public function duplicate() | |
{ | |
$app = Application::getFacadeApplication(); | |
$em = $app->make(EntityManagerInterface::class); | |
$qq = $em->createQuery('SELECT max(v.fvID) FROM \Concrete\Core\Entity\File\Version v where v.file = :file'); | |
$qq->setParameter('file', $this->file); | |
$fvID = $qq->getSingleScalarResult(); | |
++$fvID; | |
$fv = clone $this; | |
$fv->fvID = $fvID; | |
$fv->fvIsApproved = false; | |
$fv->fvDateAdded = new DateTime(); | |
if (User::isLoggedIn()) { | |
$uID = (int) (new User())->getUserID(); | |
if ($uID !== 0) { | |
$fv->fvAuthorUID = $uID; | |
} | |
} | |
$em->persist($fv); | |
$this->deny(); | |
foreach ($this->getAttributes() as $value) { | |
$value = clone $value; | |
$value->setVersion($fv); | |
$em->persist($value); | |
} | |
$em->flush(); | |
$fve = new FileVersionEvent($fv); | |
$app->make(EventDispatcherInterface::class)->dispatch('on_file_version_duplicate', $fve); | |
return $fv; | |
} | |
/** | |
* Duplicate the underlying file and assign its new position to this instance. | |
*/ | |
public function duplicateUnderlyingFile() | |
{ | |
$app = Application::getFacadeApplication(); | |
$importer = new Importer(); | |
$fi = $app->make('helper/file'); | |
$cf = $app->make('helper/concrete/file'); | |
$filesystem = $this->getFile()->getFileStorageLocationObject()->getFileSystemObject(); | |
$fileName = $this->getFileName(); | |
do { | |
$prefix = $importer->generatePrefix(); | |
$path = $cf->prefix($prefix, $fileName); | |
} while ($filesystem->has($path)); | |
$fileContents = $this->getFileResource()->read(); | |
$mimeType = Util::guessMimeType($fileName, $fileContents); | |
$filesystem->write( | |
$path, | |
$fileContents, | |
[ | |
'visibility' => AdapterInterface::VISIBILITY_PUBLIC, | |
'mimetype' => $mimeType, | |
] | |
); | |
$this->updateFile($fileName, $prefix); | |
} | |
/** | |
* Delete this version of the file. | |
* | |
* @param bool $deleteFilesAndThumbnails should we delete the actual file and the thumbnails? | |
*/ | |
public function delete($deleteFilesAndThumbnails = false) | |
{ | |
$app = Application::getFacadeApplication(); | |
$db = $app->make(Connection::class); | |
$em = $app->make(EntityManagerInterface::class); | |
$category = $this->getObjectAttributeCategory(); | |
foreach ($this->getAttributes() as $attribute) { | |
$category->deleteValue($attribute); | |
} | |
$db->executeQuery('DELETE FROM FileVersionLog WHERE fID = ? AND fvID = ?', [$this->getFileID(), $this->fvID]); | |
if ($deleteFilesAndThumbnails) { | |
$types = Type::getVersionList(); | |
foreach ($types as $type) { | |
$this->deleteThumbnail($type); | |
} | |
try { | |
$fsl = $this->getFile()->getFileStorageLocationObject()->getFileSystemObject(); | |
$fre = $this->getFileResource(); | |
if ($fsl->has($fre->getPath())) { | |
$fsl->delete($fre->getPath()); | |
} | |
} catch (FileNotFoundException $e) { | |
} | |
} | |
$em->remove($this); | |
$em->flush(); | |
} | |
/** | |
* Get an abstract object to work with the actual file resource (note: this is NOT a concrete5 File object). | |
* | |
* @throws \League\Flysystem\FileNotFoundException | |
* | |
* @return \League\Flysystem\File | |
*/ | |
public function getFileResource() | |
{ | |
$app = Application::getFacadeApplication(); | |
$cf = $app->make('helper/concrete/file'); | |
$fs = $this->getFile()->getFileStorageLocationObject()->getFileSystemObject(); | |
$fo = $fs->get($cf->prefix($this->fvPrefix, $this->fvFilename)); | |
return $fo; | |
} | |
/** | |
* Update the contents of the file. | |
* | |
* @param string $contents The new content of the file | |
* @param bool $rescanThumbnails Should thumbnails be rescanned as well? | |
*/ | |
public function updateContents($contents, $rescanThumbnails = true) | |
{ | |
$this->releaseImagineImage(); | |
$storage = $this->getFile()->getFileStorageLocationObject(); | |
if ($storage !== null) { | |
$app = Application::getFacadeApplication(); | |
$cf = $app->make('helper/concrete/file'); | |
$path = $cf->prefix($this->fvPrefix, $this->fvFilename); | |
$filesystem = $storage->getFileSystemObject(); | |
try { | |
if ($filesystem->has($path)) { | |
$filesystem->delete($path); | |
} | |
} catch (FileNotFoundException $x) { | |
} | |
$filesystem->write($path, $contents); | |
$this->logVersionUpdate(self::UT_CONTENTS); | |
$fve = new FileVersionEvent($this); | |
$app->make(EventDispatcherInterface::class)->dispatch('on_file_version_update_contents', $fve); | |
$this->refreshAttributes($rescanThumbnails); | |
} | |
} | |
/** | |
* Get the contents of the file. | |
* | |
* @return string|null return NULL if the actual file does not exist or can't be read | |
*/ | |
public function getFileContents() | |
{ | |
$result = null; | |
$fsl = $this->getFile()->getFileStorageLocationObject(); | |
if ($fsl !== null) { | |
$app = Application::getFacadeApplication(); | |
$cf = $app->make('helper/concrete/file'); | |
try { | |
$result = $fsl->getFileSystemObject()->read($cf->prefix($this->fvPrefix, $this->fvFilename)); | |
if ($result === false) { | |
$result = null; | |
} | |
} catch (FileNotFoundException $x) { | |
} | |
} | |
return $result; | |
} | |
/** | |
* {@inheritdoc} | |
* | |
* @see \Concrete\Core\Attribute\ObjectInterface::getObjectAttributeCategory() | |
* | |
* @return \Concrete\Core\Attribute\Category\FileCategory | |
*/ | |
public function getObjectAttributeCategory() | |
{ | |
$app = Application::getFacadeApplication(); | |
return $app->make(FileCategory::class); | |
} | |
/** | |
* Rescan all the attributes of this file version. | |
* This will run any type-based import routines, and store those attributes, generate thumbnails, etc... | |
* | |
* @param bool $rescanThumbnails Should thumbnails be rescanned as well? | |
* | |
* @return null|int Return one of the \Concrete\Core\File\Importer::E_... constants in case of errors, NULL otherwise. | |
*/ | |
public function refreshAttributes($rescanThumbnails = true) | |
{ | |
$app = Application::getFacadeApplication(); | |
$storage = $this->getFile()->getFileStorageLocationObject(); | |
if ($storage !== null) { | |
$fs = $storage->getFileSystemObject(); | |
$adapter = $fs->getAdapter(); | |
if ($adapter instanceof CachedAdapter) { | |
$cache = $adapter->getCache(); | |
$cf = $app->make('helper/concrete/file'); | |
$path = Util::normalizePath($cf->prefix($this->fvPrefix, $this->fvFilename)); | |
$cache->delete($path); | |
} | |
} | |
$em = $app->make(EntityManagerInterface::class); | |
$fh = $app->make('helper/file'); | |
$ext = $fh->getExtension($this->fvFilename); | |
$ftl = FileTypeList::getType($ext); | |
$cl = $ftl->getCustomInspector(); | |
if ($cl !== null) { | |
$this->fvGenericType = $ftl->getGenericType(); | |
$cl->inspect($this); | |
} | |
$em->refresh($this); | |
try { | |
$fsr = $this->getFileResource(); | |
if (!$fsr->isFile()) { | |
return Importer::E_FILE_INVALID; | |
} | |
} catch (FileNotFoundException $e) { | |
return Importer::E_FILE_INVALID; | |
} | |
$this->fvExtension = $ext; | |
$this->fvType = $ftl->getGenericType(); | |
if ($this->fvTitle === null) { | |
$this->fvTitle = $this->getFileName(); | |
} | |
$this->fvSize = $fsr->getSize(); | |
if ($rescanThumbnails) { | |
$this->rescanThumbnails(); | |
} | |
$this->save(); | |
$f = $this->getFile(); | |
$f->reindex(); | |
} | |
/** | |
* Get the list of attributes associated to this file version. | |
* | |
* @return \Concrete\Core\Entity\Attribute\Value\FileValue[] | |
*/ | |
public function getAttributes() | |
{ | |
return $this->getObjectAttributeCategory()->getAttributeValues($this); | |
} | |
/** | |
* {@inheritdoc} | |
* | |
* @see \Concrete\Core\Attribute\ObjectInterface::getAttributeValueObject() | |
* | |
* @return \Concrete\Core\Entity\Attribute\Value\FileValue|null | |
*/ | |
public function getAttributeValueObject($ak, $createIfNotExists = false) | |
{ | |
if (!($ak instanceof AttributeKeyInterface)) { | |
$ak = $ak ? $this->getObjectAttributeCategory()->getAttributeKeyByHandle((string) $ak) : null; | |
} | |
if ($ak === null) { | |
$result = null; | |
} else { | |
$result = $this->getObjectAttributeCategory()->getAttributeValue($ak, $this); | |
if ($result === null && $createIfNotExists) { | |
$result = new FileValue(); | |
$result->setVersion($this); | |
$result->setAttributeKey($ak); | |
} | |
} | |
return $result; | |
} | |
/** | |
* Get an \Imagine\Image\ImageInterface representing the image. | |
* | |
* @return \Imagine\Image\ImageInterface|null return NULL if the image coulnd't be read, an ImageInterface otherwise | |
*/ | |
public function getImagineImage() | |
{ | |
if (null === $this->imagineImage) { | |
$app = Application::getFacadeApplication(); | |
$resource = $this->getFileResource(); | |
$mimetype = $resource->getMimeType(); | |
$imageLibrary = $app->make(ImagineInterface::class); | |
switch ($mimetype) { | |
case 'image/svg+xml': | |
case 'image/svg-xml': | |
case 'text/plain': | |
if ($imageLibrary instanceof \Imagine\Gd\Imagine) { | |
try { | |
$imageLibrary = $app->make('image/imagick'); | |
} catch (Exception $x) { | |
$this->imagineImage = false; | |
} catch (Throwable $x) { | |
$this->imagineImage = false; | |
} | |
} | |
break; | |
} | |
if (null === $this->imagineImage) { | |
$metadataReader = $imageLibrary->getMetadataReader(); | |
if (!$metadataReader instanceof ExifMetadataReader) { | |
if ($app->make('config')->get('concrete.file_manager.images.use_exif_data_to_rotate_images')) { | |
try { | |
$imageLibrary->setMetadataReader(new ExifMetadataReader()); | |
} catch (NotSupportedException $e) { | |
} | |
} | |
} | |
try { | |
$this->imagineImage = $imageLibrary->load($resource->read()); | |
} catch (FileNotFoundException $e) { | |
$this->imagineImage = false; | |
} | |
} | |
} | |
return $this->imagineImage ?: null; | |
} | |
/** | |
* Does the \Imagine\Image\ImageInterface instance have already been loaded? | |
* | |
* @return bool | |
*/ | |
public function hasImagineImage() | |
{ | |
return $this->imagineImage ? true : false; | |
} | |
/** | |
* Unload the loaded Image instance. | |
*/ | |
public function releaseImagineImage() | |
{ | |
$this->imagineImage = null; | |
} | |
/** | |
* Create missing thumbnails (or re-create all the thumbnails). | |
* | |
* @param bool $deleteExistingThumbnails Set to true to delete existing thumbnails (they will be re-created from scratch) | |
* | |
* @return bool return true on success, false on failure (file is not an image, problems during image processing, ...) | |
*/ | |
public function refreshThumbnails($deleteExistingThumbnails) | |
{ | |
$result = false; | |
if ($this->fvType == \Concrete\Core\File\Type\Type::T_IMAGE) { | |
try { | |
$image = $this->getImagineImage(); | |
if ($image) { | |
$imageWidth = (int) $this->getAttribute('width') ?: (int) $image->getSize()->getWidth(); | |
$imageHeight = (int) $this->getAttribute('height') ?: (int) $image->getSize()->getHeight(); | |
$types = Type::getVersionList(); | |
$file = $this->getFile(); | |
$fsl = null; | |
foreach ($types as $type) { | |
if ($type->shouldExistFor($imageWidth, $imageHeight, $file)) { | |
if ($deleteExistingThumbnails) { | |
$this->deleteThumbnail($type); | |
} else { | |
if ($fsl === null) { | |
$fsl = $this->getFile()->getFileStorageLocationObject()->getFileSystemObject(); | |
} | |
$path = $type->getFilePath($this); | |
try { | |
$exists = $fsl->has($path); | |
} catch (FileNotFoundException $e) { | |
$exists = false; | |
} | |
if ($exists) { | |
continue; | |
} | |
} | |
$this->generateThumbnail($type); | |
} else { | |
// delete the file if it exists | |
$this->deleteThumbnail($type); | |
} | |
} | |
$result = true; | |
} | |
unset($image); | |
$this->releaseImagineImage(); | |
} catch (\Imagine\Exception\InvalidArgumentException $e) { | |
} catch (\Imagine\Exception\RuntimeException $e) { | |
} | |
} | |
return $result; | |
} | |
protected $prevHeight = null; | |
protected $prevWidth = null; | |
/** | |
* Generate a thumbnail for a specific thumbnail type version. | |
* | |
* @param \Concrete\Core\File\Image\Thumbnail\Type\Version $type | |
*/ | |
public function generateThumbnail(ThumbnailTypeVersion $type) | |
{ | |
$app = Application::getFacadeApplication(); | |
$config = $app->make('config'); | |
$bitmapFormat = $app->make(BitmapFormat::class); | |
$filesystem = $this->getFile() | |
->getFileStorageLocationObject() | |
->getFileSystemObject(); | |
$height = $type->getHeight(); | |
$width = $type->getWidth(); | |
if (!empty($this->prevHeight) && !empty($height) && $this->prevHeight < $height) { | |
$this->releaseImagineImage(); | |
} elseif (!empty($this->width) && !empty($width) && $this->prevWidth < $width) { | |
$this->releaseImagineImage(); | |
} | |
$image = $this->getImagineImage(); | |
if ($height && $width) { | |
$size = new Box($width, $height); | |
$this->prevWidth = $width; | |
$this->prevHeight = $height; | |
} elseif ($width) { | |
$size = $image->getSize()->widen($width); | |
$this->prevHeight = null; | |
$this->prevWidth = $width; | |
} else { | |
$size = $image->getSize()->heighten($height); | |
$this->prevWidth = null; | |
$this->prevHeight = $height; | |
} | |
// isCropped only exists on the CustomThumbnail type | |
if (method_exists($type, 'isCropped') && $type->isCropped()) { | |
$thumbnailMode = ImageInterface::THUMBNAIL_OUTBOUND; | |
} else { | |
switch ($type->getSizingMode()) { | |
case Type::RESIZE_EXACT: | |
$thumbnailMode = ImageInterface::THUMBNAIL_OUTBOUND; | |
break; | |
case Type::RESIZE_PROPORTIONAL: | |
default: | |
$thumbnailMode = ImageInterface::THUMBNAIL_INSET; | |
break; | |
} | |
} | |
$imageForThumbnail = $image; | |
if ($type->isUpscalingEnabled()) { | |
$imageSize = $image->getSize(); | |
if ($size->contains($imageSize) && $imageSize->getWidth() !== $size->getWidth() && $imageSize->getHeight() !== $size->getHeight()) { | |
if (($imageSize->getWidth() / $imageSize->getHeight()) >= ($size->getWidth() / $size->getHeight())) { | |
$newImageSize = $imageSize->heighten($size->getHeight()); | |
} else { | |
$newImageSize = $imageSize->widen($size->getWidth()); | |
} | |
$imageForThumbnail = $image->resize($newImageSize); | |
} | |
} | |
$thumbnail = $this->resizeInPlace($imageForThumbnail, $size, $thumbnailMode); | |
unset($imageForThumbnail); | |
$thumbnailPath = $type->getFilePath($this); | |
$thumbnailFormat = $app->make(ThumbnailFormatService::class)->getFormatForFile($this); | |
$mimetype = $bitmapFormat->getFormatMimeType($thumbnailFormat); | |
$thumbnailOptions = $bitmapFormat->getFormatImagineSaveOptions($thumbnailFormat); | |
$filesystem->write( | |
$thumbnailPath, | |
$thumbnail->get($thumbnailFormat, $thumbnailOptions), | |
[ | |
'visibility' => AdapterInterface::VISIBILITY_PUBLIC, | |
'mimetype' => $mimetype, | |
] | |
); | |
$app['director']->dispatch('on_thumbnail_generate', | |
new \Concrete\Core\File\Event\ThumbnailGenerate($thumbnailPath, $type) | |
); | |
if ($type->getHandle() == $config->get('concrete.icons.file_manager_listing.handle') && !$this->fvHasListingThumbnail) { | |
$this->fvHasListingThumbnail = true; | |
$this->save(); | |
} | |
if ($type->getHandle() == $config->get('concrete.icons.file_manager_detail.handle') && !$this->fvHasDetailThumbnail) { | |
$this->fvHasDetailThumbnail = true; | |
$this->save(); | |
} | |
unset($image); | |
unset($size); | |
unset($thumbnail); | |
unset($filesystem); | |
} | |
/** | |
* This function is a copy of the core thumbnail() function, | |
* modified to allow thumbnailing without making a copy in memory first as it is not always needed depending on the context. | |
* | |
* @param ImageInterface $image The image to be resized | |
* @param Box $size The size of the image | |
* @param string $mode | |
* @param string $filter | |
* | |
* @throws InvalidArgumentException | |
* | |
* @return ImageInterface | |
*/ | |
public function resizeInPlace(ImageInterface $image, Box $size, $mode = ImageInterface::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED) | |
{ | |
if ($mode !== ImageInterface::THUMBNAIL_INSET && | |
$mode !== ImageInterface::THUMBNAIL_OUTBOUND) { | |
throw new InvalidArgumentException('Invalid mode specified'); | |
} | |
$imageSize = $image->getSize(); | |
$ratios = [ | |
$size->getWidth() / $imageSize->getWidth(), | |
$size->getHeight() / $imageSize->getHeight(), | |
]; | |
$image->strip(); | |
// if target width is larger than image width | |
// AND target height is longer than image height | |
if ($size->contains($imageSize)) { | |
return $image; | |
} | |
if ($mode === ImageInterface::THUMBNAIL_INSET) { | |
$ratio = min($ratios); | |
} else { | |
$ratio = max($ratios); | |
} | |
if ($mode === ImageInterface::THUMBNAIL_OUTBOUND) { | |
if (!$imageSize->contains($size)) { | |
$size = new Box( | |
min($imageSize->getWidth(), $size->getWidth()), | |
min($imageSize->getHeight(), $size->getHeight()) | |
); | |
} else { | |
$imageSize = $image->getSize()->scale($ratio); | |
$image->resize($imageSize, $filter); | |
} | |
$image->crop(new Point( | |
max(0, round(($imageSize->getWidth() - $size->getWidth()) / 2)), | |
max(0, round(($imageSize->getHeight() - $size->getHeight()) / 2)) | |
), $size); | |
} else { | |
if (!$imageSize->contains($size)) { | |
$imageSize = $imageSize->scale($ratio); | |
$image->resize($imageSize, $filter); | |
} else { | |
$imageSize = $image->getSize()->scale($ratio); | |
$image->resize($imageSize, $filter); | |
} | |
} | |
return $image; | |
} | |
/** | |
* Import an existing file as a thumbnail type version. | |
* | |
* @param \Concrete\Core\File\Image\Thumbnail\Type\Version $version | |
* @param string $path | |
*/ | |
public function importThumbnail(ThumbnailTypeVersion $version, $path) | |
{ | |
$app = Application::getFacadeApplication(); | |
$config = $app->make('config'); | |
$thumbnailPath = $version->getFilePath($this); | |
$filesystem = $this->getFile() | |
->getFileStorageLocationObject() | |
->getFileSystemObject(); | |
try { | |
if ($filesystem->has($thumbnailPath)) { | |
$filesystem->delete($thumbnailPath); | |
} | |
} catch (FileNotFoundException $e) { | |
} | |
$fileContents = file_get_contents($path); | |
$mimeType = Util::guessMimeType($path, $fileContents); | |
$filesystem->write( | |
$thumbnailPath, | |
$fileContents, | |
[ | |
'visibility' => AdapterInterface::VISIBILITY_PUBLIC, | |
'mimetype' => $mimeType, | |
] | |
); | |
if ($version->getHandle() == $config->get('concrete.icons.file_manager_listing.handle')) { | |
$this->fvHasListingThumbnail = true; | |
} | |
if ($version->getHandle() == $config->get('concrete.icons.file_manager_detail.handle')) { | |
$this->fvHasDetailThumbnail = true; | |
} | |
$this->save(); | |
} | |
/** | |
* Get the URL of a thumbnail type. | |
* If the thumbnail is smaller than the image (or if the file does not satisfy the Conditional Thumbnail criterias) you'll get the URL of the image itself. | |
* | |
* Please remark that the path is resolved using the default core path resolver: avoid using this method when you have access to the resolver instance. | |
* | |
* @param \Concrete\Core\File\Image\Thumbnail\Type\Version|string $type the thumbnail type version (or its handle) | |
* | |
* @return string|null return NULL if the thumbnail does not exist and the file storage location is invalid | |
* | |
* @example /application/files/thumbnails/file_manager_listing/0000/0000/0000/file.png | |
*/ | |
public function getThumbnailURL($type) | |
{ | |
$app = Application::getFacadeApplication(); | |
$path = null; | |
if (!($type instanceof ThumbnailTypeVersion)) { | |
$type = ThumbnailTypeVersion::getByHandle($type); | |
} | |
if ($type !== null) { | |
$imageWidth = (int) $this->getAttribute('width'); | |
$imageHeight = (int) $this->getAttribute('height'); | |
$file = $this->getFile(); | |
if ($type->shouldExistFor($imageWidth, $imageHeight, $file)) { | |
$path_resolver = $app->make(Resolver::class); | |
$path = $path_resolver->getPath($this, $type); | |
} | |
} | |
if (!$path) { | |
$url = $this->getURL(); | |
$path = $url ? (string) $url : null; | |
} | |
return $path; | |
} | |
/** | |
* Get the list of all the thumbnails. | |
* | |
* @throws \Concrete\Core\File\Exception\InvalidDimensionException | |
* | |
* @return \Concrete\Core\File\Image\Thumbnail\Thumbnail[] | |
*/ | |
public function getThumbnails() | |
{ | |
$thumbnails = []; | |
$imageWidth = (int) $this->getAttribute('width'); | |
$imageHeight = (int) $this->getAttribute('height'); | |
if ($imageWidth < 1 || $imageHeight < 1) { | |
throw new InvalidDimensionException($this->getFile(), $this, t('Invalid dimensions.')); | |
} | |
$types = Type::getVersionList(); | |
$file = $this->getFile(); | |
foreach ($types as $type) { | |
if ($type->shouldExistFor($imageWidth, $imageHeight, $file)) { | |
$thumbnailPath = $type->getFilePath($this); | |
$location = $file->getFileStorageLocationObject(); | |
$configuration = $location->getConfigurationObject(); | |
$filesystem = $location->getFileSystemObject(); | |
if ($filesystem->has($thumbnailPath)) { | |
$thumbnails[] = new Thumbnail($type, $configuration->getPublicURLToFile($thumbnailPath)); | |
} | |
} | |
} | |
return $thumbnails; | |
} | |
/** | |
* Get the HTML that renders the thumbnail for the details (a generic type icon if the thumbnail does not exist). | |
* Return the thumbnail for an image or a generic type icon for a file. | |
* | |
* @return string | |
*/ | |
public function getDetailThumbnailImage() | |
{ | |
if ($this->fvHasDetailThumbnail) { | |
$app = Application::getFacadeApplication(); | |
$config = $app->make('config'); | |
$type = Type::getByHandle($config->get('concrete.icons.file_manager_detail.handle')); | |
$result = '<img src="' . $this->getThumbnailURL($type->getBaseVersion()) . '"'; | |
if ($config->get('concrete.file_manager.images.create_high_dpi_thumbnails')) { | |
$result .= ' data-at2x="' . $this->getThumbnailURL($type->getDoubledVersion()) . '"'; | |
} | |
$result .= ' />'; | |
} else { | |
$result = $this->getTypeObject()->getThumbnail(); | |
} | |
return $result; | |
} | |
/** | |
* Get the HTML that renders the thumbnail for the file listing (a generic types icon if the thumbnail does not exist). | |
* | |
* @return string | |
*/ | |
public function getListingThumbnailImage() | |
{ | |
if ($this->fvHasListingThumbnail) { | |
$app = Application::getFacadeApplication(); | |
$config = $app->make('config'); | |
$type = Type::getByHandle($config->get('concrete.icons.file_manager_listing.handle')); | |
$result = '<img class="ccm-file-manager-list-thumbnail" src="' . $this->getThumbnailURL($type->getBaseVersion()) . '"'; | |
if ($config->get('concrete.file_manager.images.create_high_dpi_thumbnails')) { | |
$result .= ' data-at2x="' . $this->getThumbnailURL($type->getDoubledVersion()) . '"'; | |
} | |
$result .= ' />'; | |
} else { | |
return $this->getTypeObject()->getThumbnail(); | |
} | |
return $result; | |
} | |
/** | |
* Delete the thumbnail for a specific thumbnail type version. | |
* | |
* @param \Concrete\Core\File\Image\Thumbnail\Type\Version|string $type the thumbnail type version (or its handle) | |
*/ | |
public function deleteThumbnail($type) | |
{ | |
$app = Application::getFacadeApplication(); | |
$config = $app->make('config'); | |
if (!($type instanceof ThumbnailTypeVersion)) { | |
$type = ThumbnailTypeVersion::getByHandle($type); | |
} | |
$fsl = $this->getFile()->getFileStorageLocationObject()->getFileSystemObject(); | |
$path = $type->getFilePath($this); | |
try { | |
if ($fsl->has($path)) { | |
$fsl->delete($path); | |
$app['director']->dispatch('on_thumbnail_delete', | |
new \Concrete\Core\File\Event\ThumbnailDelete($path, $type) | |
); | |
} | |
} catch (FileNotFoundException $e) { | |
} | |
if ($type->getHandle() == $config->get('concrete.icons.file_manager_listing.handle') && $this->fvHasListingThumbnail) { | |
$this->fvHasListingThumbnail = false; | |
$this->save(); | |
} | |
if ($type->getHandle() == $config->get('concrete.icons.file_manager_detail.handle') && $this->fvHasDetailThumbnail) { | |
$this->fvHasDetailThumbnail = false; | |
$this->save(); | |
} | |
} | |
/** | |
* Move the thumbnail of a specific thumbnail type version to a new storage location. | |
* | |
* @param \Concrete\Core\File\Image\Thumbnail\Type\Version|string $type the thumbnail type version (or its handle) | |
* @param StorageLocation $location The destination storage location | |
*/ | |
public function updateThumbnailStorageLocation($type, StorageLocation $location) | |
{ | |
if (!($type instanceof ThumbnailTypeVersion)) { | |
$type = ThumbnailTypeVersion::getByHandle($type); | |
} | |
$fsl = $this->getFile()->getFileStorageLocationObject()->getFileSystemObject(); | |
$path = $type->getFilePath($this); | |
$manager = new MountManager([ | |
'current' => $fsl, | |
'new' => $location->getFileSystemObject(), | |
]); | |
try { | |
$manager->move('current://' . $path, 'new://' . $path); | |
} catch (FileNotFoundException $e) { | |
} | |
} | |
/** | |
* Copy the thumbnail of a specific thumbnail type version from another file version (useful for instance when duplicating a file). | |
* | |
* @param \Concrete\Core\File\Image\Thumbnail\Type\Version|string $type the thumbnail type version (or its handle) | |
* @param Version $source The File Version instance to copy the thumbnail from | |
*/ | |
public function duplicateUnderlyingThumbnailFiles($type, Version $source) | |
{ | |
if (!($type instanceof ThumbnailTypeVersion)) { | |
$type = ThumbnailTypeVersion::getByHandle($type); | |
} | |
$new = $this->getFile()->getFileStorageLocationObject()->getFileSystemObject(); | |
$current = $source->getFile()->getFileStorageLocationObject()->getFileSystemObject(); | |
$newPath = $type->getFilePath($this); | |
$currentPath = $type->getFilePath($source); | |
$manager = new MountManager([ | |
'current' => $current, | |
'new' => $new, | |
]); | |
try { | |
$manager->copy('current://' . $currentPath, 'new://' . $newPath); | |
} catch (FileNotFoundException $e) { | |
} | |
} | |
/** | |
* Get a representation of this Version instance that's easily serializable. | |
* | |
* @return stdClass A \stdClass instance with all the information about a file (including permissions) | |
*/ | |
public function getJSONObject() | |
{ | |
$app = Application::getFacadeApplication(); | |
$urlResolver = $app->make(ResolverManagerInterface::class); | |
$r = new stdClass(); | |
$fp = new Permissions($this->getFile()); | |
$r->canCopyFile = $fp->canCopyFile(); | |
$r->canEditFileProperties = $fp->canEditFileProperties(); | |
$r->canEditFilePermissions = $fp->canEditFilePermissions(); | |
$r->canDeleteFile = $fp->canDeleteFile(); | |
$r->canReplaceFile = $fp->canEditFileContents(); | |
$r->canEditFileContents = $fp->canEditFileContents(); | |
$r->canViewFileInFileManager = $fp->canRead(); | |
$r->canRead = $fp->canRead(); | |
$r->canViewFile = $this->canView(); | |
$r->canEditFile = $this->canEdit(); | |
$r->url = $this->getURL(); | |
$r->urlInline = (string) $urlResolver->resolve(['/download_file', 'view_inline', $this->getFileID()]); | |
$r->urlDownload = (string) $urlResolver->resolve(['/download_file', 'view', $this->getFileID()]); | |
$r->title = $this->getTitle(); | |
$r->genericTypeText = $this->getGenericTypeText(); | |
$r->description = $this->getDescription(); | |
$r->fileName = $this->getFileName(); | |
$r->resultsThumbnailImg = $this->getListingThumbnailImage(); | |
$r->fID = $this->getFileID(); | |
$r->treeNodeMenu = new Menu($this->getfile()); | |
return $r; | |
} | |
/** | |
* @deprecated Use buildForceDownloadResponse | |
*/ | |
public function forceDownload() | |
{ | |
$app = Application::getFacadeApplication(); | |
$response = $this->buildForceDownloadResponse(); | |
$response->prepare($app->make(Request::class)); | |
session_write_close(); | |
ob_end_clean(); | |
$response->send(); | |
$app->shutdown(); | |
exit; | |
} | |
/** | |
* @deprecated | |
* | |
* @param int $level | |
* | |
* @return bool | |
*/ | |
public function hasThumbnail($level) | |
{ | |
switch ($level) { | |
case 1: | |
return $this->fvHasListingThumbnail; | |
case 2: | |
return $this->fvHasDetailThumbnail; | |
} | |
return false; | |
} | |
/** | |
* @deprecated use refreshThumbnails(true) instead | |
* | |
* @return bool | |
*/ | |
public function rescanThumbnails() | |
{ | |
return $this->refreshThumbnails(true); | |
} | |
/** | |
* Save the instance changes. | |
* | |
* @param bool $flush Flush the EM cache? | |
*/ | |
protected function save($flush = true) | |
{ | |
$app = Application::getFacadeApplication(); | |
$em = $app->make(EntityManagerInterface::class); | |
$em->persist($this); | |
if ($flush) { | |
$em->flush(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment