chrisbryan17's picture
Upload folder using huggingface_hub
d2897cd verified
<?php
namespace Mautic\AssetBundle\Entity;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Mautic\ApiBundle\Serializer\Driver\ApiMetadataDriver;
use Mautic\CoreBundle\Doctrine\Mapping\ClassMetadataBuilder;
use Mautic\CoreBundle\Entity\FormEntity;
use Mautic\CoreBundle\Helper\FileHelper;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Mapping\ClassMetadata;
class Asset extends FormEntity
{
/**
* @var int
*/
private $id;
/**
* @var string
*/
private $title;
/**
* @var string|null
*/
private $description;
/**
* @var string|null
*/
private $storageLocation = 'local';
/**
* @var string|null
*/
private $path;
/**
* @var string|null
*/
private $remotePath;
/**
* @var string|null
*/
private $originalFileName;
/**
* @var File
*/
private $file;
/**
* Holds upload directory.
*/
private $uploadDir;
/**
* Holds max size of uploaded file.
*/
private $maxSize;
/**
* Temporary location when asset file is beeing updated.
* We need to keep the old file till we are sure the new
* one is stored correctly.
*/
private $temp;
/**
* Temporary ID used for file upload and validations
* before the actual ID is known.
*/
private $tempId;
/**
* Temporary file name used for file upload and validations
* before the actual ID is known.
*/
private $tempName;
/**
* @var string
*/
private $alias;
/**
* @var string
*/
private $language = 'en';
/**
* @var \DateTimeInterface|null
*/
private $publishUp;
/**
* @var \DateTimeInterface|null
*/
private $publishDown;
/**
* @var int
*/
private $downloadCount = 0;
/**
* @var int
*/
private $uniqueDownloadCount = 0;
/**
* @var int
*/
private $revision = 1;
/**
* @var \Mautic\CategoryBundle\Entity\Category|null
**/
private $category;
/**
* @var string|null
*/
private $extension;
/**
* @var string|null
*/
private $mime;
/**
* @var int|null
*/
private $size;
/**
* @var string|null
*/
private $downloadUrl;
/**
* @var bool|null
*/
private $disallow = true;
public static function loadMetadata(ORM\ClassMetadata $metadata): void
{
$builder = new ClassMetadataBuilder($metadata);
$builder->setTable('assets')
->setCustomRepositoryClass(AssetRepository::class)
->addIndex(['alias'], 'asset_alias_search');
$builder->addIdColumns('title');
$builder->addField('alias', 'string');
$builder->createField('storageLocation', 'string')
->columnName('storage_location')
->nullable()
->build();
$builder->createField('path', 'string')
->nullable()
->build();
$builder->createField('remotePath', Types::TEXT)
->columnName('remote_path')
->nullable()
->build();
$builder->createField('originalFileName', Types::TEXT)
->columnName('original_file_name')
->nullable()
->build();
$builder->createField('language', 'string')
->columnName('lang')
->build();
$builder->addPublishDates();
$builder->createField('downloadCount', 'integer')
->columnName('download_count')
->build();
$builder->createField('uniqueDownloadCount', 'integer')
->columnName('unique_download_count')
->build();
$builder->addField('revision', 'integer');
$builder->addCategory();
$builder->createField('extension', 'string')
->nullable()
->build();
$builder->createField('mime', 'string')
->nullable()
->build();
$builder->createField('size', 'integer')
->nullable()
->build();
$builder->createField('disallow', 'boolean')
->nullable()
->build();
}
/**
* Prepares the metadata for API usage.
*/
public static function loadApiMetadata(ApiMetadataDriver $metadata): void
{
$metadata->setGroupPrefix('asset')
->addListProperties(
[
'id',
'title',
'alias',
'category',
'description',
]
)
->addProperties(
[
'language',
'publishUp',
'publishDown',
'downloadCount',
'uniqueDownloadCount',
'revision',
'extension',
'mime',
'size',
'downloadUrl',
'storageLocation',
'disallow',
]
)
->build();
}
/**
* Clone magic function.
*/
public function __clone()
{
$this->id = null;
parent::__clone();
}
/**
* Get id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Sets file.
*/
public function setFile(File $file = null): void
{
$this->file = $file;
// check if we have an old asset path
if (isset($this->path)) {
// store the old name to delete after the update
$this->temp = $this->path;
$this->path = null;
}
}
/**
* Get file.
*
* @return UploadedFile
*/
public function getFile()
{
// if file is not set, try to find it at temp folder
if ($this->isLocal() && empty($this->file)) {
$tempFile = $this->loadFile(true);
if ($tempFile) {
$this->setFile($tempFile);
}
}
return $this->file;
}
/**
* Set title.
*
* @param string $title
*
* @return Asset
*/
public function setTitle($title)
{
$this->isChanged('title', $title);
$this->title = $title;
return $this;
}
/**
* Get title.
*
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* @return mixed
*/
public function getExtension()
{
return $this->extension;
}
/**
* @param mixed $extension
*/
public function setExtension($extension): void
{
$this->extension = $extension;
}
/**
* @return mixed
*/
public function getMime()
{
return $this->mime;
}
/**
* @param mixed $mime
*/
public function setMime($mime): void
{
$this->mime = $mime;
}
/**
* Set originalFileName.
*
* @param string $originalFileName
*
* @return Asset
*/
public function setOriginalFileName($originalFileName)
{
$this->isChanged('originalFileName', $originalFileName);
$this->originalFileName = $originalFileName;
return $this;
}
/**
* Get originalFileName.
*
* @return string
*/
public function getOriginalFileName()
{
return $this->originalFileName;
}
/**
* Set storage location.
*
* @param string $storageLocation
*
* @return Asset
*/
public function setStorageLocation($storageLocation)
{
$this->isChanged('storageLocation', $storageLocation);
$this->storageLocation = $storageLocation;
return $this;
}
/**
* Get storage location.
*
* @return string
*/
public function getStorageLocation()
{
if (null === $this->storageLocation) {
$this->storageLocation = 'local';
}
return $this->storageLocation;
}
/**
* Set path.
*
* @param string $path
*
* @return Asset
*/
public function setPath($path)
{
$this->isChanged('path', $path);
$this->path = $path;
return $this;
}
/**
* Get path.
*
* @return string
*/
public function getPath()
{
return $this->path;
}
/**
* Set remote path.
*
* @param string $remotePath
*
* @return Asset
*/
public function setRemotePath($remotePath)
{
$this->isChanged('remotePath', $remotePath);
$this->remotePath = $remotePath;
return $this;
}
/**
* Get remote path.
*
* @return string
*/
public function getRemotePath()
{
return $this->remotePath;
}
/**
* Set alias.
*
* @param string $alias
*
* @return Asset
*/
public function setAlias($alias)
{
$this->isChanged('alias', $alias);
$this->alias = $alias;
return $this;
}
/**
* Get alias.
*
* @return string
*/
public function getAlias()
{
return $this->alias;
}
/**
* Set publishUp.
*
* @param \DateTime $publishUp
*
* @return Asset
*/
public function setPublishUp($publishUp)
{
$this->isChanged('publishUp', $publishUp);
$this->publishUp = $publishUp;
return $this;
}
/**
* Get publishUp.
*
* @return \DateTimeInterface
*/
public function getPublishUp()
{
return $this->publishUp;
}
/**
* Set publishDown.
*
* @param \DateTimeInterface $publishDown
*
* @return Asset
*/
public function setPublishDown($publishDown)
{
$this->isChanged('publishDown', $publishDown);
$this->publishDown = $publishDown;
return $this;
}
/**
* Get publishDown.
*
* @return \DateTimeInterface
*/
public function getPublishDown()
{
return $this->publishDown;
}
/**
* Set downloadCount.
*
* @param int $downloadCount
*
* @return Asset
*/
public function setDownloadCount($downloadCount)
{
$this->downloadCount = $downloadCount;
return $this;
}
/**
* Get downloadCount.
*
* @return int
*/
public function getDownloadCount()
{
return $this->downloadCount;
}
/**
* Set revision.
*
* @param int $revision
*
* @return Asset
*/
public function setRevision($revision)
{
$this->revision = $revision;
return $this;
}
/**
* Get revision.
*
* @return int
*/
public function getRevision()
{
return $this->revision;
}
/**
* Set language.
*
* @param string $language
*
* @return Asset
*/
public function setLanguage($language)
{
$this->isChanged('language', $language);
$this->language = $language;
return $this;
}
/**
* Get language.
*
* @return string
*/
public function getLanguage()
{
return $this->language;
}
/**
* Set category.
*
* @return Asset
*/
public function setCategory(\Mautic\CategoryBundle\Entity\Category $category = null)
{
$this->isChanged('category', $category);
$this->category = $category;
return $this;
}
/**
* Get category.
*
* @return \Mautic\CategoryBundle\Entity\Category
*/
public function getCategory()
{
return $this->category;
}
/**
* Set uniqueDownloadCount.
*
* @param int $uniqueDownloadCount
*
* @return Asset
*/
public function setUniqueDownloadCount($uniqueDownloadCount)
{
$this->uniqueDownloadCount = $uniqueDownloadCount;
return $this;
}
/**
* Get uniqueDownloadCount.
*
* @return int
*/
public function getUniqueDownloadCount()
{
return $this->uniqueDownloadCount;
}
public function setFileNameFromRemote(): void
{
$fileName = basename($this->getRemotePath());
$this->setOriginalFileName($fileName);
// set the asset title as original file name if title is missing
if (null === $this->getTitle()) {
$this->setTitle($fileName);
}
}
public function preUpload(): void
{
if (null !== $this->getFile()) {
// set the asset title as original file name if title is missing
if (null === $this->getTitle()) {
$this->setTitle($this->file->getClientOriginalName());
}
$filename = sha1(uniqid(mt_rand(), true));
$extension = $this->getFile()->guessExtension();
if (empty($extension)) {
// get it from the original name
$extension = pathinfo($this->originalFileName, PATHINFO_EXTENSION);
}
$this->path = $filename.'.'.$extension;
} elseif ($this->isRemote() && null !== $this->getRemotePath()) {
$this->setFileNameFromRemote();
}
}
public function upload(): void
{
// the file property can be empty if the field is not required
if (null === $this->getFile()) {
// check for the remote and set type data
if ($this->isRemote()) {
$this->setFileInfoFromFile();
}
return;
}
// move takes the target directory and then the
// target filename to move to
$this->getFile()->move($this->getUploadDir(), $this->path);
$filePath = $this->getUploadDir().'/'.$this->temp;
$this->setFileInfoFromFile();
// check if we have an old asset
if (isset($this->temp) && file_exists($filePath)) {
// delete the old asset
unlink($filePath);
// clear the temp asset path
$this->temp = null;
}
// Remove temporary folder and files
$fs = new Filesystem();
$fs->remove($this->getAbsoluteTempDir());
// clean up the file property as you won't need it anymore
$this->file = null;
}
/**
* Remove a file.
*/
public function setFileInfoFromFile(): void
{
// get some basic information about the file type
$fileInfo = $this->getFileInfo();
if (!is_array($fileInfo)) {
return;
}
// set the mime and extension column values
$this->setExtension($fileInfo['extension']);
$this->setMime($fileInfo['mime']);
$this->setSize($fileInfo['size']);
}
/**
* Remove a file.
*
* @param bool $temp >> regular uploaded file or temporary
*/
public function removeUpload($temp = false): void
{
if ($temp) {
$file = $this->getAbsoluteTempPath();
} else {
$file = $this->getAbsolutePath();
}
if ($file && file_exists($file)) {
unlink($file);
}
}
/**
* Returns absolute path to the file.
*
* @return string
*/
public function getAbsolutePath()
{
return null === $this->path
? null
: $this->getUploadDir().'/'.$this->path;
}
/**
* Returns absolute path to temporary file.
*
* @return string
*/
public function getAbsoluteTempPath()
{
return null === $this->tempId || null === $this->tempName
? null
: $this->getAbsoluteTempDir().'/'.$this->tempName;
}
/**
* Returns absolute path to temporary file.
*
* @return string
*/
public function getAbsoluteTempDir()
{
return null === $this->tempId
? null
: $this->getUploadDir().'/tmp/'.$this->tempId;
}
/**
* Returns absolute path to upload dir.
*
* @return string
*/
protected function getUploadDir()
{
if ($this->uploadDir) {
return $this->uploadDir;
}
return 'media/files';
}
/**
* Set uploadDir.
*
* @param string $uploadDir
*
* @return Asset
*/
public function setUploadDir($uploadDir)
{
$this->uploadDir = $uploadDir;
return $this;
}
/**
* Returns maximal uploadable size in bytes.
* If not set, 6000000 is default.
*
* @return string
*/
protected function getMaxSize()
{
if ($this->maxSize) {
return $this->maxSize;
}
return 6_000_000;
}
/**
* Set max size.
*
* @param string $maxSize
*
* @return Asset
*/
public function setMaxSize($maxSize)
{
$this->maxSize = $maxSize;
return $this;
}
/**
* Returns file extension.
*
* @return string
*/
public function getFileType()
{
if (!empty($this->extension) && empty($this->changes['originalFileName'])) {
return $this->extension;
}
if ($this->isRemote()) {
return pathinfo(parse_url($this->getRemotePath(), PHP_URL_PATH), PATHINFO_EXTENSION);
}
if (null === $this->loadFile()) {
return '';
}
return $this->loadFile()->guessExtension();
}
/**
* Returns some file info.
*
* @return array
*/
public function getFileInfo()
{
$fileInfo = [];
if ($this->isRemote()) {
$ch = curl_init($this->getRemotePath());
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_exec($ch);
// build an array of handy info
$fileInfo['mime'] = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
$fileInfo['extension'] = $this->getFileType();
$fileInfo['size'] = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
return $fileInfo;
}
if (null === $this->loadFile()) {
return '';
}
// return an array of file type info
$fileInfo['mime'] = $this->loadFile()->getMimeType();
$fileInfo['extension'] = $this->getFileType();
$fileInfo['size'] = $this->getSize(false, true);
return $fileInfo;
}
/**
* Returns file mime type.
*
* @return string
*/
public function getFileMimeType()
{
if ($this->isRemote()) {
$ch = curl_init($this->getRemotePath());
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_exec($ch);
return curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
}
if (null === $this->loadFile()) {
return '';
}
return $this->loadFile()->getMimeType();
}
/**
* Returns Font Awesome icon class based on file type.
*/
public function getIconClass(): string
{
$fileType = $this->getFileType();
// return missing file icon if file type is empty
if (!$fileType) {
return 'ri-prohibited-line';
}
$fileTypes = $this->getFileExtensions();
// Search for icon name by file extension.
foreach ($fileTypes as $icon => $extensions) {
if (in_array($fileType, $extensions)) {
return 'fa fa-file-'.$icon.'-o';
}
}
// File extension is unknown, display general file icon.
return 'ri-file-line';
}
/**
* Decides if an asset is image displayable by browser.
*/
public function isImage(): bool
{
$fileType = strtolower($this->getFileType());
if (!$fileType) {
return false;
}
$imageTypes = ['jpg', 'jpeg', 'png', 'gif'];
if (in_array($fileType, $imageTypes)) {
return true;
}
return false;
}
/**
* Returns array of common extensions.
*
* @return array<string, string[]>
*/
public function getFileExtensions(): array
{
return [
'excel' => [
'xlsx',
'xlsm',
'xlsb',
'xltx',
'xltm',
'xls',
'xlt',
],
'word' => [
'doc',
'docx',
'docm',
'dotx',
],
'pdf' => [
'pdf',
],
'audio' => [
'mp3',
],
'archive' => [
'zip',
'rar',
'iso',
'tar',
'gz',
'7z',
],
'image' => [
'jpg',
'jpeg',
'png',
'gif',
'ico',
'bmp',
'psd',
],
'text' => [
'txt',
'pub',
],
'code' => [
'php',
'js',
'json',
'yaml',
'xml',
'html',
'htm',
'sql',
],
'powerpoint' => [
'ppt',
'pptx',
'pptm',
'xps',
'potm',
'potx',
'pot',
'pps',
'odp',
],
'video' => [
'wmv',
'avi',
'mp4',
'mkv',
'mpeg',
],
];
}
/**
* Load the file object from it's path.
*
* @return File|null
*/
public function loadFile($temp = false)
{
if ($temp) {
$path = $this->getAbsoluteTempPath();
} else {
$path = $this->getAbsolutePath();
}
if (!$path || !file_exists($path)) {
return null;
}
try {
$file = new File($path);
} catch (FileNotFoundException) {
$file = null;
}
return $file;
}
/**
* Load content of the file from it's path.
*/
public function getFileContents(): string|bool
{
$path = $this->getFilePath();
return file_get_contents($path);
}
/**
* Get the path to the file; a URL if remote or full file path if local.
*
* @return string
*/
public function getFilePath()
{
return $this->isRemote() ? $this->getRemotePath() : $this->getAbsolutePath();
}
/**
* @return mixed
*/
public function getDescription()
{
return $this->description;
}
/**
* @param mixed $description
*/
public function setDescription($description): void
{
$this->description = $description;
}
public static function loadValidatorMetadata(ClassMetadata $metadata): void
{
// Add a constraint to manage the file upload data
$metadata->addConstraint(new Assert\Callback([self::class, 'validateFile']));
}
/**
* Validator to ensure proper data for the file fields.
*
* @param Asset $object Entity object to validate
* @param ExecutionContextInterface $context Context object
*/
public static function validateFile($object, ExecutionContextInterface $context): void
{
if ($object->isLocal()) {
$tempName = $object->getTempName();
$path = $object->getPath();
// If the object is stored locally, we should have file data
if ($object->isNew() && null === $tempName && null === $path) {
$context->buildViolation('mautic.asset.asset.error.missing.file')
->atPath('tempName')
->setTranslationDomain('validators')
->addViolation();
}
if (null === $object->getTitle()) {
$context->buildViolation('mautic.asset.asset.error.missing.title')
->atPath('title')
->setTranslationDomain('validators')
->addViolation();
}
// Unset any remote file data
$object->setRemotePath(null);
} elseif ($object->isRemote()) {
// If the object is stored remotely, we should have a remote path
if (null === $object->getRemotePath()) {
$context->buildViolation('mautic.asset.asset.error.missing.remote.path')
->atPath('remotePath')
->setTranslationDomain('validators')
->addViolation();
}
// Unset any local file data
$object->setPath(null);
}
}
/**
* Set temporary ID.
*
* @param string $tempId
*
* @return Asset
*/
public function setTempId($tempId)
{
$this->tempId = $tempId;
return $this;
}
/**
* Get temporary ID.
*
* @return string
*/
public function getTempId()
{
return $this->tempId;
}
/**
* Set temporary file name.
*
* @param string $tempName
*
* @return Asset
*/
public function setTempName($tempName)
{
$this->tempName = $tempName;
return $this;
}
/**
* Get temporary file name.
*
* @return string
*/
public function getTempName()
{
return $this->tempName;
}
/**
* @param bool $humanReadable
* @param bool $forceUpdate
* @param string $inUnit
*
* @return float|string
*/
public function getSize($humanReadable = true, $forceUpdate = false, $inUnit = '')
{
if (empty($this->size) || $forceUpdate) {
// Try to fetch it
if ($this->isRemote()) {
$ch = curl_init($this->getRemotePath());
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_exec($ch);
$this->setSize(round(curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD)));
}
if (null === $this->loadFile()) {
return 0;
}
$this->setSize(round($this->loadFile()->getSize()));
}
return ($humanReadable) ? static::convertBytesToHumanReadable($this->size, $inUnit) : $this->size;
}
/**
* @param mixed $size
*
* @return Asset
*/
public function setSize($size)
{
$this->size = $size;
return $this;
}
/**
* Get value from PHP configuration with special handling of -1.
*
* @param string $setting
* @param bool|true $convertToBytes
*/
public static function getIniValue($setting, $convertToBytes = true): int
{
$value = ini_get($setting);
if (-1 == $value || 0 === $value) {
return PHP_INT_MAX;
}
if ($convertToBytes) {
$value = FileHelper::convertPHPSizeToBytes($value);
}
return (int) $value;
}
/**
* @param string $unit
*/
public static function convertBytesToHumanReadable($size, $unit = ''): string
{
[$number, $unit] = self::convertBytesToUnit($size, $unit);
// Format number
$number = number_format($number, 2);
// Remove trailing .00
$number = str_contains($number, '.') ? rtrim(rtrim($number, '0'), '.') : $number;
return $number.' '.$unit;
}
/**
* @param string $unit
*/
public static function convertBytesToUnit($size, $unit = ''): array
{
$unit = strtoupper($unit);
if ((!$unit && $size >= 1 << 30) || 'GB' == $unit || 'G' == $unit) {
return [$size / (1 << 30), 'GB'];
}
if ((!$unit && $size >= 1 << 20) || 'MB' == $unit || 'M' == $unit) {
return [$size / (1 << 20), 'MB'];
}
if ((!$unit && $size >= 1 << 10) || 'KB' == $unit || 'K' == $unit) {
return [$size / (1 << 10), 'KB'];
}
// Add zero to remove useless .00
return [$size, 'bytes'];
}
/**
* @return string|null
*/
public function getDownloadUrl()
{
return $this->downloadUrl;
}
/**
* @param string|null $downloadUrl
*
* @return Asset
*/
public function setDownloadUrl($downloadUrl)
{
$this->downloadUrl = $downloadUrl;
return $this;
}
public function isLocal(): bool
{
return 'local' === $this->storageLocation;
}
public function isRemote(): bool
{
return 'remote' === $this->storageLocation;
}
/**
* @return bool
*/
public function getDisallow()
{
return $this->disallow;
}
/**
* @param mixed $disallow
*/
public function setDisallow($disallow): void
{
$this->disallow = $disallow;
}
}