statamic / workshop

Create and edit entries, pages, and globals on the front-end of your site without the control panel.
https://statamic.com/marketplace/addons/workshop
3 stars 2 forks source link

Uploading Multiple Images to an Asset Field Fails #20

Closed bgarrant closed 6 years ago

bgarrant commented 6 years ago

Describe the bug When I upload multiple images using the single <input type="file" name="gallery_images[]" multiple> to a Asset filed with no max items, the upload works if files are selected. If no files are selected an EDIT form, it fails with an error Call to a member function getClientOriginalName() on null

To Reproduce Steps to reproduce the behavior: In a Workshop form, have a field setup for multiple image uploads like: <input type="file" name="gallery_images[]" multiple>. If you select images it will work, if no images selected it fails. The Asset field has no validation on it.

Expected behavior Upload multiple images to the Asset field array without issues. When no images are selected, either keep the existing values or upload nothing if null.

Screenshots If applicable, add screenshots to help explain your problem.

Environment details (please complete the following information): Statamic 2.10.3 and Workshop 1.1.1.

Additional context Add any other context about the problem here.

bgarrant commented 6 years ago

Here is my EDIT form code

      <div class="grid-x grid-padding-x mt-1">
        <div class="small-12 cell">
          <label>Gallery Images</label>
        </div>

        {{ assets:gallery_images }}
        <div class="small-12 medium-4 cell">
          <div class="card">
            <div class="card-image">
              <img src="{{ glide:url preset='cards' }}" alt="{{ alt or filename }}" />
            </div>
          </div>
        </div>
        {{ /assets:gallery_images }}
      </div>

      <div class="grid-x grid-padding-x mt-1">
        <div class="small-12 cell">
          <div class="card">
            <div class="card-section">
              <label>Replace Gallery Images</label>
              {{ gallery_images }}
              <input type="hidden" name="gallery_images[]" value="{{ value }}">
              {{ /gallery_images }}
              <input type="file" name="gallery_images[]" aria-describedby="galleryimagesHelpText" multiple>
              <p class="help-text" id="galleryimagesHelpText">This will replace all uploaded images with new images</p>
            </div>
          </div>
        </div>
      ​</div>

And the Fieldset YAML

      gallery_images:
        container: main
        folder: images/events
        restrict: true
        mode: grid
        type: assets
        display: Gallery Images

FatalThrowableError in WorkshopController.php line 211: Call to a member function getClientOriginalName() on null

bgarrant commented 6 years ago

anyone know how to fix this? Trying to get my edit form to work. I need it to look for existing images, upload over them if any selected. I tried this with no luck:

              {{ gallery_images }}
                <input type="hidden" name="gallery_images[]" value="{{ value }}">
              {{ /gallery_images }}
              <input type="file" name="gallery_images[]" multiple>
bgarrant commented 6 years ago

FatalThrowableError in WorkshopController.php line 217: Call to a member function getClientOriginalName() on null

bgarrant commented 6 years ago

It seems to be looking at this code when no changes are made.

    /**
     * Upload a single file
     *
     * @param UploadedFile $file  The uploaded file
     * @param array $config       The field config
     */
    private function uploadFile($file, $config)
    {
        // Not an asset field? Bye.
        if (array_get($config, 'type') !== 'assets') {
            return;
        }

        $path = Path::assemble(array_get($config, 'folder'), $file->getClientOriginalName());

        $asset = Asset::create()
            ->container(array_get($config, 'container'))
            ->path(ltrim($path, '/'))
            ->get();

        $asset->upload($file);
        $asset->save();

        return $asset->url();
    }
bgarrant commented 6 years ago

This is from the logs:

