fsi-open / files

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Convert file from URL to FSi\Component\Files\UploadedWebFile

pawloaka opened this issue · comments

Hello again,

My User entity looks like this:

class User
{
    private int $id;

    private ?WebFile $cover;

    private string $coverPath;

    public function __construct(?WebFile $cover)
    {
        $this->cover = $cover;
    }

    public function setCover(?WebFile $cover): void
    {
        $this->cover = $cover;
    }

    public function getCover(): ?WebFile
    {
        return $this->cover;
    }
}

And controller which is suitable for creating user:

...
use FSi\Component\Files\Upload\FileFactory;
use FSi\Component\Files\UploadedWebFile;
...

class StartController extends AbstractController
{
    private FileFactory $fileFactory;

    public function __construct(FileFactory $fileFactory)
    {
        $this->fileFactory = $fileFactory;
    }

    public function __invoke(ServerRequestInterface $request): Response
    {
        $urlToFile = 'https://miro.medium.com/max/1838/1*MI686k5sDQrISBM6L8pf5A.jpeg';

        /** @var UploadedWebFile $file */
        $file = $this->convertUrlFileToUploadedWebFile($urlToFile);
        $book = new User($file);
        $this->em->persist($user);
        $this->em->flush();
		
        return $this->json([]);
    }

    private function convertUrlFileToUploadedWebFile(string $url): UploadedWebFile
    {
        //HERE How to convert file from url to UploadedWebFile 
    }
}

And now my question is how the method convertUrlFileToUploadedWebFile should look like for converting a file from URL to UploadedWebFile?

Thanks in advance!

Or it would be awesome if we can do something like this:

...
    private function convertUrlFileToUploadedWebFile(string $url): UploadedWebFile
    {
        return $this->fileFactory->createFromPath($url);
    }
...

This is how you would go about it

<?php

declare(strict_types=1);

namespace Your\NamespacePath;

use finfo;
use FSi\Component\Files\Upload\FileFactory;
use FSi\Component\Files\UploadedWebFile;
use Psr\Http\Message\StreamFactoryInterface;
use const FILEINFO_MIME_TYPE;
use function array_key_exists;
use function basename;
use function file_get_contents;
use function is_string;
use function mb_strlen;
use function trim;

final class Uploader
{
    private FileFactory $fileFactory;
    private StreamFactoryInterface $streamFactory;
    private ?finfo $fileinfo = null;

    public function __construct(FileFactory $fileFactory, StreamFactoryInterface $streamFactory)
    {
        $this->fileFactory = $fileFactory;
        $this->streamFactory = $streamFactory;
    }

    public function __invoke(string $fileUri): ?UploadedWebFile
    {
        $fileContents = file_get_contents($fileUri);
        if (false === is_string($fileContents) || 0 === mb_strlen(trim($fileContents))) {
            return null;
        }

        $mimeType = $this->getMimeType($fileContents);
        if (null === $mimeType) {
            return null;
        }

        $name = $this->getBasenameFromUri($fileUri);
        if (null === $name || 0 === mb_strlen(trim($name))) {
            return null;
        }

        $stream = $this->streamFactory->createStream($fileContents);
        $file = $this->fileFactory->create(
            $stream,
            $name,
            $mimeType,
            $stream->getSize() ?? 0,
            UPLOAD_ERR_OK
        );

        if (0 === $file->getSize()) {
            return null;
        }

        return $file;
    }

    private function getBasenameFromUri(string $uri): ?string
    {
        $uriInfo = parse_url($uri);
        if (false === is_array($uriInfo) || false === array_key_exists('path', $uriInfo)) {
            return null;
        }

        $path = $uriInfo['path'];
        if (0 === mb_strlen(trim($path))) {
            return null;
        }

        return basename($uriInfo['path']);
    }

    private function getMimeType(string $source): ?string
    {
        $buffer = $this->getFileInfo()->buffer($source);
        return true === is_string($buffer) ? $buffer : null;
    }

    private function getFileInfo(): finfo
    {
        if (null === $this->fileinfo) {
            $this->fileinfo = new finfo(FILEINFO_MIME_TYPE);
        }

        return $this->fileinfo;
    }
}

We'll try to add something like this to the library, but we need to think it through a bit so we won't have to change it 15 times afterwards :P

Thanks @szymach

We'll try to add something like this to the library, but we need to think it through a bit so we won't have to change it 15 times afterwards :P

Why not just copy-paste code in your reply? I mean what could change 15 times? It is almost the same functionality as creating the file fromPath.

@pawloaka ah man sorry, I somehow missed your reply. 15 times was a hyperbole, perhaps the code above is perfectly fine, perhaps we should consider some edge case and/or user experience. We were not working on the library at the moment you wrote, so I just gave you some code that would (should) work and explained why it is not currently part of the code base. We will probably update it sooner than later, so don't worry.

You can now use FileFactory::createFromUri to create files form URL