Laravel-Backpack / medialibrary-uploaders

MIT License
9 stars 3 forks source link

Drozone returning array_filter() error #22

Closed logifloor closed 9 months ago

logifloor commented 9 months ago

Discussed in https://github.com/Laravel-Backpack/community-forum/discussions/772

Originally posted by **logifloor** December 1, 2023 I'm struggling with Dropzone uploads when using the Spatie media library addon. All is working well until I try and submit a form without any uploads (other fields text/date etc populated). I don't want to 'require' and upload because sometimes not necessary for this application, however, after extensive debugging, I can't find a solution to array_filter(): Argument Laravel-Backpack/community-forum#1 ($array) must be of type array, null given, when the files field is submitted empty. Anybody else come across this?
karandatwani92 commented 9 months ago

Hey @pxpm,

I confirmed the bug by utilizing withMedia on the dropzone field of Monster CRUD, which started throwing the same error, on create error log & on update error log

Following is a solution proposed by @logifloor.

Please check, Thanks

The problem seems to revolve around this code in medialibrary-uploaders/ MediaAjaxUploader.php

$uploads = json_decode($uploads, true) ?? [];

$uploadedFiles = array_filter($uploads, function ($value) use ($temporaryFolder, $temporaryDisk) {
    return strpos($value, $temporaryFolder) !== false && Storage::disk($temporaryDisk)->exists($value);
});

Its supposed to decode a/the JSON string into an array. If $uploads is null or if json_decode fails and returns null, its supposed to provide an empty array as a default value. However, It seems that despite the null coalescing operator, $uploads is still null when it reaches array_filter, which is why the error occurs.

I've modified the method in MediaAjaxUploader.php to include an additional check and make sure an empty array is returned even when all else fails.

public function uploadFiles(Model $entry, $value = null)
{
    $temporaryDisk = CRUD::get('dropzone.temporary_disk');
    $temporaryFolder = CRUD::get('dropzone.temporary_folder');

    $uploads = $value ?? CRUD::getRequest()->input($this->getName());

    // Ensure $uploads is an array. If not, decode it or set it to an empty array.
    if (!is_array($uploads)) {
        $uploads = is_string($uploads) ? json_decode($uploads, true) : [];
    }

    // Ensure $uploads is an array before using array_filter
    if (!is_array($uploads)) {
        $uploads = [];
    }

    $uploadedFiles = array_filter($uploads, function ($value) use ($temporaryFolder, $temporaryDisk) {
        return strpos($value, $temporaryFolder) !== false && Storage::disk($temporaryDisk)->exists($value);
    });

    $previousSentFiles = array_filter($uploads, function ($value) use ($temporaryFolder) {
        return strpos($value, $temporaryFolder) === false;
    });

    $previousFiles = $this->get($entry);

    foreach ($previousFiles as $previousFile) {
        if (! in_array($this->getMediaIdentifier($previousFile, $entry), $previousSentFiles)) {
            $previousFile->delete();
        }
    }

    foreach ($uploadedFiles as $key => $value) {
        $file = new File(Storage::disk($temporaryDisk)->path($value));

        $this->addMediaFile($entry, $file);
    }
}
pxpm commented 9 months ago

Thanks for the report @logifloor and sorry for the bad experience.

I've just fixed it in #26 🙏

Thanks @karandatwani92 for the confirmation and providing an easy to read issue history in this thread 🙏

Cheers

logifloor commented 9 months ago

Thanks for getting the fix out on this. Just a quick follow on from this, you (or I at least), now have to ensure I send 'something' with withMedia(), or it returns an empty array error. I.e. withMedia('');

pxpm commented 9 months ago

Humm sorry the bad experience 🙏 . That shouldn't be happening, thanks for the report.

I've just pushed a fix for it in 1.0.3, you can get it with a composer update backpack/medialibrary-uploaders

Cheers