Image upload in Laravel - BOOKC -->

Image upload in Laravel

Friday, March 23, 2018


Hey Guys! I think you are no familiar with Laravel to some extent. Images plays a vital role in designing of a web page. We can use images in many ways to describe more things at a glance instead of words. Here I will explain how to upload images into a database using Laravel framework.

In this article, I will create a simple application to upload Blog posts with images. Let's start!

Things we need additionally:

  • Laravel Collective package         -    For form binding
  • CK Editor                                     -   Text editor 
  • Dropify CSS and JS                     -    For displaying uploading image
  • Bootswatch CDN for bootstrap   -    For styling of pages
First create a database to upload posts. I created one called laravel_image. Then go to a folder where you want to place your application.

cd C:\xampp\htdocs\Laravel

Create a project using Laravel. Give a name you want. I named my project as Image_Upload.

composer create-project laravel/laravel Image_Upload

Run the project: php artisan serve

This is a bit long tutorial...So, patience is needed Guys!

Now open the project using an IDE or Text Editor. As a start, edit the two DB config files. Edit .env file and config/database.php file in the project folder.

.env file

 config/database.php


Create a model 

Go into database/migration folder. Delete the existing migration files Next step is to to create a model for posts. Use singular name for model name and then the migration table will have a table with its plural name.

php artisan make:model Post -m

Edit the model and place this code.
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
// table name
protected $table = 'posts';
// primary key
public $primaryKey = 'id';
// Timestamps
public $timestamps = true;
}
Now you can see a migration file created by Laravel in this folder.

Database Migrations

Open the newly created migration file and edit like this.


<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePostsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('body');
$table->timestamps();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('posts');
}
}

There's another special thing to do in order to avoid our database migration errors. Open app/Http/Providers/AppServiceProvider.php file included in the project. Copy this and replace into this file. Then boot function will be replaced.

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;

class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}

/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
}

Now migrate the files. Open cmd and type this command.

php artisan migrate

Are you following me? I think so...Go yo phpmyadmin and look for DB tables. Both posts and migrations tables should be there.


Integrate CK Editor, Laravel Collective, Dropify and Boostrap

1. CK Editor

Go to below link and see the documentation.
https://github.com/UniSharp/laravel-ckeditor
Open a cmd and type the first command.

composer require unisharp/laravel-ckeditor

Then edit config/app.php file as the they says. Add this line to the providers section at last.

Unisharp\Ckeditor\ServiceProvider::class,

Then type this command in cmd. That's all..The way to use this will be explained later.

php artisan vendor:publish --tag=ckeditor


2. Laravel Collective

Go to below link and see the documentation.
https://laravelcollective.com/docs/master/html
Open a cmd and type the first command.

composer require "laravelcollective/html":"^5.4.0"

Then edit config/app.php file as the they says. Add this line to the providers section at last.

Collective\Html\HtmlServiceProvider::class,

Add this line to the aliases section at last.

'Form' => Collective\Html\FormFacade::class,

'Html' => Collective\Html\HtmlFacade::class,

Now you are allowed to use this package!

3. Dropify CSS and JS

Go to below GitHub link and download the folder. 
Then extract and open it. Copy the folder is the dist folder in it. Place this folder in public folder in your Laravel project. Name the folder as dropify.

4. Custom Bootstrap theme

Visit this link and select a theme. I selected Lumen style theme.


Create Controller for posts

Open a cmd and type the below command. Here I create a resource controller for my ease.

php artisan make:controller PostsController --resource

Place this code in it. -- PostsController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use App\Post;

class PostsController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$posts = Post::orderBy('id','desc')->paginate(5);
return view('posts.index')->with('posts',$posts)->withTitle('Blog');
}

/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}

