Dropzone no valid MIME type in backend Laravel?
Asked Answered
R

5

8

I have really no idea where the problem resides to be honest.

Might be Dropzone, Laravel (5.4), ... So I truly hope even a thought might help me get past this problem.

When I upload files, I don't get any js issues but Laravel throws me following error (for each file):

Call to undefined method Symfony\Component\HttpFoundation\File\UploadedFile::store()

This is my backend code (Error is set in the portfolioStore method):

    <?php

namespace App\Http\Controllers;

use App\Http\Requests\UploadPortfolioPhotoRequest; use App\PortfolioPhoto; use DebugBar\DebugBar; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage;

class AdminController extends Controller {
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');
    }

    /**
     * Show the application dashboard.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view('admin.home');
    }

    public function portfolioIndex()
    {
        $photos = PortfolioPhoto::all();

        return view ('admin.portfolio.index')->with('photos', $photos);
    }

    public function portfolioStore(UploadPortfolioPhotoRequest $request)
    {
        foreach ($request->files as $photo) {
            $filename = $photo->store('photos');

            $test = PortfolioPhoto::create([
                'filename' => $filename,
                'title' => 'title',
                'alt' => 'alt'
            ]);
        }

        return 'Upload successful!';
    }

    public function portfolioDelete()
    {
        return view ('admin.portfolio.index');
    } }

In any case, here is my Dropzone config:

var previewNode = document.querySelector("#template");
previewNode.id = "";
var previewTemplate = previewNode.parentNode.innerHTML;
previewNode.parentNode.removeChild(previewNode);

var myDropzone = new Dropzone(document.body, { // Make the whole body a dropzone
    url: "/admin/portfolio", // Set the url
    thumbnailWidth: 80,
    thumbnailHeight: 80,
    parallelUploads: 20,
    previewTemplate: previewTemplate,
    autoDiscover: false,
    autoQueue: false, // Make sure the files aren't queued until manually added
    previewsContainer: "#previews", // Define the container to display the previews
    clickable: ".fileinput-button", // Define the element that should be used as click trigger to select files.
    headers: {
        'x-csrf-token': document.querySelectorAll('meta[name=csrf-token]')[0].getAttributeNode('content').value,
    }
});

myDropzone.on("addedfile", function(file) {
    // Hookup the start button
    file.previewElement.querySelector(".start").onclick = function() { myDropzone.enqueueFile(file); };
});

myDropzone.on("sending", function(file) {
    // And disable the start button
    file.previewElement.querySelector(".start").setAttribute("disabled", "disabled");
});

// Hide the total progress bar when nothing's uploading anymore
myDropzone.on("queuecomplete", function(progress) {
    var alertMsg = document.createElement('div'),
        actions = document.getElementById('actions');
    alertMsg.setAttribute('class', 'alert bg-success');
    alertMsg.innerHTML = 'Files successfully uploaded<a href="#" class="pull-right"><em class="fa fa-lg fa-close"></em></a>';
  actions.parentNode.insertBefore(alertMsg, actions.nextSibling);
});

// Setup the buttons for all transfers
// The "add files" button doesn't need to be setup because the config
// `clickable` has already been specified.
document.querySelector("#actions .start").onclick = function() {
    myDropzone.enqueueFiles(myDropzone.getFilesWithStatus(Dropzone.ADDED));
};
document.querySelector("#actions .cancel").onclick = function() {
    myDropzone.removeAllFiles(true);
};

Here is the view:

@extends('admin.layouts.app')

@section('content')
    <div class="row">
        <div class="col-xs-12">
            <div class="panel panel-default">
                <div class="panel-heading">Upload images</div>

                <div class="panel-body">
                    @if (count($errors) > 0)
                        <div class="row">
                            <div class="col-xs-12">
                                <div class="alert bg-danger" role="alert"><em class="fa fa-lg fa-warning">&nbsp;</em>
                                    <ul style="display: inline-block;">
                                        @foreach ($errors->all() as $error)
                                            <li>{{ $error }}</li>
                                        @endforeach
                                    </ul>
                                    <a href="#" class="pull-right"><em class="fa fa-lg fa-close"></em></a>
                                </div>
                            </div>
                        </div>
                    @endif

                    <div id="actions" class="row">
                        <div class="col-xs-12">
                            <div class="form-group">
                                <button class="btn btn-success fileinput-button">
                                    <i class="glyphicon glyphicon-plus"></i><span>Add files...</span>
                                </button>
                                <button type="submit" class="btn btn-primary start">
                                    <i class="glyphicon glyphicon-upload"></i> <span>Start upload</span>
                                </button>
                                <button type="reset" class="btn btn-warning cancel">
                                    <i class="glyphicon glyphicon-ban-circle"></i> <span>Cancel upload</span>
                                </button>
                            </div>
                        </div>
                    </div>

                    <div class="row">
                        <div class="col-xs-12">
                            <div class="files" id="previews">
                                <div id="template" class="file-row">
                                    <div class="media">
                                        <div class="media-left">
                                            <img data-dz-thumbnail/>
                                        </div>
                                        <div class="media-body">
                                            <h4 class="media-heading name" data-dz-name></h4>
                                            <div class="col-xs-12"><strong class="error text-danger" data-dz-errormessage></strong></div>
                                            <div class="col-xs-12">
                                                <div class="col-sm-3">
                                                    <p class="size" data-dz-size></p>
                                                    <div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
                                                        <div class="progress-bar progress-bar-success" style="width:0%;" data-dz-uploadprogress></div>
                                                    </div>
                                                </div>
                                                <div class="col-sm-9 text-right">
                                                    <button class="btn btn-primary start">
                                                        <i class="glyphicon glyphicon-upload"></i>
                                                        <span>Start</span>
                                                    </button>
                                                    <button data-dz-remove class="btn btn-warning cancel">
                                                        <i class="glyphicon glyphicon-ban-circle"></i>
                                                        <span>Cancel</span>
                                                    </button>
                                                    <button data-dz-remove class="btn btn-danger delete">
                                                        <i class="glyphicon glyphicon-trash"></i>
                                                        <span>Delete</span>
                                                    </button>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-xs-12">
            <div class="panel panel-default">
                <div class="panel-heading">Portfolio</div>

                <div class="panel-body">
                    <div class="row">
                        @foreach($photos as $photo)
                            <div class="col-xs-6 col-md-3">
                                <a href="#" class="thumbnail">
                                    <img src="..." alt="...">
                                </a>
                            </div>
                        @endforeach
                    </div>
                </div>
            </div>
        </div>
    </div>@endsection

@push('styles')
<link href="{{asset('css/vendor/dropzone.css')}}"/>
@endpush

@push('scripts')
<script src="{{asset('js/vendor/dropzone.js')}}"></script>
<script src="{{asset('js/vendor/initialize/dropzone.cfg.js')}}"></script>
@endpush

So now I'm wondering whether the issue is related to a MIME type being undefined which cause the store method to not work. Or should I be looking elsewhere?

Any advice, ideas welcome :)

Rabbinate answered 4/9, 2017 at 7:43 Comment(5)
can you show the html form where drop zone is initializedSaltzman
@AatishSai Hey thanks for your reply, I added the view to my post.Rabbinate
if you were to dd($photo);in the foreach, does it return an object?Butterbur
@Butterbur unfortunately not. As if the dd() isn't used.Rabbinate
Found any solution yet?Knell
S
2

The problem here is that the $request->files does not exist in the Laravel codebase. Since the Illuminate\Http\Request class extends the Symfony\Component\HttpFoundation\Request class, the files refers to the Symfony\Component\HttpFoundation\FileBag class which does happens to contain numerous Symfony\Component\HttpFoundation\File\UploadedFiles that do not have the store method.

Simple fix: Replace $request->files with $request->allFiles() which should give you an array of Illuminate\Http\UploadedFile classes which have the store method

Feel free to shoot any questions in the comment section if you need further help

Sinnard answered 7/9, 2017 at 18:5 Comment(0)
G
2

This seems to be no issue of dropzone.js to me. The error says "undefined method..." in the backend (laravel), so the method is not available to your object photo.

Have a look at the docs in laravel. (https://laravel.com/docs/5.4/filesystem#file-uploads)

Maybe you can try something like this:

foreach ($request->files as $photo) {
    $path = Storage::putFile('photos', $photo);
...
Gobi answered 4/9, 2017 at 8:39 Comment(3)
I thought of using this as well: but then I get: Call to undefined method Symfony\Component\HttpFoundation\File\UploadedFile::hashName()....Rabbinate
Can you please provide the full code of your backend class?Gobi
I've replaced the backend function with the whole class. I haven't included the request as it passes.Rabbinate
S
2

The problem here is that the $request->files does not exist in the Laravel codebase. Since the Illuminate\Http\Request class extends the Symfony\Component\HttpFoundation\Request class, the files refers to the Symfony\Component\HttpFoundation\FileBag class which does happens to contain numerous Symfony\Component\HttpFoundation\File\UploadedFiles that do not have the store method.

Simple fix: Replace $request->files with $request->allFiles() which should give you an array of Illuminate\Http\UploadedFile classes which have the store method

Feel free to shoot any questions in the comment section if you need further help

Sinnard answered 7/9, 2017 at 18:5 Comment(0)
K
2

I had a similar problem but in my case it was simply not having enctype="multipart/form-data" property included in the <form> tag. Once I did that it worked. And I see you also don't have <form> tag.

<form action="/route" method="post" enctype="multipart/form-data">
    <!-- your code for dropzone goes here -->
</form>

And on a side note, in your portfolioStore() method in your AdminController controller you have,

foreach ($request->allFiles() as $photo) {
    $filename = $photo->store('photos');

    $test = PortfolioPhoto::create([
        'filename' => $filename,
        'title' => 'title',
        'alt' => 'alt'
    ]);
}

Please Don't do it!

You're creating too many insert queries here.

Refactor it as follows. You can get away with one db query :)

$photos = [];
foreach ($request->files as $photo) {
    $filename = $photo->store('photos');

    $photos[] = [
        'filename' => $filename,
        'title' => 'title',
        'alt' => 'alt'
    ];
}
PortfolioPhoto::createMany($photos);

And also in a previous post I answered how to convieninetly store files in Laravel. you can check it out here. it could improve your $filename = $photo->store('photos'); part.

Hope this would help you :)

Knell answered 13/9, 2017 at 16:4 Comment(1)
This wont work. $request->files returns Symfony\Component\HttpFoundation\FileBag which does not have the store method. Replace $request->files with $request->allFiles()Sinnard
B
1

UPDATED

In Laravel you access uploaded files using the file method, which takes the name of the file input as a parameter. And from the Dropzonejs docs:

The uploaded files can be handled just as if there would have been a html input like this: <input type="file" name="file" />

So try this:

foreach ($request->file('file') as $photo) {
Bruce answered 7/9, 2017 at 8:48 Comment(4)
This shows up as an invalid argument (supplied for foreach()).Rabbinate
What do your file inputs look like?Iridotomy
It doesn't have a direct file input. All is done through the Dropzone configuration.Rabbinate
Ah sorry - answer updated. Dropzone uses 'file' as the input name, AFAIK. You can double check by just doing return $request->all() in portfolioStore().Iridotomy
C
1

Just dump your $request object, dropzone may send base64_encoded images, that are not in $request->files array.

Anotherway, you can use https://github.com/bnbwebexpertise/laravel-attachments

This is very helpful package to work with files.

Calamondin answered 7/9, 2017 at 13:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.