What's your code so far?
Single or multiple images?
Hi, sorry for this thread is not completelly for Laravel. I have one question.
I am building project management site for my company.
I have a view for adding a new task, that task can have many attachments.
I have form fields like: Task name, task description, project, category...and I would like to add another field (div) for dropzone. Ok, I have done that. I dont know JavaScript and Jquery :( I want to save image data to database. I dont know how. When I drag images they are automaticaly uploaded, thats ok, but how to get their data to save them in database, when I click on submit button.
Can I make something like: 1. I drop images on dropzone field. 2. Images are in queue 3. When I click submit button on form, images start to upload. 4.After uploading, page is refreshed, task is saved, images are uploaded.
Thanks!
What's your code so far?
Single or multiple images?
Thanks for reply :)
I want to upload multiple image... I have been writeing something but deleted everything.
Database: tasks_table (id, task_name, task_description...) task_images_table (id, task_id, image_name, path....)
So, I want to store task info in database, also upload images, and store image info in task_images database...
So the problem is: How to store them in db? Becouse I am not familiar with JSON, jquery....
I normally add this sort of data for the table structures
If you want custom fields for each image uploaded, you'll need to include them and insert them into the Javascript for when you upload a file.
// Add on extra field to post
var fileLabel = file.previewElement.querySelector('input[name="file_label"]').value;
formData.append('file_label', fileLabel);
formData.append('_token', '{{ csrf_token() }}');
Thanks, but...you dont understand me!
I have UploadController, that uploads files in "uploads" directory...
But how to get image data of uploaded images to save them in database?
When I drop images, they are automaticaly uploaded, but image info, and task info is not saved, until I click the Submit button. When I click submit button, task is saved, but how to save images?
Generate a random temporary string and use that in hidden form field
When the images are uploaded save them into a folder with the random string name
When form is submitted, look through the folder for the uploaded images and save details to database
Move the images to where they should be
Delete the old folder
uff..to much to do! Is there a way to upload images, when I click submit? SO, when I click submit, images are uploading (with progress bar), after upload..page is refreshed?
autoProcessQueue
You asked how to store them in the database so I gave you a structure :P
Always best to display the code you already have so we understand better
Why don't you separate file save and meta-data save?
Send files through Dropzone's ajax request -> Save files at FilesController@store and in return, array of file_ids in json format-> Upon json response parse file_ids, and update hidden file_id[] field at view holding Dropzone -> Submit file_id[] and additional task-related form data -> Save task meta data in the TasksController@store and Update task_id at the FilesController@update.
Let me leave my complete code here. Mine is poor though, you can improve more.
create_releases_table:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateReleasesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('releases', function (Blueprint $table) {
$table->increments('id')->unsigned();
$table->integer('app_id')->unsigned()->index();
$table->string('app_name'); // deliberate duplicate for full-text search
$table->string('package'); // deliberate duplicate for full-text search
$table->integer('version_code');
$table->string('version_name')->nullable();
$table->timestamp('expires_at')->nullable();
$table->timestamp('confirmed_at')->nullable();
$table->text('description')->nullable();
$table->softDeletes();
$table->timestamps();
$table->foreign('app_id')->references('id')->on('apps')->onUpdate('cascade')->onDelete('cascade');
});
DB::statement('ALTER TABLE releases ADD FULLTEXT search(app_name, package, version_name, description)');
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('releases');
}
}
create_files_table:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateFilesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('files', function (Blueprint $table) {
$table->increments('id')->unsigned();
$table->integer('release_id')->unsigned()->index();
$table->string('filename');
$table->string('size');
$table->softDeletes();
$table->timestamps();
$table->foreign('release_id')->references('id')->on('releases')->onUpdate('cascade')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('files');
}
}
files/create.blade.php
...
<div class="upload-let">
<!-- Form element for Dropzone -->
<form action="{{route('files.store')}}" method="post" enctype="multipart/form-data" id="my-awesome-dropzone" class="dropzone" role="form">
{{Form::hidden('_token', csrf_token())}}
{{Form::hidden('release_id', $release->id)}}
{{Form::hidden('app_id', $release->app_id)}}
<div class="fallback">
<input name="file" type="file" multiple/>
</div>
</form>
</div>
{{Form::open(['route' => ['releases.approveme', $release->id], 'role' => 'form'])}}
<p class="text-center">
<button type="submit" class="btn btn-primary my-submit" data-loading-text="{{trans('messages.working')}}">{{trans('releases.done')}}</button>
<a class="btn btn-default cancel-hook my-submit" data-release-id="{{$release->id}}" data-loading-text="{{trans('messages.working')}}">{{trans('releases.cancel')}}</a>
</p>
{{Form::close()}}
...
@section('script')
<!-- Dropzone library -->
<script src="/js/vendor/dropzone/dropzone.min.js"></script>
<script>
(function() {
// Dropzone initialization
Dropzone.options.myAwesomeDropzone = {
dictDefaultMessage: "<div class=\"text-center text-muted\"><h2>{{trans('messages.dropzone_headline')}}</h2><p>{{trans('messages.dropzone_subhead')}}</p></div>",
maxFilesize: 100,
addRemoveLinks: true,
init: function () {
this.on("error", function (file, response, xhr) {
utility.flashMessage(response.error, "danger", 5000);
});
this.on("success", function (file, response) {
if (response.data) utility.flashMessage("{{trans('messages.file_saved')}}", "success", 3000);
else utility.flashMessage(response.error, "danger", 5000);
});
}
};
})();
</script>
@stop
FilesController:
...
/**
* Store a newly created resource in storage.
* POST /files
*
* @return \Illuminate\Http\Response
*/
public function store()
{
$file = Input::file('file');
if (! Input::hasFile('file'))
return Response::json(['error'=>'File too big.'], 422);
$release = Releases::find(Input::get('release_id'));
$app = Apps::find(Input::get('app_id'));
$directory = files_path($app->package, $release->version_code);
try
{
$data = save_file($file, $directory);
$data = array_merge($data, [
'release_id' => $release->id
]);
$this->newForm->validate($data);
$file = $this->repo->create($data);
}
catch (FileAlreadyExistsException $e)
{
return $this->setStatusCode(400)->respond(['error' => 'Duplicate file name !']);
}
catch (FileSaveFailedException $e)
{
return $this->setStatusCode(500)->respond(['error' => 'File save failed !']);
}
catch (airplug\Exceptions\FormValidationException $e)
{
return $this->setStatusCode(422)->respond(['error' => implode(' | ', $e->getErrors())]);
}
Event::fire('cache.flush', ['files']);
Event::fire('logs.record', [json_encode($file->toArray(), JSON_PRETTY_PRINT)]);
return $this->respond(['data' => $file->toArray()]);
}
/**
* Delete a given file from file system
*
* @param \Files $file
* @throws Illuminate\Filesystem\FileNotFoundException
* @return bool
*/
public function deleteFile(\Files $file)
{
$app = Apps::find($file->release->app_id);
$directory = files_path($app->package, $file->release->version_code);
$path = $directory . '/' . $file->filename;
if (! File::exists($path)) throw new FileNotFoundException;
Event::fire('logs.record', ['Deleted-' . $path]);
return File::delete($path);
}
...
ReleasesController:
...
/**
* Store a newly created resource in storage.
* POST /releases
*
* @return \Illuminate\Http\Response
*/
public function store()
{
$data = array_except(Input::all(), ['_method', '_token']);
$app = Apps::find($data['app_id']);
$expires_at = ! Input::get('expires_at') ? : Carbon::now()->addMonths(2)->toDateTimeString();
$data = array_merge($data, [
'app_name' => $app->name,
'package' => $app->package,
'expires_at' => $expires_at
]);
$this->newForm->validate($data);
if (! $release = $this->repo->create($data))
{
Flash::error('Something went wrong! Please try again.');
return Redirect::back()->withInput();
}
Event::fire('cache.flush', ['releases']);
Event::fire('logs.record', [json_encode($data, JSON_PRETTY_PRINT)]);
Flash::success('Metadata saved ! Attach a file(s) now !');
return View::make('files.create')->with(compact('release'));
}
...
helpers.php:
...
/**
* Resize and save image file
*
* @param \Symfony\Component\HttpFoundation\File\UploadedFile $file
* @param $path
* @param string $prefix
* @param int $width
* @return array|bool
*/
function save_image(Symfony\Component\HttpFoundation\File\UploadedFile $file, $path, $prefix = 'img', $width = 720)
{
$file_name = $prefix . '_' . time() . '_' . $file->getClientOriginalName();
$save_path = $path . '/' . $file_name;
$image = Image::make($file->getRealPath());
if ($image->width() > $width)
{
$image->resize($width, null, function ($constraint)
{
$constraint->aspectRatio();
});
}
if ($image->save($save_path))
{
return [
'filename' => $file_name,
'size' => $file->getSize()
];
}
return false;
}
...
Hi, I get this error: Uncaught TypeError: Cannot read property 'addEventListener' of null..I want to make when I cick button to submit form, images to upload.... and this is my code... add.blade.php part:
<div class="col-md-6">
<button type="submit" id="add" class="btn btn-block btn-primary "><i class="fa fa-check-square-o"></i> Spremi</button>
</div>
and js file
Dropzone.options.myAwesomeDropzone = { // The camelized version of the ID of the form element
// The configuration we've talked about above
autoProcessQueue: false,
uploadMultiple: true,
parallelUploads: 100,
maxFiles: 100,
// The setting up of the dropzone
init: function() {
var myDropzone = this;
// First change the button to actually tell Dropzone to process the queue.
this.element.querySelector("button[type=submit]").addEventListener("click", function(e) {
// Make sure that the form isn't actually being sent.
e.preventDefault();
e.stopPropagation();
myDropzone.processQueue();
});
// Listen to the sendingmultiple event. In this case, it's the sendingmultiple event instead
// of the sending event because uploadMultiple is set to true.
this.on("sendingmultiple", function() {
// Gets triggered when the form is actually being sent.
// Hide the success button or the complete form.
});
this.on("successmultiple", function(files, response) {
// Gets triggered when the files have successfully been sent.
// Redirect user or notify of success.
});
this.on("errormultiple", function(files, response) {
// Gets triggered when there was an error sending the files.
// Maybe show form again, and notify user of error
});
}
}
how to name the submit button to be recognized in js? I dont know js... :(
The error means JS can't find the element, either put the JS below the HTML or add a document.ready to it (not that great at JS myself but I know the error is that).
$(document).ready(function() {
// Handler for .ready() called.
});
thanks, solved it! Not, next problem :) Images are uploaded...now how to handle if images are uploaded, but form validation is not working...? code: DocumentController
//Process adding new document
public function postAdd()
{
if(!Document::isValid(Input::all()))
{
/*return Redirect::back()->with('errorMessage','Pokušajte ponovno! Dogodila se greška!')
->withErrors(Document::$errors);*/
return Response::json('error',500);
}
$document = new Document();
$document->title = Input::get('title');
$document->description = Input::get('description');
$document->project_id = Input::get('project');
$document->user_id = Auth::user()->id;
$document->save();
if(Input::hasFile('file'))
{
$files = Input::file('file');
foreach($files as $file)
{
//$file = Input::file('attachment');
$destinationPath = 'uploads/document-attachments';
//$filename = $file->getClientOriginalName();
$upload_success = $file->move($destinationPath, $file->getClientOriginalName());
if($upload_success)
{
$attachment = new DocumentAttachment();
$attachment->attachmentname = $file->getClientOriginalName();
$attachment->document_id = $document->id;
$attachment->attachmentsize = $upload_success->getSize();
$attachment->format = '1';
$attachment->save();
}
}
}
return Redirect::to('documents')->with('successMessage','Dokument je dodan u sustav!');
}
my-dropzone.js
Dropzone.options.myAwesomeDropzone = { // The camelized version of the ID of the form element
// The configuration we've talked about above
autoProcessQueue: false,
previewsContainer: ".dropzone",
uploadMultiple: true,
parallelUploads: 25,
maxFiles: 25,
// The setting up of the dropzone
init: function() {
var myDropzone = this;
// Here's the change from enyo's tutorial...
$("#submit-all").click(function (e) {
e.preventDefault();
e.stopPropagation();
myDropzone.processQueue();
}
);
this.on("successmultiple", function(files, response) {
window.location.href="http://pmrinels/documents";
});
this.on("complete", function(file) {
myDropzone.removeFile(file);
});
this.on("errormultiple", function(files, response) {
});
}
}
In my from I have two sections, one section for "document name, document description, document project"...other part is dropzone section...where I drop images...
1) I drop images, they are not uploading, thats good, only when I click form submit. 2) But, when I click submit, images are uploaded, document is saved in db....but no redirection. It stucks on document add form. I want: - If everithing is not ok, to Laravel process the form, redirect...show errorr.... - If is ok, show success message with Laravel.
Since Dropzone JS does separate POST requests per file, it would be best to use the Javascript for redirection on complete.
this.on("complete", function(file) {
myDropzone.removeFile(file);
// Add redirection code here
});
1) If I dont want to upload image, form is not posted. I need to add at least one image. 2) If images are uploaded, but form validation for other fields is not passed, it redirects, like it is passed validation. Becouse of JS. 3) Upload container is show over my form fields, how to show it in one "section" 4) :)
Ah, I didn't add a redirection on mine so couldn't say it was on full complete or per image. Do you NEED to redirect?
I need to solve these 3 questions :) last post...
Goes beyond my level of help but I put inputs inside the upload for Dropzone JS. Makes it nice for a "per image" field.

hi lukacavic, I have a same problem with upload on click with dropezone, how you could resolve this problem ? I follow your code but I can't upload it to database , did you use Appkr solution by separate file save and meta-data save? or you use another solution . can I look all your code ?
Please or to participate in this conversation.