<?php declare(strict_types=1); /* * Copyright (C) 2015-2017 IRSTEA * All rights reserved. */ namespace Irstea\FileUploadBundle\Entity\Repository; use DateTime; use Doctrine\ORM\EntityRepository; use Gaufrette\Filesystem; use Gaufrette\StreamMode; use InvalidArgumentException; use Irstea\FileUploadBundle\Entity\UploadedFile; use Irstea\FileUploadBundle\Event\FileUploadCompleteEvent; use Irstea\FileUploadBundle\Exception\RejectedFileException; use Irstea\FileUploadBundle\FileUploadEvents; use Irstea\FileUploadBundle\Model\FileManagerInterface; use Irstea\FileUploadBundle\Model\UploadedFileInterface; use Psr\Log\LoggerAwareTrait; use Psr\Log\LogLevel; use Rhumsaa\Uuid\Uuid; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** * Class UploadedFileRepository. */ class UploadedFileRepository extends EntityRepository implements FileManagerInterface { use LoggerAwareTrait; /** * @var Filesystem */ protected $filesystem; /** * @var EventDispatcher */ protected $eventDispatcher; /** * @param Filesystem $filesystem */ public function setFilesystem(Filesystem $filesystem) { $this->filesystem = $filesystem; } /** * @param EventDispatcherInterface $eventDispatcher */ public function setEventDispatcher(EventDispatcherInterface $eventDispatcher) { $this->eventDispatcher = $eventDispatcher; } /** * @param string $filename * @param int $size * @param string $mimeType * @param null $lastModified * * @return UploadedFile */ public function create($filename, $size, $mimeType, $lastModified = null) { $file = new UploadedFile(); $file ->setFilesystem($this->filesystem) ->setDisplayName($filename) ->setMetadata( [ 'client' => [ 'filename' => $filename, 'size' => $size, 'mimeType' => $mimeType, 'lastModified' => $lastModified, ], ] ); $this->_em->persist($file); $this->_em->flush(); $this->log(LogLevel::INFO, 'File created', ['file' => $file]); return $file; } /** * @param UploadedFileInterface $original * * @return UploadedFile */ public function duplicate(UploadedFileInterface $original) { if (!$original->isValid()) { throw new InvalidArgumentException('Impossible de dupliquer le fichier ' . $original->getId() . ' car il est invalide !'); } $new = new UploadedFile(); $metadata = $original->getMetadata(); if (!isset($metadata['duplicateOf'])) { $metadata['duplicateOf'] = [$original->getId()]; } else { array_unshift($metadata['duplicateOf'], $original->getId()); } $new ->setFilesystem($this->filesystem) ->setMetadata($metadata) ->setDisplayName($original->getDisplayName()) ->setDescription($original->getDescription()) ->setMimeType($original->getMimeType()) ->setChecksum($original->getChecksum()) ->setSize($original->getSize()); $stream = $this->filesystem->createStream($new->getPath()); $stream->open(new StreamMode('cb')); $original->copyTo($stream->cast(STREAM_CAST_AS_STREAM)); $stream->close(); $this->_em->persist($new); return $new; } /** * @param UploadedFileInterface $file */ public function delete(UploadedFileInterface $file) { $this->_em->remove($file); $this->_em->flush(); $this->log(LogLevel::INFO, 'File deleted', ['file' => $file]); } /** * @param string $uuid */ public function get($uuid) { if (!$uuid) { return null; } if (!is_string($uuid) || !Uuid::isValid($uuid)) { throw new InvalidArgumentException(sprintf('Identifiant invalide: %s', (string) $uuid)); } return $this->findOneById($uuid); } /** * @param UploadedFileInterface $file */ public function completed(UploadedFileInterface $file) { $path = $file->getPath(); $filesystem = $this->filesystem; $file ->setChecksum($filesystem->checksum($path)) ->setSize($filesystem->size($path)) ->setMimeType($filesystem->mimeType($path)) ->setEtat(UploadedFileInterface::ETAT_ORPHELIN); $this->_em->persist($file); try { $this->eventDispatcher->dispatch(FileUploadEvents::UPLOAD_COMPLETE, new FileUploadCompleteEvent($file)); $this->_em->flush(); $this->log(LogLevel::INFO, 'File completed', ['file' => $file]); } catch (RejectedFileException $ex) { $file->setEtat(UploadedFileInterface::ETAT_REJETE); $this->_em->flush(); $this->log(LogLevel::WARNING, 'File rejected', ['file' => $file, 'exception' => $ex]); throw $ex; } } /** * @param string $level * @param string $message * @param array $context */ protected function log($level, $message, array $context = []) { if (null !== $this->logger) { $this->logger->log($level, $message, $context); } } /** * @return array */ public function findGarbage() { $files = $this->findBy(['etat' => [UploadedFileInterface::ETAT_EN_COURS, UploadedFileInterface::ETAT_ORPHELIN]]); $limit = new DateTime('now'); $limit->modify('- 1 hour'); return array_filter( $files, function (UploadedFileInterface $file) use ($limit) { $mtime = $file->getLastModified(); return $mtime === null || $mtime < $limit; } ); } /** * @return array */ public function findFilesToValidate() { return $this->findBy(['etat' => [UploadedFileInterface::ETAT_ORPHELIN, UploadedFileInterface::ETAT_NORMAL]]); } }