In this post, we will create a image gallery. As we know, image gallery is one of the major elements in web development for most of the projects. Off course, they should be dynamic which we are going to build. We will be using Laravel framework. We will start from fresh laravel installation.
Install Project
First, lets’s install a fresh laravel project using the command below:
composer create-project laravel/laravel gallery
Database Setup
Next, we need to setup our database configuration to match our scenario. I am going to use mysql database with the following configuration in .env
file.
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=gallery DB_USERNAME=root DB_PASSWORD=secret
Create Model, Migration and Controller
We will use a single artisan command to create our model, migration and controller with resource. To do so, execute the following command:
php artisan make:model Gallery -m -c --resource
Configure Model
Let’s make some changes to our model to match our needs. We will have image, thumbnail, title and status of image in our database. So, after changing it, our model looks like below:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Gallery extends Model { protected $table = 'galleries'; protected $fillable = ['image', 'thumbnail', 'title', 'status']; }
Modify Migration
As stated earlier, we will modify our migration file adding some columns for image and others. The image
and thumbnail
will store image name with location. The title
will store image description. On the other hand, status
will store integer value for defining active or in-active.
public function up() { Schema::create('galleries', function (Blueprint $table) { $table->increments('id'); $table->string('image'); $table->string('thumbnail')->nullable(); $table->string('title')->nullable(); $table->integer('status'); $table->timestamps(); }); }
Modify Controller
It’s time to modify our controller. We will display a upload form above the images form. The <code>Store</code> method will save the data into database, the update
method will update the database and the destroy
method will delete the record from database.
We have added the controller code to do the above functions. Thus our final GalleryController
looks like below:
<?php namespace App\Http\Controllers; use File; use Image; use App\Gallery; use Illuminate\Http\Request; class GalleryController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { $images = Gallery::paginate(10); return view('galleries.index', ['images' => $images]); } /** * 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, [ 'image' => 'required', 'image.*' => 'image|mimes:jpeg,jpg,png,gif|max:8000' ]); if ($request->hasFile('image')) { $images = $request->file('image'); $org_img = $thm_img = true; if( ! File::exists('images/gallery/originals/')) { $org_img = File::makeDirectory(public_path('images/gallery/originals/'), 0777, true); } if ( ! File::exists('images/gallery/thumbnails/')) { $thm_img = File::makeDirectory(public_path('images/gallery/thumbnails'), 0777, true); } foreach($images as $key => $image) { $gallery = new Gallery; $filename = rand(1111,9999).time().'.'.$image->getClientOriginalExtension(); $org_path = 'images/gallery/originals/' . $filename; $thm_path = 'images/gallery/thumbnails/' . $filename; $gallery->image = 'images/gallery/originals/'.$filename; $gallery->thumbnail = 'images/gallery/thumbnails/'.$filename; $gallery->title = $request->title; $gallery->status = $request->status; if ( ! $gallery->save()) { flash('Gallery could not be updated.')->error()->important(); return redirect()->back()->withInput(); } if (($org_img && $thm_img) == true) { Image::make($image)->fit(900, 500, function ($constraint) { $constraint->upsize(); })->save($org_path); Image::make($image)->fit(270, 160, function ($constraint) { $constraint->upsize(); })->save($thm_path); } } } flash('Image uploaded successfully.')->success(); return redirect()->action('GalleryController@index'); } /** * Display the specified resource. * * @param \App\Gallery $gallery * @return \Illuminate\Http\Response */ public function show(Gallery $gallery) { // } /** * Show the form for editing the specified resource. * * @param \App\Gallery $gallery * @return \Illuminate\Http\Response */ public function edit(Gallery $gallery) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param \App\Gallery $gallery * @return \Illuminate\Http\Response */ public function update(Request $request, Gallery $gallery) { $image = Gallery::findOrFail($request->id); if ($image->status == 1) { $image->status = 0; $status = 'disabled'; } else { $image->status = 1; $status = 'enabled'; } if ( ! $image->save()) { flash('Image could not be reverted.')->error(); return redirect()->route('gallery.index'); } flash('Image has been successfully '.$status)->success(); return redirect()->route('gallery.index'); } /** * Remove the specified resource from storage. * * @param \App\Gallery $gallery * @return \Illuminate\Http\Response */ public function destroy($id) { $post = Gallery::findOrFail($id); if ($post->delete()) { flash('Image successfully deleted.')->success(); } else { flash('Image could not be deleted.')->error(); } return redirect()->route('gallery.index'); } }
Create View
Now, let’s create our frontend view. I have used Gentelella theme for dashboard but I will not be showing in this tutorial. Thus, we will create a simple view that meets our requirements.
<!DOCTYPE html> <html lang="en"> <head> <title>Image gallery with Laravel</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> </head> <body> <div class="clearfix"></div> <div class="row"> <div class="col-md-12 col-sm-12 col-xs-12"> <div class="x_panel"> <div class="x_title"> <h2>Listing Images</h2> <div class="clearfix"></div> </div> <div class="x_content"> <br /> <form method="POST" action="{{ route('gallery.store') }}" enctype="multipart/form-data" class="form-inline"> <p><small>Note: Total size of uploading files shold not be greater than 8 MB.</small></p> <div class="form-group"> <label for="">Image</label> <input type="file" name="image[]" accept="image/png, image/jpeg, image/jpg, image/gif" class="form-control" multiple/> <input type="text" name="title" placeholder="Image description (Optional)" class="form-control"/> <select name="status" class="form-control"> <option value="1">Publish</option> <option value="0">Save in draft</option> </select> {{ csrf_field() }} <button type="submit" class="btn btn-success" style="margin-bottom: 0px;">Upload</button> </div> </form> <div class="ln_solid"></div> @if(empty($images->count())) <p>No record found.</p> @else <div class="table-responsive"> <table class="table table-bordered table-striped"> <thead> <tr> <th>SN</th> <th>Image</th> <th>Status</th> <th>Date/Time Added</th> <th>Operations</th> </tr> </thead> <tbody> @foreach ($images as $image) <tr> <td>{{ (($images->currentPage() - 1 ) * $images->perPage() ) + $loop->iteration }}</td> <td><img class="img-responsive thumbnail_img" src="{{ asset($image->thumbnail) }}" /></td> <td> @if($image->status == 1) <span class="enable">Active</span> @else <span class="disable">Inactive</span> @endif </td> <td>{{ $image->updated_at->format('F d, Y') }}</td> <td> <form action="{{ route('gallery.update', $image->id) }}" method="post" onsubmit="return confirm('Revert process will Enable/Disable the image. Continue?');"> {{ csrf_field() }} <input type="hidden" name="_method" value="put" /> <input type="hidden" name="id" value="{{ $image->id }}" /> <button type="submit" class="btn btn-sm btn-info action_btn">Revert</button> </form> <form action="{{ route('gallery.destroy', $image->id) }}" method="post" onsubmit="return confirm('Are you sure you want to delete this record?');"> <input type="hidden" name="_method" value="DELETE" /> {{ csrf_field() }} <button type="submit" name="Delete" class="btn btn-sm btn-danger action_btn">Delete</button> </form> </td> </tr> @endforeach </tbody> </table> @if($images->total() != 0) <div>Showing {{ ($images->currentpage()-1) * $images->perpage()+1}} to {{(($images->currentpage()-1) * $images->perpage())+$images->count()}} of {{$images->total()}} records </div> {{ $images->links() }} @else No records found. @endif </div> @endif </div> </div> </div> </div> </body> </html>
I have added a revert
button. Click on the button will revert the status of image i.e. disable it if it’s enabled and vice-versa.
Add Route
We need to add routes for our system. For this, we will use route resource
. Simply add the following in web.php file.
Route::resource('gallery', 'GalleryController');
All set, good to go! Now, it’s time to test our system. Run your local host and navigate to the route /gallery
, you will see the frontend as screenshot above. You can play with revert
and delete
button. They are functional. Yey!
If you have any comment or issues regarding the implementation, don’t forget to drop a comment below.