[2018-08-21 06:42:18] dev.NOTICE: $this->request is deprecated. You should typehint the Request object in your controller methods.  
[2018-08-21 06:42:18] dev.ERROR: Symfony\Component\Debug\Exception\FatalThrowableError: Call to a member function getClientOriginalName() on null in /Users/bgarrant/Sites/fishcap/site/addons/Workshop/WorkshopController.php:217
Stack trace:
#0 /Users/bgarrant/Sites/fishcap/site/addons/Workshop/WorkshopController.php(192): Statamic\Addons\Workshop\WorkshopController->uploadFile(NULL, Array)
#1 [internal function]: Statamic\Addons\Workshop\WorkshopController->Statamic\Addons\Workshop\{closure}(NULL, 0)
#2 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Support/Collection.php(469): array_map(Object(Closure), Array, Array)
#3 /Users/bgarrant/Sites/fishcap/site/addons/Workshop/WorkshopController.php(193): Illuminate\Support\Collection->map(Object(Closure))
#4 [internal function]: Statamic\Addons\Workshop\WorkshopController->Statamic\Addons\Workshop\{closure}(Array, 'gallery_images')
#5 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Support/Collection.php(469): array_map(Object(Closure), Array, Array)
#6 /Users/bgarrant/Sites/fishcap/site/addons/Workshop/WorkshopController.php(198): Illuminate\Support\Collection->map(Object(Closure))
#7 /Users/bgarrant/Sites/fishcap/site/addons/Workshop/WorkshopController.php(348): Statamic\Addons\Workshop\WorkshopController->uploadFiles()
#8 /Users/bgarrant/Sites/fishcap/site/addons/Workshop/WorkshopController.php(245): Statamic\Addons\Workshop\WorkshopController->update(Array)
#9 [internal function]: Statamic\Addons\Workshop\WorkshopController->postEntryUpdate()
#10 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Container/Container.php(507): call_user_func_array(Array, Array)
#11 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Container/Container.php(604): Illuminate\Container\Container->call(Array, Array)
#12 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Container/Container.php(502): Illuminate\Container\Container->callClass('Statamic\\Addons...', Array, NULL)
#13 /Users/bgarrant/Sites/fishcap/statamic/core/Http/Controllers/StatamicController.php(123): Illuminate\Container\Container->call('Statamic\\Addons...', Array)
#14 /Users/bgarrant/Sites/fishcap/statamic/core/Http/Controllers/StatamicController.php(93): Statamic\Http\Controllers\StatamicController->callControllerMethod('Workshop', 'postEntryUpdate', NULL)
#15 [internal function]: Statamic\Http\Controllers\StatamicController->controllerTrigger('Workshop', 'entryUpdate')
#16 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(256): call_user_func_array(Array, Array)
#17 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(164): Illuminate\Routing\Controller->callAction('controllerTrigg...', Array)
#18 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(112): Illuminate\Routing\ControllerDispatcher->call(Object(Statamic\Http\Controllers\StatamicController), Object(Illuminate\Routing\Route), 'controllerTrigg...')
#19 [internal function]: Illuminate\Routing\ControllerDispatcher->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#20 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(139): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#21 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#22 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(102): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#23 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(114): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#24 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(68): Illuminate\Routing\ControllerDispatcher->callWithinStack(Object(Statamic\Http\Controllers\StatamicController), Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request), 'controllerTrigg...')
#25 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Routing/Route.php(203): Illuminate\Routing\ControllerDispatcher->dispatch(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request), 'Statamic\\Http\\C...', 'controllerTrigg...')
#26 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Routing/Route.php(134): Illuminate\Routing\Route->runWithCustomDispatcher(Object(Illuminate\Http\Request))
#27 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Routing/Router.php(708): Illuminate\Routing\Route->run(Object(Illuminate\Http\Request))
#28 [internal function]: Illuminate\Routing\Router->Illuminate\Routing\{closure}(Object(Illuminate\Http\Request))
#29 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(139): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#30 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#31 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(102): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#32 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Routing/Router.php(710): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#33 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Routing/Router.php(674): Illuminate\Routing\Router->runRouteWithinStack(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request))
#34 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Routing/Router.php(635): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request))
#35 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(236): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))
#36 [internal function]: Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http\{closure}(Object(Illuminate\Http\Request))
#37 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(139): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#38 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(50): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#39 [internal function]: Illuminate\Foundation\Http\Middleware\VerifyCsrfToken->handle(Object(Illuminate\Http\Request), Object(Closure))
#40 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)
#41 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#42 [internal function]: Illuminate\View\Middleware\ShareErrorsFromSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#43 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)
#44 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(62): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#45 [internal function]: Illuminate\Session\Middleware\StartSession->handle(Object(Illuminate\Http\Request), Object(Closure))
#46 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)
#47 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#48 [internal function]: Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse->handle(Object(Illuminate\Http\Request), Object(Closure))
#49 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)
#50 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(59): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#51 [internal function]: Illuminate\Cookie\Middleware\EncryptCookies->handle(Object(Illuminate\Http\Request), Object(Closure))
#52 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)
#53 /Users/bgarrant/Sites/fishcap/statamic/core/StaticCaching/Middleware/Retrieve.php(33): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#54 [internal function]: Statamic\StaticCaching\Middleware\Retrieve->handle(Object(Illuminate\Http\Request), Object(Closure))
#55 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)
#56 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(44): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#57 [internal function]: Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode->handle(Object(Illuminate\Http\Request), Object(Closure))
#58 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)
#59 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline\{closure}(Object(Illuminate\Http\Request))
#60 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(102): call_user_func(Object(Closure), Object(Illuminate\Http\Request))
#61 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(122): Illuminate\Pipeline\Pipeline->then(Object(Closure))
#62 /Users/bgarrant/Sites/fishcap/statamic/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(87): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter(Object(Illuminate\Http\Request))
#63 /Users/bgarrant/Sites/fishcap/public_html/index.php(155): Illuminate\Foundation\Http\Kernel->handle(Object(Illuminate\Http\Request))
#64 /Users/bgarrant/.composer/vendor/laravel/valet/server.php(147): require('/Users/bgarrant...')
#65 {main}  
bgarrant commented 6 years ago

trying to do this on an EDIT form screen shot 2018-08-21 at 7 09 11 am

bgarrant commented 6 years ago

Just tried this approach and also throws the same error: FatalThrowableError in WorkshopController.php line 217: Call to a member function getClientOriginalName() on null

      <div class="grid-x grid-padding-x mt-1">
        <div class="small-12 cell">
          <div class="card">
            <div class="card-section">
              <label>Replace Gallery Images</label>
              {{ if gallery_images }}
              {{ gallery_images }}
              <input type="hidden" name="gallery_images[]" value="{{ value }}"/>
              {{ /gallery_images }}
              {{ else }}
              <input type="hidden" name="gallery_images" value="false"/>
              {{ /if }}
              <input type="file" name="gallery_images[]" aria-describedby="galleryimagesHelpText" multiple/>
              <p class="help-text" id="galleryimagesHelpText">This will replace all uploaded images with new images</p>
            </div>
          </div>
        </div>
      ​</div>
bgarrant commented 6 years ago

The issue is only when you try to save with no new assets selected. Either an empty form, or leaving existing assets in place. I have the hidden field setup and all looks fine. Just wont save.

screen shot 2018-08-21 at 12 38 53 pm

jasonvarga commented 6 years ago

We're working on it, you've given plenty of details, no worries. Thanks!

jackmcdade commented 6 years ago

Fixed and released 1.1.2. FYI the official solution is to not use the multiple option.