I am in Laravel 5.1 and am trying to use Dropzone.JS to handle uploading images and videos to my website. It is a very exciting process but unfortunately I am stuck currently and need help.
My routes.php:
Route::post('upload_video', ['as' => 'upload-post', 'uses' =>'ImageController#postUpload']);
My view from which I am sending the dropzone.js request:
<form action="/upload_video" enctype="multipart/form-data" class="dropzone needsclick dz-clickable" id="upload">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<div class="dz-message needsclick">
Drop files here or click to upload.<br>
</div>
</form>
<script>
Dropzone.options.upload= {
url: "http://example.com/upload_video",
paramName: "file",// The name that will be used to transfer the file
maxFilesize: 20,
autoProccessQueue: false,
uploadMultiple: true,
addRemoveLinks: false,
parallelUploads: 10,
init: function() {
// this.on("successmultiple", function(file, serverresponse) { window.location.href="http://example.com/your_awesome_profile"; });
}
};
</script>
My Image Controller:
<?php
namespace App\Http\Controllers;
use App\Logic\Image\ImageRepository;
use Illuminate\Support\Facades\Input;
class ImageController extends Controller
{
protected $image;
public function __construct(ImageRepository $imageRepository)
{
$this->image = $imageRepository;
}
public function getUpload()
{
return view('pages.upload');
}
public function postUpload()
{
$photo = Input::all();
$response = $this->image->upload($photo);
return $response;
}
My Image Repository:
<?php
namespace App\Logic\Image;
use Auth;
use App\Models\Image;
use App\Models\Video;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\File;
class ImageRepository
{
public function upload( $form_data )
{
//return dd($form_data);
$destinationPath = public_path().'/images/';
$validator = Validator::make($form_data, Image::$rules, Image::$messages);
if ($validator->fails()) {
//**FAILS HERE BUT IS AN IMAGE**
$validator = Validator::make($form_data, Video::$rules, Video::$messages);
}
else{
$photo = $form_data['file'];
$file = $photo->getClientOriginalName();
$filename = pathinfo($file, PATHINFO_FILENAME);
$extension = pathinfo($file, PATHINFO_EXTENSION);
$filename2 = $this->sanitize($filename);
$allowed_filename = $this->createUniqueFilename( $filename2, $extension );
$filenameExt = $allowed_filename . "." . $extension;
$uploadSuccess = $photo->move($destinationPath, $filenameExt);
if( !$uploadSuccess) {
return Response::json([
'error' => true,
'message' => 'Server error while uploading',
'code' => 500
], 500);
}
else{
$sessionImage = new Image;
$sessionImage->user_id = Auth::user()->id;
$sessionImage->name = $filename;
$sessionImage->url = $filenameExt;
list($width, $height) = getimagesize(public_path().'/images/' . $filenameExt);
$sessionImage->width = $width;
$sessionImage->height = $height;
$sessionImage->save();
return;
}
My problem is that, when I upload a .jpg I am being told that it is not a proper file type, even though my validation rules accept a .jpg. I'm not sure what I'm doing wrong, as the validator is failing on the line indicated in my Image Repository. Why does it fail there? At first I thought it was because return dd($form_data); yeilds an array but apparently that is what the validator wants, not a foreach for each file? I'm very confused, please assist and I can provide more code if needed, this is just excerpts.
Update: When I comment out my script in my view, the functionality seems to work perfectly in that images are being uploaded to my server and I can see this happening, but why when I set some options on the dropzone does it suddenly break? Any ideas?
The problem was on the client side. To be able to set options on the Dropzone.js properly, you want to disable autodiscover and set it up programmatically, like so:
Dropzone.autoDiscover = false;
After that, carry on, like so:
$("#upload").dropzone({
url: "http://examle.com/upload_video",
clickable: true,
uploadmultipe:true,
maxFilesize: 20,
init: function() {
this.on("queuecomplete", function(file, serverresponse) { window.location.href="http://example.com/your_awesome_profile"; });
}
});
Related
I'm using Dropzone.js to upload multiple files with a dropzone and an image preview, which works well, and this file field is part of a form with other fields from Symfony formBuilder.
What I would like now is to be able to send those file data to my Symfony server side.
I followed this tutorial, but the part where he gets the data returns null for me: $request->files->get('file') (of course by changing 'file' with 'product_form[distilleryPhotos][]' for me).
Moreover, my distilleryPhotos field from the builder isn't replaced by the Dropzone one. They seem to be two different fields on front side.
Here is my Controller function:
#[Route('/products/{id}', name: 'product_details', methods: ['GET', 'POST'])]
public function show(int $id, Request $request, TranslatorInterface $translator, SluggerInterface $slugger): Response
{
$repository = $this->getDoctrine()->getRepository(Product::class);
$product = $repository->findOneBy(['id' => $id]);
$form = $this->createForm(ProductFormType::class, $product, ['attr' =>
[
'class' => 'dropzone',
'id' => 'distillery-photos-dropzone'
]
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$product->setName($form->get('name')->getData());
$product->setAge($form->get('age')->getData());
$distilleryPhotos = $form->get('distilleryPhotos')->getData();
if($distilleryPhotos)
{
$photos = [];
foreach($distilleryPhotos as $distilleryPhoto)
{
$originalFilename = pathinfo($distilleryPhoto->getClientOriginalName(), PATHINFO_FILENAME);
// this is needed to safely include the file name as part of the URL
$safeFilename = $slugger->slug($originalFilename);
$newFilename = $safeFilename.'-'.uniqid().'.'.$distilleryPhoto->guessExtension();
// Move the file to the directory where brochures are stored
try
{
$distilleryPhoto->move(
$this->getParameter('distillery_photos_directory'),
$newFilename
);
}
catch (FileException $e)
{
throwException($e);
}
$photos[] = $newFilename;
// updates the 'brochureFilename' property to store the PDF file name
// instead of its contents
}
$product->setDistilleryPhotos($photos);
}
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($product);
$entityManager->flush();
$this->addFlash('success', $translator->trans('Your product was updated successfully.'));
return $this->redirectToRoute('product_details', [
'id' => $id,
]);
}
My twig:
<form name="product_form" method="post" class="dropzone" id="distillery-photos-dropzone" enctype="multipart/form-data" action="{{ path('product_details', {'id': product.id}) }}">
{{ form_end(productForm) }}
And my JS:
let fileUploadActionName = document.querySelector('#distillery-photos-dropzone').action;
let distilleryPhotosDropzone = new Dropzone(
"#distillery-photos-dropzone",
{
paramName: "product_form[distilleryPhotos][]",
maxFilesize: 10,
maxFile: 10,
addRemoveLinks: true,
uploadMultiple: true,
init: function () {
this.on("maxfilesexceeded", function(file) {
this.removeFile(file);
});
this.on("sending", function(file, xhr, formData) {
// send additional data with the file as POST data if needed.
// formData.append("key", "value");
});
this.on("success", function(file, response) {
if (response.uploaded)
alert('File Uploaded: ' + response.fileName);
});
}
}
);
distilleryPhotosDropzone.on("addedfile", file => {
console.log(`File added: ${file.name}`);
});
Might be useful for new visitors. You can use a library that extends Symfony Form and adds a new type DropzneType.
Example
public function buildForm(FormBuilderInterface
$builder, array $options){
// userFiles is OneToMany
$builder->add('userFiles', DropzoneType::class, [
'class' => File::class,
'maxFiles' => 6,
'uploadHandler'=>'uploadhandler', // route name
'removeHandler'=> 'removeHandler'// route name
]);
}
when i use from ckeditor to upload image and attach that on post my upload image function in controller work fine without any problem, but when i want to return uploaded image to that, ckeditor can't get that, for example this is my code:
Controller:
public function uploadImageContent()
{
$this->validate(request(), [
'upload' => 'mimes:jpeg,jpg,gif,png'
]);
$file = request()->file('upload');
$filename = $file->getClientOriginalName();
$year = Carbon::now()->year;
$imagePath = "/uploads/post_images/{$year}/";
if (file_exists(public_path($imagePath) . $filename)) {
$filename = Carbon::now()->timestamp . '.' . $filename;
}
$file->move(public_path() . $imagePath, $filename);
$url = $imagePath . $filename;
return "<script>window.parent.CKEDITOR.tools.callFunction(1,'{$url}','')</script>";
}
this function work fine and i dont get any error on console or network
return "<script>window.parent.CKEDITOR.tools.callFunction(1,'{$url}','')</script>";
should be return path, but dont work.
view:
<script>
$(function () {
CKEDITOR.replace('description', {
height: '200px',
extraPlugins: 'forms',
filebrowserUploadUrl:'/dashboard/administrator/attachImage',
filebrowserImageUploadUrl:'/dashboard/administrator/attachImage'
});
});
</script>
route:
Route::group(['namespace' => 'Dashboard', 'prefix' => 'dashboard'], function () {
$this->group(['prefix' => 'administrator'], function () {
...
$this->post('/attachImage', 'ContentsController#attachImage');
...
});
ContentsController:
class ContentsController extends Controller
{
...
public function attachImage()
{
$this->uploadImageContent(request()->all());
}
}
Your code did not work for me. What I observed is, you are not embedding the CKEditorFuncNum (which server receives as POST variable) at the place of 1 as the first parameter to callFunction(). I replaced the 1 with $request->CKEditorFuncNum and then I used return statement instead of echo and it all works.
Here's your code:
echo "<script>window.parent.CKEDITOR.tools.callFunction(1,'{$url}','')</script>";
and
Here's my code:
return "<script>window.parent.CKEDITOR.tools.callFunction('{$request->CKEditorFuncNum}','{$url}','')</script>";
I'm on Laravel 5.8
Hope it helps others.
using echo instead of return resolve my problem:
echo "<script>window.parent.CKEDITOR.tools.callFunction(1,'{$url}','')</script>";
i have this issue on laravel 5.5
I try to use dropzoneJS in order to upload multiple image for my products and so far I can save images in database, also in images folder but I have problem with getting product id to relate each image to products.
Here is what I have:
Databases
Products (where my products including info will save)
Images (where my images including product id will save screenshot provided )
Models
Product:
public function images()
{
return $this->morphMany(Image::class, 'imageable');
}
Image:
class Image extends Model
{
protected $fillable = ['name'];
public function imageable()
{
return $this->morphTo();
}
public function product()
{
return $this->belongsTo(Product::class);
}
}
Image Schema
public function up()
{
Schema::create('images', function (Blueprint $table) {
$table->increments('id');
$table->integer('imageable_id')->nullable();
$table->string('imageable_type')->nullable();
$table->string('name');
$table->timestamps();
});
}
ImageController
class ImageController extends Controller
{
public function dropzone()
{
return view('dropzone-view');
}
public function dropzoneStore(Request $request)
{
// works
$file = $request->file('file');
$filename = 'product' . '-' . time() . '.' . $file->getClientOriginalExtension();
$filePath = public_path('images/');
$request->file('file')->move($filePath, $filename);
return Image::create([
'name' => $filename,
'imageable_id' => $request->input('imageable_id'),
])->id;
}
}
Product Create (Blade)
// Form
{!! Form::open([ 'route' => [ 'dropzone.store' ], 'files' => true, 'enctype' => 'multipart/form-data', 'class' => 'dropzone mt-20', 'id' => 'my-awesome-dropzone' ]) !!}
<div class="fallback">
<input name="file" type="file" multiple />
</div>
<input type="hidden" name="imageIds[]" value="">
{{Form::close()}}
// Javascript
<script type="text/javascript">
Dropzone.autoDiscover = false;
var myDropzone = new Dropzone("form#my-awesome-dropzone", {
headers: {
"X-CSRF-TOKEN": $("meta[name='csrf-token']").attr("content")
},
acceptedFiles: ".jpeg,.jpg,.png,.gif",
dictDefaultMessage: "Drag an image here to upload, or click to select one",
maxFiles: 15, // Maximum Number of Files
maxFilesize: 8, // MB
addRemoveLinks: true,
});
myDropzone.on("success", function (response) {console.log(response.xhr.response); });
</script>
Any idea?
Code for controller:
class ImageController extends Controller
{
public function dropzone($id)
{
$product = Product::find($id);
return view('dropzone-view')
->withProduct($porduct);
}
public function dropzoneStore(Request $request)
{
// works
$file = $request->file('file');
$filename = 'product' . '-' . time() . '.' . $file->getClientOriginalExtension();
$filePath = public_path('images/');
$request->file('file')->move($filePath, $filename);
return Image::create([
'name' => $filename,
'imageable_id' => $request->input('imageable_id'),
])->id;
}
}
Code on blade view:
{!! Form::open([ 'route' => [ 'dropzone.store' ], 'files' => true, 'enctype' => 'multipart/form-data', 'class' => 'dropzone mt-20', 'id' => 'my-awesome-dropzone' ]) !!}
<div class="fallback">
<input name="imageable_id" type="hidden" value="{{$product->id}}" />
<input name="file" type="file" multiple />
</div>
{{Form::close()}}
Try this hope this should get you going. This is one of many way to make this thing work.
this is a morpic relation and this is how you get morphic relation
$post = App\Post::find(1);
foreach ($post->comments as $comment) {
//
}
read about it here polymorphic-relations
What i normally do is,
After you upload a picture, return the ID of the newly created image (you already do that in ImageController)
On your product page, in the dropzone 'success' callback you can read the the image ID and add it to an hidden array input field
In your controller you have to create the new product, and then after saving it , you can attach the images to the correct product, because now you have the id's of the images + the product instance has been made.
I have a Laravel setup where I can add files and remove them. Now when I try to remove icons on my site on the server I get
Not Found
The requested URL /icons/24 was not found on this server.
Uploading the files and retrieving the files works. When I test it locally it works. And I do it the exact same way as with images, video files and audio files, and those all work on the server.
To debug it I also added the show() function in the controller, and that one also gives the same problem. What is going on?
routes/web.php: (partially)
Route::get('iconFile/{id}','IconController#iconFile');
Route::get('imageFile/{id}','ImageController#imageFile');
Route::get('audioFile/{id}','AudioController#audioFile');
Route::get('videoFile/{id}','VideoController#videoFile');
Route::get('signlanguageFile/{id}','SignlanguageController#signlanguageFile');
Route::group(['middleware' => ['auth']], function() {
Route::post('image-upload-with-validation',['as'=>'postimage','uses'=>'ImageController#postImage']);
Route::post('icon-upload-with-validation',['as'=>'posticon','uses'=>'IconController#postIcon']);
Route::resource('texts', 'TextController');
Route::resource('icons', 'IconController');
Route::resource('images', 'ImageController');
Route::resource('videos', 'VideoController');
Route::resource('signlanguages', 'SignlanguageController');
Route::resource('audios', 'AudioController');
});
IconController:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Http\Requests;
use App\Icon;
use Storage;
class IconController extends Controller
{
public function iconFile($id)
{
$icon = Icon::find($id);
$contents = Storage::disk('local')->get('uploads/icons/'.$icon->file);
$response = Response($contents);
$response->header('Content-Type', 'icon');
return $response;
}
public function show($id)
{
$icon = Icon::find($id);
$data = [
'icon' => $icon
];
echo $icon;
//return view('icon', $data);
}
public function postIcon(Request $request)
{
$this->validate($request, [
'icon_file' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:10000',
]);
$iconName = time().'.'.$request->icon_file->getClientOriginalExtension();
$request->icon_file->move(storage_path('app/uploads/icons'), $iconName);
$icon = new Icon;
$icon->parent_id = $request->parent_id;
$icon->file = $iconName;
$icon->save();
return back()
->with('success','You have successfully uploaded an icon.')
->with('icon',$iconName);
}
public function destroy($id)
{
$icon = Icon::find($id);
$section_id = $icon->parent_id;
Storage::delete('uploads/icons/'.$icon->file);
$icon->delete();
return redirect('/section/'.$section_id)->with('success','Icon deleted.');
}
}
Update:
i tried replacing the resource route to Route::resource('iconz', 'IconController'); (with a z) and then it works! Changing it back to "icons" makes it stop working again. Could icons be some kind of reserved word?
Also tried php artisan route:clear which didn't help.
Trying to build my upload images part of my site and wanted to use blueimp/jQuery-File-Upload instead of hardcoding everything from scratch. However I am new too all that, could you tell me HOW to integrate that plugin with my Laravel structure ?
Where do I put all the files ? In vendors folder ? Or should I split all the folders and put their js folder in mine etc???
If you know a tutorial it is even better...
Couldn't find anything good with google.
Thanks
You can try this code I'm posting to help others.
The first step is to define the upload page and upload handling Routes, like this:
Route::get('image_', function() {
return View::make('image.upload-form');
});
Route::post('image_updade', 'ImageController#postUpload');
Make your image.upload-form view something like this (I'm using simple HTML, not a Blade template):
<?php echo Form::open(array('url' => 'image_updade', 'files' => true, 'id' => 'myForm')) ?>
Name: <input type='file' name='image' id='myFile'/>
<br/>
Comment: <textarea name='comment'></textarea>
<br/>
<input type='submit' value='Submit Comment' />
<?php echo Form::close() ?>
Now you need to add the JavaScript files in that view page's <HEAD> tag:
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js'></script>
<script src='http://malsup.github.com/jquery.form.js'></script>
<script>
// Wait for the DOM to be loaded
$(document).ready(function() {
// Bind 'myForm' and provide a simple callback function
$('#myForm').ajaxForm(function() {
alert('Thank you for your comment!');
});
$('#myFile').change(function() {
$('#myForm').submit();
});
});
</script>
Finally, here's a simple example of code for the ImageController#postUpload controller to get the uploaded file, and move it to a destination folder:
<?php
class ImageController extends BaseController {
public function getUploadForm() {
return View::make('image/upload-form');
}
public function postUpload() {
$file = Input::file('image');
$input = array('image' => $file);
$rules = array( 'image' => 'image');
$validator = Validator::make($input, $rules);
if ( $validator->fails() ){
return Response::json(['success' => false, 'errors' => $validator->getMessageBag()->toArray()]);
}
else {
$destinationPath = 'files/';
$filename = $file->getClientOriginalName();
Input::file('image')->move($destinationPath, $filename);
return Response::json(['success' => true, 'file' => asset($destinationPath.$filename)]);
}
}
}