/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$this->validate($request, [
'title' => 'required',
'body' => 'required',
'cover_image' => 'image|nullable|max:1999'
]);
// file upload
if($request->hasFile('cover_image')){
$fileNameWithExt = $request->file('cover_image')->getClientOriginalName();
// get file name
$filename = pathinfo($fileNameWithExt, PATHINFO_FILENAME);
// get extension
$extension = $request->file('cover_image')->getClientOriginalExtension();

$fileNameToStore = $filename.'_'.time().'.'.$extension;
// upload
$path = $request->file('cover_image')->storeAs('public/cover_images', $fileNameToStore);
}
else{
$fileNameToStore = 'noimage.jpg';
}
// create post
$post = new Post;
$post->title = $request->input('title');
$post->body = $request->input('body');
$post->cover_image = $fileNameToStore;
$post->save();
// redirect to the create page with success message
return redirect('/')->with('success', 'Post created');
}

/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
$post = Post::find($id);
return view('posts.show')->with('post',$post)->withTitle('Post Details');
}

/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}

/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}

/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}


Create views

Create two folders in  views folder called layouts and posts. Place the views in this order and structure. Otherwise my routes will not be compatible with you.

resources/views/layouts/master.blade.php


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootswatch/4.0.0/lumen/bootstrap.min.css">
<link rel="stylesheet" href="{{ asset('dropify/css/dropify.css' )}}">
<link href="https://fonts.googleapis.com/css?family=Roboto|Oswald|Michroma" rel="stylesheet" type="text/css">
</head>
<body>

@yield('content')

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="{{ asset('dropify/js/dropify.js' )}}"></script>
<script type="text/javascript">
$(document).ready(function(){
$('.dropify').dropify();
});
</script>
<script defer src="https://use.fontawesome.com/releases/v5.0.7/js/all.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>

resources/views/posts/index.blade.php

@extends('layouts.master')

@section('content')
<div class="container">
<h1 style="margin-top: 30px;" class="text-center">Blog Posts</h1><br>
<a href="/" class="btn btn-secondary"><i class="fas fa-arrow-alt-circle-left"></i> create post</a><br>
@include('messages')<br>
@if(count($posts)>0)
@foreach($posts as $post)
<div class="card">
<div class="row">
<div class="col-lg-4">
<img src="/storage/cover_images/{{$post->cover_image}}" alt="" style="height:222px;width:380px;">
</div>
<div class="col-lg-8">
<div class="card-header">
<h3><a href="/posts/{{$post->id}}">{{$post->title}}</a></h3>
</div>
<div class="card-body">
{!!$post->body!!}
</div>
<div class="card-footer">
<p class="card-text">Published on {{$post->created_at}}</p>
</div>
</div>
</div>

</div>
<br>
@endforeach
{{$posts->links()}}
@else
<h3>No posts</h3>
@endif
</div>
@endsection

resources/views/posts/create.blade.php

@extends('layouts.master')
@section('content')
<div class="container">
<br><br>
<div class="row">
<div class="col-lg-2"></div>
<div class="col-lg-8">
<h2>Create a Post</h2><br>
@include('messages')
{!! Form::open(['action' => 'PostsController@store', 'method' => 'POST', 'id' => 'post-form', 'enctype' => 'multipart/form-data']) !!}
<div class="form-group">
{{ Form::label('title', 'Title of the Post ', ['class' => 'form-label'] )}}
{{ Form::text('title', '', ['class' => 'form-control', 'placeholder' => 'Give a Title', 'id' => 'title']) }}
</div>
<div class="form-group">
{{ Form::label('body', 'Body of the Post ', ['class' => 'form-label'] )}}
{{ Form::textarea('body', '', ['class' => 'form-control', 'placeholder' => 'Give a Description', 'id' => 'body']) }}
</div>
<div class="form-group">
{{ Form::file('cover_image',['class' => 'dropify'])}}
</div>
<br>
{{ Form::submit('Post', ['class' => 'btn btn-primary']) }}
<a href="/posts" class="btn btn-dark">Read posts</a>
{!! Form::close() !!}
</div>
<div class="col-lg-2"></div>
</div>
<br><br><br>
</div>
<script src="/vendor/unisharp/laravel-ckeditor/ckeditor.js"></script>
<script>
CKEDITOR.replace( 'body' );
</script>
@endsection

