3

Is anyone using Laravel package spatie/media-library with Cloudinary?
I thought implementing it would be trivial with flysystem.
I'm actually using Cloudinary as a Nova field with silvanite/nova-field-cloudinary and it works great but I have a need for the media-libaray which doesn't support it out of the box.

So, what I did:
- add cloudinary disk:

'cloudinary' => [
    'driver' => 'cloudinary',
    'api_key' => env('CLOUDINARY_API_KEY'),
    'api_secret' => env('CLOUDINARY_API_SECRET'),
    'cloud_name' => env('CLOUDINARY_CLOUD_NAME'),
    'url' => env('CLOUDINARY_URL'),
],
  • changed disk name to cloudinary

    'disk_name' => 'cloudinary',
    
  • tried adding the image

    $newMedia = $myModel
        ->addMediaFromUrl($imageUrl)
        ->setFileName($filename)
        ->toMediaCollection();
    

and then I get "File not found" error. The image is uploaded but record is not saved to DB.

#message: "File not found at path: 711297/my-image.jpg"
#code: 0
#file: "./vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php"
#line: 435
-previous: League\Flysystem\FileNotFoundException^ {#2389
#path: "711297/my-image.jpg"
#message: "File not found at path: 711297/my-image.jpg"
#code: 0
#file: "./vendor/league/flysystem/src/Filesystem.php"
#line: 389
trace: {
./vendor/league/flysystem/src/Filesystem.php:389 { …}
./vendor/league/flysystem/src/Filesystem.php:194 { …}
./vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php:433 { …}
./vendor/spatie/laravel-medialibrary/src/Filesystem/Filesystem.php:81 { …}
./vendor/spatie/laravel-medialibrary/src/Filesystem/Filesystem.php:88 { …}
./vendor/spatie/laravel-medialibrary/src/FileManipulator.php:77 { …}
./vendor/spatie/laravel-medialibrary/src/FileManipulator.php:44 { …}
./vendor/spatie/laravel-medialibrary/src/Filesystem/Filesystem.php:33 { …}
./vendor/spatie/laravel-medialibrary/src/FileAdder/FileAdder.php:310 { …}
./vendor/spatie/laravel-medialibrary/src/FileAdder/FileAdder.php:301 { …}
./vendor/spatie/laravel-medialibrary/src/FileAdder/FileAdder.php:251 { …}
./vendor/efdi/carmarket-module/src/Jobs/ImportImages.php:145 { …}
./vendor/efdi/carmarket-module/src/Jobs/ImportImages.php:84 { …}
./vendor/efdi/carmarket-module/src/Jobs/ImportImages.php:43 { …}

So it seems the problem is it's trying to load the image using local path which of course doesn't exist.
I tried using a custom PathGenerator so it returns the url that's no solution since it expects a path.
I can't figure out how they do it for S3.

So if anyone knows how to solve this or has a working solution I would appreciate it.

apokryfos
  • 38,771
  • 9
  • 70
  • 114
praxus
  • 488
  • 1
  • 7
  • 18

1 Answers1

3

This happens because the spatie package is trying to make conversion of the uploaded image. Go to the medialibrary.php config file and comment out these lines:

    'image_generators' => [
        Spatie\MediaLibrary\ImageGenerators\FileTypes\Image::class,
        Spatie\MediaLibrary\ImageGenerators\FileTypes\Webp::class,
        Spatie\MediaLibrary\ImageGenerators\FileTypes\Pdf::class,
        Spatie\MediaLibrary\ImageGenerators\FileTypes\Svg::class,
        Spatie\MediaLibrary\ImageGenerators\FileTypes\Video::class,
    ],

When no generator is found for the given image mime-type, the image will not be converted. Thus the error will not be thrown. Then convert your images using cloudinary.

For this I've created a CloudinaryUrlGenerator which extends BaseUrlGenerator.

    const HOST = 'https://res.cloudinary.com/';

    /**
     * Get the url for a media item.
     *
     * @return string
     */
    public function getUrl(): string
    {
        $cloudBaseUrl = self::HOST . config('filesystems.disks.cloudinary.cloud_name') . '/';

        $options = [
            'q_auto',
        ];

        $filePathIncludingFilenameAndExtension = '/' . $this->pathGenerator->getPath($this->media) . $this->media->file_name;

        return $cloudBaseUrl . implode(',', $options) . $filePathIncludingFilenameAndExtension;
    }

In getTemporaryUrl and getResponsiveImagesDirectoryUrl I've simply returned: $this->getUrl().

Once you've done this, then you can get your images like so:

<img src="{{ $model->media->first()->getUrl() }}" />
Martijn Imhoff
  • 918
  • 1
  • 8
  • 22
  • So far it works, thanks. I should have known because there is FileManipulator in stack trace... Btw. commenting out those _image_generators_ was not enough for me, I also had _registerMediaConversions()_ method defined in the model. – praxus Nov 26 '19 at 08:57
  • @Martijn Imhoff I have a similar issue and need clarification on this solution – Enrico Apr 16 '22 at 09:44