Spread the love

In this article i will learn CRUD with Search, Image and Pagination in laravel 9. In this post we will not only cover the CRUD operation but also the validation on form, unique validation, image uploading and view the uploaded image, Flash messages, Search the uploaded data and many more.

This is important we learn each and every aspect of crud and the above the crud like uploading , searching and all. As we know CRUD is full form is Create, Read, Update and Delete. Crud is the basic operation is in all programming languages and we will cover all the aspects in this tutorial.

In the example first we will create a project then make the appropriate database connections to connect our application with mysql. After that we will create a resource controller which gives us default routes for add edit and delete functionalities.

In our list page we will include the pagination and searching as well so user can search by email and title easily. Pagination to show data in chunk that will optimize our page to load data on request. In our form page we will take 4 fields title, email , body and Image. I figured it out that most of the laravel crud examples do not cover the unique and image uploading but here we will cover that too.

So let’s learn Laravel 9 CRUD with Search, Image and Pagination step by step

Step 1: Create a laravel project

First step is to create the Laravel 8 project using composer command or you can also read the How to install laravel 8 ? and Laravel artisan command to generate controllers, Model, Components and Migrations

composer create-project laravel/laravel crud

Step 2: Configure database

Next step is to configure the database for our project, table and data. So open .env or if file not exist then rename .env.example file to .env file in root folder and change below details

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=test
DB_USERNAME=root
DB_PASSWORD=

Step 3: Create Model and Migration

If you have table and large data already then you can skip this step but if you are beginner and trying to implement Crud then in this step we are creating a model and migration using artisan command

php artisan make:model Article -m

Above command will create two files one is migration and other one is model. open migration file which is located at database/migrations/timestamp_create_articles_table.php and edit the schema as below

  public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->id();
            $table->string('email')->unique();;
            $table->string('title');
            $table->string('body')->nullable();;
            $table->string('image');
            $table->timestamps();
        });
    }

Run migration using artisan command in command line

php artisan migrate

Output of above command

Migrating: 2022_06_25_112800_create_articles_table
Migrated:  2022_06_25_112800_create_articles_table (45.63ms)

Step 4 : Create a controller

Next, Create the resource controller and add the necessary imports and class. You can create by Laravel artisan or manually.

php artisan make:controller ArticleController --resource

Now, add the controller logic for pagination

<?php

namespace App\Http\Controllers;

