I have 2 tables: articles and images
#articles: id, user_id, title, body
#images: id, original_name, filename, article_id
I am trying to upload multiple images using Dropzone on the create article view.
The problem is the Dropzone plugin submits the image to the database as soon as I drag/drop it into the box, even before creating the article to be able to get its id.
So far the upload is working, but I can't associate it with an article_id. I've tried associating it with Auth::user()->id and that worked.
How do I go about achieving this?
In my ArticleController
public function syncTags(Article $article, array $tags) {
$article->tags()->sync($tags);
}
/**
* @param ArticleRequest|BlogRequest $request
* @return mixed
*/
public function createArticle(Requests\ArticleRequest $request) {
$article = Auth::user()->articles()->create($request->all());
$this->syncTags($article, $request->input('tag_list'));
return $article;
}
public function postUpload() {
$photo = Input::all();
$response = $this->image->upload($photo);
return $response;
}
In Article Model
public function image() {
return $this->hasMany('App\Image');
}
In Image Model
public function article() {
return $this->belongsTo('App\Article');
}
ImageRepository
<?php
namespace App\Logic\Image;
use Auth;
use App\Article;
use App\Image;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\File;
use Intervention\Image\ImageManager;
class ImageRepository
{
public function upload( $form_data )
{
$validator = Validator::make($form_data, Image::$rules, Image::$messages);
if ($validator->fails()) {
return Response::json([
'error' => true,
'message' => $validator->messages()->first(),
'code' => 400
], 400);
}
//$articleId = $article->id;
$photo = $form_data['file'];
$originalName = $photo->getClientOriginalName();
$originalNameWithoutExt = substr($originalName, 0, strlen($originalName) - 4);
$filename = $this->sanitize($originalNameWithoutExt);
$allowed_filename = $this->createUniqueFilename( $filename );
$filenameExt = $allowed_filename .'.jpg';
$uploadSuccess1 = $this->original( $photo, $filenameExt );
$uploadSuccess2 = $this->icon( $photo, $filenameExt );
if( !$uploadSuccess1 || !$uploadSuccess2 ) {
return Response::json([
'error' => true,
'message' => 'Server error while uploading',
'code' => 500
], 500);
}
$sessionImage = new Image;
$sessionImage->filename = $allowed_filename;
$sessionImage->original_name = $originalName;
//$sessionImage->article_id = $articleId;
$sessionImage->save();
return Response::json([
'error' => false,
'code' => 200
], 200);
}
public function createUniqueFilename( $filename )
{
$full_size_dir = Config::get('images.full_size');
$full_image_path = $full_size_dir . $filename . '.jpg';
if ( File::exists( $full_image_path ) )
{
// Generate token for image
$imageToken = substr(sha1(mt_rand()), 0, 5);
return $filename . '-' . $imageToken;
}
return $filename;
}
/**
* Optimize Original Image
*/
public function original( $photo, $filename )
{
$manager = new ImageManager();
$image = $manager->make( $photo )->encode('jpg')->save(Config::get('images.full_size') . $filename );
return $image;
}
/**
* Create Icon From Original
*/
public function icon( $photo, $filename )
{
$manager = new ImageManager();
$image = $manager->make( $photo )->encode('jpg')->resize(200, null, function($constraint){$constraint->aspectRatio();})->save( Config::get('images.icon_size') . $filename );
return $image;
}
/**
* Delete Image From Session folder, based on original filename
*/
public function delete( $originalFilename)
{
$full_size_dir = Config::get('images.full_size');
$icon_size_dir = Config::get('images.icon_size');
$sessionImage = Image::where('original_name', 'like', $originalFilename)->first();
if(empty($sessionImage))
{
return Response::json([
'error' => true,
'code' => 400
], 400);
}
$full_path1 = $full_size_dir . $sessionImage->filename . '.jpg';
$full_path2 = $icon_size_dir . $sessionImage->filename . '.jpg';
if ( File::exists( $full_path1 ) )
{
File::delete( $full_path1 );
}
if ( File::exists( $full_path2 ) )
{
File::delete( $full_path2 );
}
if( !empty($sessionImage))
{
$sessionImage->delete();
}
return Response::json([
'error' => false,
'code' => 200
], 200);
}
function sanitize($string, $force_lowercase = true, $anal = false)
{
$strip = array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]",
"}", "\\", "|", ";", ":", "\"", "'", "‘", "’", "“", "”", "–", "—",
"—", "–", ",", "<", ".", ">", "/", "?");
$clean = trim(str_replace($strip, "", strip_tags($string)));
$clean = preg_replace('/\s+/', "-", $clean);
$clean = ($anal) ? preg_replace("/[^a-zA-Z0-9]/", "", $clean) : $clean ;
return ($force_lowercase) ?
(function_exists('mb_strtolower')) ?
mb_strtolower($clean, 'UTF-8') :
strtolower($clean) :
$clean;
}
}
routes.php
Route::resource('articles', 'ArticlesController');
// dropzone upload
Route::post('upload', ['as' => 'upload-post', 'uses' =>'ArticlesController@postUpload']);
Route::post('upload/delete', ['as' => 'upload-remove', 'uses' =>'ArticlesController@deleteUpload']);
And this is create.blade.php - I was compelled to include it as I'm using 2 forms on the same page. Can this even work?
{!! Form::open(['url' => 'articles', 'id' => 'frm']) !!}
<p>
{!! Form::label('title', 'Title:') !!}
{!! Form::text('title', null, ['class' => 'form-control']) !!}
</p>
<div class="editor">
<p>
{!! Form::label('body', 'Body:') !!}
{!! Form::textarea('body', null, ['class' => 'form-control', 'id' => 'myEditor']) !!}
</p>
</div>
<p>
{!! Form::label('published_at', 'Date:') !!}
{!! Form::input('date', 'published_at', date('Y-m-d'), ['class' => 'form-control']) !!}
</p>
<p>
{!! Form::label('tag_list', 'Tags:') !!}
{!! Form::select('tag_list[]', $tags, null, ['class' => 'form-control', 'multiple']) !!}
</p>
<p>
{!! Form::submit('Submit Article', ['id' => 'submit']) !!}
</p>
{!! Form::close() !!}
<div class="row">
<div class="col-md-offset-1 col-md-10">
<div class="jumbotron how-to-create" >
<h3>Images <span id="photoCounter"></span></h3>
<br />
{!! Form::open(['url' => route('upload-post'), 'class' => 'dropzone', 'files'=>true, 'id'=>'real-dropzone']) !!}
<div class="dz-message">
</div>
<div class="fallback">
<input name="file" type="file" multiple />
</div>
<div class="dropzone-previews" id="dropzonePreview"></div>
<h4 style="text-align: center;color:#428bca;">Drop images in this area <span class="glyphicon glyphicon-hand-down"></span></h4>
{!! Form::close() !!}