Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
digitalascetic/file / EventListener / FileEntitySubscriber.php
Size: Mime:
<?php

namespace DigitalAscetic\FileBundle\EventListener;

use DigitalAscetic\FileBundle\Entity\File\FileEntity;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Events;
use Doctrine\ORM\UnitOfWork;
use Doctrine\Common\Util\ClassUtils;
use Gaufrette\Filesystem;
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
use Psr\Log\LoggerInterface;
use Symfony\Component\Config\Definition\Exception\Exception;

/**
 * Class FileEntitySubscriber
 * @package DigitalAscetic\FileBundle\EventListener
 */
class FileEntitySubscriber implements EventSubscriber
{
    /**
     * @var string
     */
    private ?string $oldPath = null;

    /**
     * @var array
     */
    private $fileEntities;

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var CacheManager $cacheManager
     */
    private $cacheManager;

    /** @var Filesystem */
    private $publicFilesystem;

    /** @var Filesystem */
    private $privateFilesystem;

    /**
     * FileEntitySubscriber constructor.
     *
     * @param Filesystem $publicFilesystem
     * @param Filesystem $privateFilesystem
     * @param array $fileEntities
     * @param LoggerInterface $logger
     * @param CacheManager $cacheManager
     */
    public function __construct(Filesystem $publicFilesystem, Filesystem $privateFilesystem, array $fileEntities, LoggerInterface $logger, CacheManager $cacheManager)
    {
        $this->publicFilesystem = $publicFilesystem;
        $this->privateFilesystem = $privateFilesystem;
        $this->fileEntities = $fileEntities;
        $this->logger = $logger;
        $this->cacheManager = $cacheManager;
    }

    /**
     * @return array
     */
    public function getSubscribedEvents(): array
    {
        return array(
            Events::onFlush
        );
    }

    /**
     * @param OnFlushEventArgs $args
     */
    public function onFlush(OnFlushEventArgs $args)
    {
        $em = $args->getObjectManager();
        $uow = $em->getUnitOfWork();

        foreach ($uow->getScheduledEntityInsertions() as $entity) {
            if ($this->isFileEntity($entity)) {
                $this->handleSyncableFileEntity($entity, $em, $uow);
            }
        }

        foreach ($uow->getScheduledEntityUpdates() as $entity) {
            if ($this->isFileEntity($entity)) {
                $this->handleSyncableFileEntity($entity, $em, $uow);
            }
        }

        foreach ($uow->getScheduledEntityDeletions() as $entity) {
            if ($this->isFileEntity($entity)) {
                $this->handleRemoveFileEntity($entity, $em);
            }
        }

    }

    private function handleSyncableFileEntity(FileEntity $fileEntity, EntityManagerInterface $em, UnitOfWork $uow)
    {
        $refClass = ClassUtils::getClass($fileEntity);
        $meta = $em->getClassMetadata($refClass);

        if ($fileEntity->isSyncWithCanonicalPath()) {
            $this->syncPathWithCanonicalPath($fileEntity);

            if ($uow->isInIdentityMap($fileEntity)) {
                $uow->recomputeSingleEntityChangeSet($meta, $fileEntity);
            } else {
                $em->persist($fileEntity);
                $uow->computeChangeSet($meta, $fileEntity);
            }
        }

        if ($this->oldPath) {
            $this->renameFileEntity($fileEntity, $em);
        }
    }

    private function handleRemoveFileEntity(FileEntity $fileEntity, EntityManagerInterface $em)
    {
        /** @var Filesystem $publicFileSystem */
        $filesystem = null;

        if ($fileEntity->getFile()->getPublic()) {
            $filesystem = $this->publicFilesystem;
        } else {
            $filesystem = $this->privateFilesystem;
        }

        if ($fileEntity->isSyncWithCanonicalPath()) {
            $canonicalPath = $fileEntity->getCanonicalPath();

            try {
                if ($filesystem->has($canonicalPath)) {
                    $filesystem->delete($canonicalPath);
                }

                foreach ($fileEntity->getRelatedPaths() as $relatedPath) {
                    if ($filesystem->has($relatedPath)) {
                        $filesystem->delete($relatedPath);
                    }
                }

            } catch (Exception $e) {
                $em->close();
                $em->getConnection()->rollback();
                throw $e;
            }

            //We need to transform uri to path for correct check cacheManage store cached
            // eg: pub/fr/1/agency/1/realestate/234232/images/131331312.jpg
            $path = parse_url($fileEntity->getFile()->getUri())['path'];
            //Remove first / from path
            $path = ltrim($path, '/');

            $this->cacheManager->remove($path);
        }
    }

    private function stripInitialSlash($path)
    {
        if (str_starts_with($path, '/')) {
            $path = substr($path, 1);
        }

        return $path;
    }

    private function syncPathWithCanonicalPath(FileEntity $fileEntity)
    {
        $canonicalPath = $this->stripInitialSlash($fileEntity->getCanonicalPath());
        $path = $this->stripInitialSlash($fileEntity->getFile()->getPath());
        if ($canonicalPath != $path) {
            // Strip initial "/" as Gaufrette wants the source key relative to root path
            $this->oldPath = $path;
            $fileEntity->getFile()->setPath($canonicalPath);
        }
    }

    private function isManagedFileEntity($entity): bool
    {
        return ($this->isFileEntity($entity));
    }

    private function isFileEntity($entity): bool
    {
        return ($entity instanceof FileEntity);
    }

    private function renameFileEntity(FileEntity $fileEntity, EntityManagerInterface $em)
    {
        if ($fileEntity->getFile()->getPublic()) {
            $filesystem = $this->publicFilesystem;
        } else {
            $filesystem = $this->privateFilesystem;
        }

        try {
            $canonicalPath = $fileEntity->getCanonicalPath();

            if ($this->oldPath && $filesystem->has($this->oldPath)) {
                $filesystem->rename($this->oldPath, $canonicalPath, 1);
            }
        } catch (Exception $e) {
            $em->close();
            $em->getConnection()->rollback();
            throw $e;
        }

        $this->oldPath = null;
    }

}