use App\Models\Article;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class ArticleController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        $articles = Article::when($request->has("title"), function ($q) use ($request) {
            return $q->where("title", "like", "%" . $request->get("title") . "%");
        })
            ->when($request->has("email"), function ($q) use ($request) {
                return $q->where("email", "like", "%" . $request->get("email") . "%");
            })
            ->paginate(2);

        return view('articles.list ', ['articles' => $articles]);
    }

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

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'title' => "required",
            'email' => "required|email|unique:articles",
            'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:4096',
        ]);
        if ($validator->fails()) {
            return redirect()->back()->withInput()->withErrors($validator->errors());
        }
        $file = $request->file("image")->store("uploads/images");

        //  save image and name in database
        $Article = new Article();
        $Article->title = $request->title;
        $Article->email = $request->email;
        $Article->image = $file;
        $Article->body  = $request->body;
        $Article->save();
        return redirect()->route("articles.index")
            ->with('success', 'You have successfully created the article.');
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        return view('articles.update', ["article" => Article::find($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)
    {
        $validator = Validator::make($request->all(), [
            'title' => "required",
            'email' => "required|email|unique:articles,email," . $id,
            'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:4096',
        ]);
        if ($validator->fails()) {
            return redirect()->back()->withInput()->withErrors($validator->errors());
        }
        $file = $request->file("image")->store("uploads/images");

        //  save image and name in database
        $Article = new Article();
        $Article->title = $request->title;
        $Article->email = $request->email;
        $Article->image = $file;
        $Article->body  = $request->body;
        $Article->save();
        return redirect()->route("articles.index")
            ->with('success', 'You have successfully created the article.');
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        Article::find($id)->delete();
        return redirect()->route("articles.index")
            ->with('success', 'You have successfully deleted the article.');
    }
}

So as you can see we have created multiple methods and created their definitions in the method. So in index method we have simply fetched the all records from atricles table using model Article along with searching.

Then, we have store method where we have defined the validation rules and the definition logic for add the data in article table along with image uploading.

Next, we have edit and destroy method to update and delete the models.

So to configure the images we need tp create Symblink as follow

This is an important step and i suggest you to not skip this step, if you are going to show images in your website because you must need to access the image to show it on website so open config\filesystems.php and add public_path('uploads') => storage_path('app/uploads') to links block

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Default Filesystem Disk
    |--------------------------------------------------------------------------
    |
    | Here you may specify the default filesystem disk that should be used
    | by the framework. The "local" disk, as well as a variety of cloud
    | based disks are available to your application. Just store away!
    |
    */

    'default' => env('FILESYSTEM_DRIVER', 'public'),
    'disks' => [

        'local' => [
            'driver' => 'local',
            'root' => storage_path('app'),
        ],

        'public' => [
            'driver' => 'local',
            'root' => storage_path('app/public'),
            'url' => env('APP_URL').'/storage',
            'visibility' => 'public',
        ],

        's3' => [
            'driver' => 's3',
            'key' => env('AWS_ACCESS_KEY_ID'),
            'secret' => env('AWS_SECRET_ACCESS_KEY'),
            'region' => env('AWS_DEFAULT_REGION'),
            'bucket' => env('AWS_BUCKET'),
            'url' => env('AWS_URL'),
            'endpoint' => env('AWS_ENDPOINT'),
            'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
        ],

    ],
    'links' => [
        public_path('storage') => storage_path('app/public'),
        public_path('uploads') => storage_path('app/uploads'),
    ],

];

Since we are using in our controller this code

$destinationPath= '/uploads/images';
         
$storageDestinationPath=storage_path('app'.$destinationPath);

so we created a Symblink as

 public_path('uploads') => storage_path('app/uploads'),

Now run artisan command to run Symblink

php artisan storage:link

You can read Full article here How to access and setup storage files after upload in laravel ?

Step 5 : Create the views

Here in this step we will create 3 views as follow

  1. resources/views/articles/list.blade.php – To list all articles
  2. resources/views/articles/create.blade.php – To create article
  3. resources/views/articles/update.blade.php – To update the article

So here is the code for resources/viewa/articles/list.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Laravel CRUD with Search, Image and Pagination Example - Readerstacks </title>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js" crossorigin="anonymous"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js"></script>
    <link href="//netdna.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" />

</head>

<body class="antialiased">
    <div class="container">
        <!-- main app container -->
        <div class="readersack">
            <div class="container">
                <div class="row">
                    <div class="col-md-12 ">
                        <h3>Laravel CRUD with Search, Image and Pagination Example - Readerstacks</h3>
                        @if ($message = Session::get('success'))
                        <div class="alert alert-success alert-block">
                            <button type="button" class="close" data-dismiss="alert">×</button>
                            <strong>{{ $message }}</strong>
                        </div>

                        @endif
                        <a class='btn btn-info' href='{{url("articles/create")}}'>Add New</a>

                        <div id="search">

                            <form id="searchform" name="searchform">
                                <div class="row">

                                    <div class="form-group col-3">
                                        <label>Search by Title</label>
                                        <input type="text" name="title" value="{{request()->get('title','')}}" class="form-control" />


                                    </div>
                                    <div class="form-group col-3">
                                        <label>Search by Email</label>
                                        <input type="text" name="email" value="{{request()->get('email','')}}" class="form-control" />


                                    </div>
                                    <div class="form-group col-3">
                                        <label>Search by body</label>
                                        <input type="text" name="body" value="{{request()->get('body','')}}" class="form-control" />


                                    </div>
                                </div>
                                <button class='btn btn-success'>Search</button>
                            </form>


                        </div>
                        <div id="pagination_data">
                            <table class="table table-striped table-dark table-bordered">
                                <tr>
                                    <th>Sr No.</th>
                                    <th>Title</th>
                                    <th>Email</th>
                                    <th>Image</th>
                                    <th>Body</th>

                                    <th>Date</th>
                                    <th>Action</th>
                                </tr>
                                @foreach($articles as $article)
                                <tr>
                                    <td>{{$article->id}}</td>
                                    <td>{{$article->email}}</td>

                                    <td>{{$article->title}}</td>
                                    <td><img src="{{url($article->image)}}" width=100 /></td>
                                    <td>{{substr($article->body,0,50)}}</td>
                                    <td>{{$article->created_at}}</td>
                                    <td>

                                        <a href="{{route('articles.edit',$article->id) }}" class="btn btn-success">Edit</a>
                                        <form action="{{ route('articles.destroy',$article->id) }}" method="Post">
                                            @csrf
                                            @method('DELETE')
                                            <button type="submit" class="btn btn-danger">Delete</button>
                                        </form>


                                    </td>
                                </tr>
                                @endforeach
                            </table>
                            <div id="pagination">
                                {{ $articles->links() }}
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <!-- credits -->
        <div class="text-center">
            <p>
                <a href="#" target="_top">Laravel CRUD with Search, Image and Pagination Example
                </a>
            </p>
            <p>
                <a href="https://readerstacks.com" target="_top">readerstacks.com</a>
            </p>
        </div>
    </div>

