Vich version : 1.15.0
Symfony version : 4.4.13PHP version : 7.4API Platform version : 2.5.7flysystem-bundle version : 1.5.0flysystem-aws-s3-v3 version : 1.0.28
When creating or updating the object containing a file on a remote repository, an error occurs because it tries to read the MimeType of the file with its path while the file is not present on the server . I don't get any error when using local storage.
the error
request.CRITICAL: Uncaught PHP Exception Symfony\Component\Mime\Exception\InvalidArgumentException: "The "5f5b6d18c6671164117604.png" file does not exist or is not readable." at /var/www/html/vendor/symfony/mime/FileinfoMimeTypeGuesser.php line 50 {"exception":"[object] (Symfony\\Component\\Mime\\Exception\\InvalidArgumentException(code: 0): The \"5f5b6d18c6671164117604.png\" file does not exist or is not readable. at /var/www/html/vendor/symfony/mime/FileinfoMimeTypeGuesser.php:50)"} []
inFileinfoMimeTypeGuesser.php
namespace Symfony\Component\Mime;use Symfony\Component\Mime\Exception\InvalidArgumentException;use Symfony\Component\Mime\Exception\LogicException;/** * Guesses the MIME type using the PECL extension FileInfo. * * @author Bernhard Schussek <bschussek@gmail.com> */class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface{....public function guessMimeType(string $path): ?string { if (!is_file($path) || !is_readable($path)) { throw new InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); } if (!$this->isGuesserSupported()) { throw new LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); } if (false === $finfo = new \finfo(FILEINFO_MIME_TYPE, $this->magicFile)) { return null; } $mimeType = $finfo->file($path); if ($mimeType && 0 === (\strlen($mimeType) % 2)) { $mimeStart = substr($mimeType, 0, \strlen($mimeType) >> 1); $mimeType = $mimeStart.$mimeStart === $mimeType ? $mimeStart : $mimeType; } return $mimeType; }}I know the file is sent to the repository because it can be recovered with GET request.
How to reproduceflysystem.yaml
flysystem: storages: uploads.storage.ovh: adapter: "aws" options: client: "Aws\S3\S3Client" bucket: "%env(OVH_BUCKET)%" uploads.storage.local: adapter: 'local' options: directory: "%kernel.project_dir%/var/storage/uploads" uploads.storage.memory: adapter: "memory"# switch with env uploads.storage: adapter: "lazy" options: source: "%env(APP_UPLOADS_SOURCE)%"vich_uploader.yaml:
vich_uploader: db_driver: orm storage: flysystem metadata: auto_detection: true mappings: userAvatar: upload_destination: uploads.storage namer: service: Vich\UploaderBundle\Naming\UniqidNamer delete_on_remove: true # determine whether to delete file upon removal of entity delete_on_update: true # determine wheter to delete the file upon update of entity inject_on_load: false productionCenterLogo: upload_destination: uploads.storage namer: service: Vich\UploaderBundle\Naming\UniqidNamer delete_on_remove: true delete_on_update: true inject_on_load: false donneurOrdreLogo: upload_destination: uploads.storage namer: service: Vich\UploaderBundle\Naming\UniqidNamer delete_on_remove: true delete_on_update: true inject_on_load: falseservice.yaml:
services: Aws\S3\S3Client: arguments: - version: 'latest' credentials: key: '%env(OVH_ACCESS_KEY_ID)%' secret: '%env(OVH_SECRET_ACCESS_KEY)%' endpoint: '%env(OVH_ENDPOINT)%' region: '%env(OVH_REGION)%' S3: version: '2006-03-01' endpoint_url: '%env(OVH_ENDPOINT)%' signature_version: 's3v4' addressing_style: 'virtual' S3API: endpoint_url: '%env(OVH_ENDPOINT)%'exemple of one entity:
<?phpnamespace App\Entity;use ApiPlatform\Core\Annotation\ApiResource;use Doctrine\ORM\Mapping as ORM;use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;use Symfony\Component\HttpFoundation\File\File;use Symfony\Component\Serializer\Annotation\Groups;use Symfony\Component\Validator\Constraints as Assert;use Vich\UploaderBundle\Mapping\Annotation as Vich;/** * @ORM\Entity(repositoryClass="App\Repository\UserAvatarRepository") * @ApiResource() * @Vich\Uploadable * @UniqueEntity(fields={"user"}, message="unique.userAvatar.user") */class UserAvatar extends FileUpload{ /** * @Assert\File( * maxSize = "1980k", * mimeTypes = { * "image/jpeg", * "image/png", * "image/svg+xml", * } * ) * @Assert\NotNull() * * @var File|null * @Groups({ * "file", * }) * @Vich\UploadableField( * mapping="userAvatar", * fileNameProperty="filePath", * size="imageSize", * originalName="originalName", * mimeType="mimeType", * dimensions="dimensions", * ) */ public $imageFile; /** * @ORM\OneToOne(targetEntity=User::class, inversedBy="avatar") * @ORM\JoinColumn(nullable=false, unique=true) */ private User $user; public function getUser(): User { return $this->user; } public function setUser(User $user): self { $this->user = $user; return $this; } /** * If manually uploading a file (i.e. not using Symfony Form) ensure an instance * of 'UploadedFile' is injected into this setter to trigger the update. If this * bundle's configuration parameter 'inject_on_load' is set to 'true' this setter * must be able to accept an instance of 'File' as the bundle will inject one here * during Doctrine hydration. * * @param File|\Symfony\Component\HttpFoundation\File\UploadedFile|null $imageFile */ public function setImageFile($imageFile = null): void { $this->imageFile = $imageFile; if (null !== $imageFile) { // It is required that at least one field changes if you are using doctrine // otherwise the event listeners won't be called and the file is lost $this->setUpdatedAt(new \DateTime()); } } public function getImageFile(): ?File { return $this->imageFile; }}<?phpnamespace App\Entity;use ApiPlatform\Core\Annotation\ApiProperty;use ApiPlatform\Core\Annotation\ApiResource;use App\Entity\Traits\UpdatedAtTrait;use Doctrine\ORM\Mapping as ORM;use Symfony\Component\Serializer\Annotation\Groups;/** * @ORM\Entity(repositoryClass="App\Repository\FileUploadRepository") * @ApiResource() * @ORM\InheritanceType("JOINED") * @ORM\DiscriminatorColumn(name="type", type="string") * @ORM\DiscriminatorMap({ * "userAvatar" = "App\Entity\UserAvatar", * "productionCenterLogo" = "App\Entity\ProductionCenterLogo", * "donneurOrdreLogo" = "App\Entity\DonneurOrdreLogo", * }) */abstract class FileUpload{ use UpdatedAtTrait; /** * @ORM\Id() * @ORM\GeneratedValue() * @ORM\Column(type="integer") * @ApiProperty(identifier=true) */ private int $id; /** * @ORM\Column(type="string") * * @var string|null * @Groups({ * "file", * "user_read", * "production_center_read", * "donneur_ordre_read", * }) */ private $filePath; /** * @ORM\Column(type="string") * * @var string|null * @Groups({ * "file", * "user_read", * "production_center_read", * "donneur_ordre_read", * }) */ private $originalName; /** * @ORM\Column(type="string") * * @var string|null * @Groups({ * "file", * "user_read", * "production_center_read", * "donneur_ordre_read", * }) */ private $mimeType; /** * @ORM\Column(type="json", nullable=true) * * @var array|null * @Groups({ * "file", * "user_read", * "production_center_read", * "donneur_ordre_read", * }) */ private $dimensions; /** * @ORM\Column(type="integer", nullable=true) * * @var int|null * @Groups({ * "file", * "user_read", * "production_center_read", * "donneur_ordre_read", * }) */ private $imageSize; public function setFilePath(?string $filePath): self { $this->filePath = $filePath; return $this; } public function getFilePath(): ?string { return $this->filePath; } public function setImageSize(?int $imageSize): self { $this->imageSize = $imageSize; return $this; } public function getImageSize(): ?int { return $this->imageSize; } public function getId(): int { return $this->id; } public function setId(int $id): self { $this->id = $id; return $this; } public function getOriginalName(): ?string { return $this->originalName; } public function setOriginalName(?string $originalName): self { $this->originalName = $originalName; return $this; } public function getMimeType(): ?string { return $this->mimeType; } public function setMimeType(?string $mimeType): self { $this->mimeType = $mimeType; return $this; } public function getDimensions(): ?array { return $this->dimensions; } public function setDimensions(?array $dimensions): self { $this->dimensions = $dimensions; return $this; }}