resources/views/posts/show.blade.php


@extends('layouts.master')

@section('content')

<div class="container" style="margin-bottom: 50px;">
<a href="/posts" class="btn btn-secondary" style="margin-top: 30px;"><i class="fas fa-arrow-alt-circle-left"></i> Go Back</a>
<h1 style="margin-top: 30px;text-align: left;">{{$post->title}}</h1><br>
<div class="row">
<div class="col-lg-12">
<img src="/storage/cover_images/{{$post->cover_image}}" style="height:400px; width:1100px;"><br><hr style="width: 1100px;">
<p style="font-size:20px; text-align: justify;">{!!$post->body!!}</p><hr style="width: 1100px;">
<p style="font-size:14px;">Written on {{$post->created_at}}</p>
<br>
</div>
</div>
</div>
@endsection

Create Link between image uploading folder and retrieving folder

We can do this using a simple command. Type this in your cmd. Remember to navigate into the project folder!

php artisan storage:link


Now I'm going to explain some special sections...


1.How to use Dropify


In our master view file I have linked the Boostrap and Dropify CDNs and URLs. Then we can use dropify for input file tag. The javascript part has been included in the master file.

<script src="{{ asset('dropify/js/dropify.js' )}}"></script>
<script type="text/javascript">
$(document).ready(function(){
$('.dropify').dropify();
});
</script>

Then it will be converted like this instead of the usual button. Where do we want to include the dropify class?

<div class="form-group">
{{ Form::file('cover_image',['class' => 'dropify'])}}
</div>

The file input button will get a look like this...



2.How to use CK editor

In our master view file I have linked the CK editor CDN. Then we can use CK Editor for textarea tag. The javascript part has been included in the create blade file.

<script>
CKEDITOR.replace( 'body' );
</script>

This code gets the php name of the textarea field. It is body. Then it is replaced by the editor. Then text area will looks like this.


3. How to use Laravel Collective Form binding

Look at this codes..You can see a special conversion of FORM tags in create.blade.php. Got it?

{!! Form::open(['action' => 'PostsController@store', 'method' => 'POST', 'id' => 'post-form', 'enctype' => 'multipart/form-data']) !!}
<div class="form-group">
{{ Form::label('title', 'Title of the Post ', ['class' => 'form-label'] )}}
{{ Form::text('title', '', ['class' => 'form-control', 'placeholder' => 'Give a Title', 'id' => 'title']) }}
</div>
<div class="form-group">
{{ Form::label('body', 'Body of the Post ', ['class' => 'form-label'] )}}
{{ Form::textarea('body', '', ['class' => 'form-control', 'placeholder' => 'Give a Description', 'id' => 'body']) }}
</div>
<div class="form-group">
{{ Form::file('cover_image',['class' => 'dropify'])}}
</div>
<br>
{{ Form::submit('Post', ['class' => 'btn btn-primary']) }}
<a href="/posts" class="btn btn-dark">Read posts</a>
{!! Form::close() !!}

{{ Form::label() }}
This is the way how to create form using Laravel Collective HTML package. Within the brackets, we can pass several parameters like php name, placeholder, class, id and etc. If you have not included the Collective package as I told previously, you can not use this format.

That's all guys! Long tutorial? Yes it is..I tried my best to shorten the article..I have included all the important things. Actually Dropify, Laravel Collective, CK editor are not needed essentially. Still you can do without them. But I needed to give some additional knowledge. That's why I explained them also. Sorry about the length of the article.

So I will conclude this tutorial now..You can drop a comment if you have questions. Or you can drop me a message to my FB page..Link is given below.

TechPool Official FB Page


Good Bye guys!!!