</body>

</html>

Here is the main code where we called $articles->links() and foreach loop to show the data.

And then create file

resources/views/articles/create.blade.php

<!DOCTYPE html>
<html>

<head>
    <title> Laravel CRUD with search, image and pagination Example  - readerstacks.com</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>

<body>
    <div class="container">

        <div class="panel panel-primary">
            <div class="panel-heading">
                <h2> Laravel CRUD with search, image and pagination Example -readerstacks.com</h2>
            </div>
            <div class="panel-body">

                @if ($message = Session::get('success'))
                <div class="alert alert-success alert-block">
                    <button type="button" class="close" data-dismiss="alert">×</button>
                    <strong>{{ $message }}</strong>
                </div>

                @endif
                @if ($errors->any())
                <div class="alert alert-danger">
                    <ul>
                        @foreach ($errors->all() as $error)
                            <li>{{ $error }}</li>
                        @endforeach
                    </ul>
                </div>
            @endif
                <br><br>
                <form action="{{ url('articles') }}" method="POST" enctype="multipart/form-data">
                    @csrf
                    <div class="row">

                        <div class="col-md-4">
                            <label>Title</label>
                            <input type="text" placeholder="Title" value="{{ old('title') }}" name="title" class="form-control">
                        </div>
                        <div class="col-md-4">
                            <label>Email</label>
                            <input type="email" placeholder="Email" value="{{ old('email') }}" name="email" class="form-control">
                        </div>
                        <div class="col-md-4">
                            <label>Body</label>
                            <input type="text" placeholder="Body" value="{{ old('body') }}" name="body" class="form-control">
                        </div>
                        <div class="col-md-4">
                            <label>Image</label>
                             <input type="file" placeholder="Image" name="image" id="imgInp">
                              <img style="visibility:hidden"  id="prview" src=""  width=100 height=100 />
                      
                    </div>
                     </div>
                    <div class="row">



                        <div class="col-md-6">
                            <button type="submit" class="btn btn-success">Add</button>
                        </div>

                    </div>
                </form>
                
        </div>
    </div>
</body>
<script>
imgInp.onchange = evt => {
  const [file] = imgInp.files
  if (file) {
    prview.style.visibility = 'visible';

    prview.src = URL.createObjectURL(file)
  }
}
</script>
</html>


and final file for update resources/views/articles/update.blade.php

Step 6 : Create Route

Last and final step is to create the route for our resource controller to serve the CRUD

<?php

use Illuminate\Support\Facades\Route;
use \App\Http\Controllers\ArticleController;


Route::resource('articles', ArticleController::class);

You can read more about resource controller How to create resource controller in Laravel 8 ?

Now run the the application using php artisan serve and check our implementation

Leave a Reply