Laravel 9 x CRUD with Tests
Tags: webdev, tutorial, laravel
Published: 2022-06-02 19:24:47



Hi there,

In this tutorial, we will see how to create a web application using Laravel version 9. We will build a  application from scratch.

We will create a Product [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) application. 

We will use [Bootstrap 5](https://getbootstrap.com/docs/5.0/) for Styling.


## Step 1: Create new Laravel application

Using the [Laravel installer](https://laravel.com/docs/9.x/installation#the-laravel-installer) to create a new application.

```sh
laravel new shop-app
cd shop-app
```

## Step 2: Database Configuration

We will update database configuration, we need to add database name, mysql username and password. 

Open `.env` file and fill all details like as bellow:

file: `.env`

```ini
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=blog
DB_USERNAME=root
DB_PASSWORD=""
```



## Step 3: Create Migrations

Here, we will create `products` table using laravel migration. so let's use following command to create migration file.

```sh
php artisan make:migration create_products_table --create=products
```

A file in "database/migrations" will be generated

```php
<?php
// ...
public function up() {
    Schema::create('products',  function  (Blueprint $table)  {
        $table->id();
        $table->string('name');
        $table->text('detail');
        $table->timestamps();
    });

}
// ....
```


```
php artisan migrate
```


## Step 4: Create Controller and Model

We create a new resource controller named `ProductController`. 

```sh
php artisan make:controller ProductController --resource --model=Product
```

A new file `app/Http/Controllers/ProductController.php`.

In this controller there will seven methods by default as bellow methods:


- 1) index() 
- 2) create() 
- 3) store()
- 4) show()
- 5) edit()
- 6) update()
- 7) destroy()

Copy code below and put on `ProductController.php` file.

file: `app/Http/Controllers/ProductController.php`
```php
<?php

namespace App\Http\Controllers;

use App\Models\Product;
use Illuminate\Http\Request;

class ProductController extends Controller {

  /**
   * Display a listing of the resource.
   *
   * @return \Illuminate\Http\Response
   */
  public  function index()
  {

    $products = Product::latest()->paginate(5);

    return view('products.index')
      ->with('products',$products);

  }

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

  /**
   * Store a newly created resource in storage.
   *
   * @param  \Illuminate\Http\Request  $request
   * @return \Illuminate\Http\Response
   */
  public  function store(Request $request) {
    $data = $request->validate([
      'name'  =>  'required|string',
      'detail'  =>  'required|string',
    ]);
    Product::create($data);

    return redirect()->route('products.index')
      ->with('success','Product created successfully.');

  }

  /**
   * Display the specified resource.
   *
   * @param  \App\Models\Product  $product
   * @return \Illuminate\Http\Response
   */
  public  function show(Product $product) {

      return view('products.show',compact('product'));

  }

  /**
   * Show the form for editing the specified resource.
   *
   * @param  \App\Models\Product  $product
   * @return \Illuminate\Http\Response
   */
  public  function edit(Product $product) {

    return view('products.edit',compact('product'));

  }

  /**
   * Update the specified resource in storage.
   *
   * @param  \Illuminate\Http\Request  $request
   * @param  \App\Models\Product  $product
   * @return \Illuminate\Http\Response
   */
  public  function update(Request $request,  Product $product) {
    $data = $request->validate([
      'name'  =>  'required',
      'detail'  =>  'required',
    ]);

    $product->update($data);
    return redirect()->route('products.index')
      ->with('success','Product updated successfully');
  }

  /**
 * Remove the specified resource from storage.
 *
 * @param  \App\Models\Product  $product
 * @return \Illuminate\Http\Response
 */
  public  function destroy(Product $product) {

    $product->delete();
    return redirect()->route('products.index')
      ->with('success','Product deleted successfully');
  }

}
```


file: `app/Models/Product.php`
```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{

  use HasFactory;

  protected $fillable = [
    'name', 
    'detail'
  ];

}
```

## Step 5: Add Resource Route

Here, we need to add resource route for product crud. 
Open your `routes/web.php` file and add following route.

file: `routes/web.php`
```php
<?php

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

// ...skippped
Route::resource('products',  ProductController::class);
```

## Step 6: Add Blade Files

In last step. In this step we have to create just blade files. So mainly we have to create layout file and then create new folder "products" then create blade files of crud app. So finally you have to create following bellow blade file:

- 1). layout.blade.php
- 2). index.blade.php
- 3). create.blade.php
- 4). edit.blade.php
- 5). show.blade.php

So let's just create following file and put bellow code.

file: `resources/views/products/layout.blade.php`
```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Laravel Application</title>
 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
    @yield('content')
</div>
</body>
</html>
```

file: `resources/views/products/index.blade.php`

```html
@extends('products.layout')

@section('content')
  <div  class="row">
  <div  class="col-lg-12 margin-tb">
    <div  class="pull-left">
       <h2>Laravel Shop | All Products</h2>
    </div>
    <div  class="pull-right">
        <a  class="btn btn-success" href="{{ route('products.create') }}"> Create New Product</a>
    </div>
  </div>
  </div>
 @if ($message = Session::get('success'))
  <div  class="alert alert-success"> 
    <p>{{ $message }}</p>
  </div>
 @endif

  <table class="table table-bordered">
  <tr>
    <th>No.</th>
    <th>Name</th>
    <th>Details</th>
    <th width="280px">Action</th>
  </tr>
  @foreach ($products as $product)
  <tr>
    <td>{{ $loop->iteration }}</td>
    <td>{{ $product->name }}</td>
    <td>{{ $product->detail }}</td>
    <td>
    <form  action="{{ route('products.destroy',$product->id) }}" method="POST">
    <a class="btn btn-info" href="{{ route('products.show',$product->id) }}">Show</a>
    <a class="btn btn-primary" href="{{ route('products.edit',$product->id) }}">Edit</a>
       @csrf
       @method('DELETE')
     <button type="submit" class="btn btn-danger">Delete</button>
    </form>
    </td>
  </tr>
 @endforeach
  </table>
 {!! $products->links() !!}
@endsection
```

file: `resources/views/products/create.blade.php`
```html
@extends('products.layout')

@section('content')
<div  class="row">
  <div  class="col-lg-12 margin-tb">
      <div  class="pull-left">
         <h2>Add New Product</h2>
      </div>
      <div class="pull-right">
          <a class="btn btn-primary"  href="{{ route('products.index') }}"> Back</a>
      </div>
  </div>
</div>

@if ($errors->any())
  <div  class="alert alert-danger">
    <strong>Whoops!</strong> There were some problems with your input.<br><br>
    <ul>
       @foreach ($errors->all() as $error)
         <li>{{ $error }}</li>
       @endforeach
    </ul>
  </div>
@endif

<form  action="{{ route('products.store') }}"  method="POST">

 @csrf
  <div class="row">
    <div class="col-xs-12 col-sm-12 col-md-12">
      <div class="form-group">
      <strong>Name:</strong>
      <input  type="text"  name="name"  class="form-control"  placeholder="Name">
    </div>
  </div>
  <div class="col-xs-12 col-sm-12 col-md-12">
    <div class="form-group">
      <strong>Detail:</strong>
      <textarea  class="form-control"  style="height:150px"  name="detail"  placeholder="Detail"></textarea>
    </div>
  </div>
  <div  class="col-xs-12 col-sm-12 col-md-12 text-center">
    <button  type="submit"  class="btn btn-primary">Submit</button>
  </div>
  </div>
</form>
@endsection
```
file: `resources/views/products/edit.blade.php`

```html
@extends('products.layout')

@section('content')
  <div class="row">
      <div class="col-lg-12 margin-tb">
          <div class="pull-left">
              <h2>Edit Product</h2>
          </div>
          <div  class="pull-right">
              <a  class="btn btn-primary"  href="{{ route('products.index') }}"> Back</a>
          </div>
      </div>
  </div>
 @if ($errors->any())
  <div  class="alert alert-danger">
     <strong>Whoops!</strong> There were some problems with your input.<br><br>
    <ul>
       @foreach ($errors->all() as $error)
         <li>{{ $error }}</li>
       @endforeach
    </ul>
  </div>
 @endif
  
  <form  action="{{ route('products.update',$product->id) }}" method="POST">
     @csrf
     @method('PUT')
  <div  class="row">
  <div  class="col-xs-12 col-sm-12 col-md-12">
    <div  class="form-group">
    <strong>Name:</strong>
    <input  type="text"  name="name"  value="{{ $product->name }}" class="form-control" placeholder="Name">
    </div>
  </div>
  <div  class="col-xs-12 col-sm-12 col-md-12">
    <div  class="form-group">
    <strong>Detail:</strong>
    <textarea  class="form-control"  style="height:150px"  name="detail"  placeholder="Detail">{{ $product->detail }}</textarea>
    </div>
  </div>
  <div  class="col-xs-12 col-sm-12 col-md-12 text-center">
    <button  type="submit"  class="btn btn-primary">Submit</button>
  </div>
  </div>
  </form>
@endsection
```


file: `resources/views/products/show.blade.php`
```html
@extends('products.layout')

@section('content')
  <div class="row">
  <div class="col-lg-12 margin-tb">
    <div class="pull-left">
      <h2>Show Product</h2>
    </div>
    <div  class="pull-right">
      <a  class="btn btn-primary"  href="{{ route('products.index') }}"> Back</a>
    </div>
  </div>
  </div>
  <div class="row">
  <div class="col-xs-12 col-sm-12 col-md-12">
    <div class="form-group">
      <strong>Name:</strong>
      {{ $product->name }}
    </div>
  </div>
  <div class="col-xs-12 col-sm-12 col-md-12">
    <div class="form-group">
    <strong>Details:</strong>
      {{ $product->detail }}
    </div>
  </div>
  </div>
@endsection
```
## Run Laravel App:

Start the delevelopment server

```sh
php artisan serve
```

Now, Go to your web browser, type the given URL and view the app output:

[http://localhost:8000/products](http://localhost:8000/products)

## Stay tuned to Part 2 Testing using [PHP Pest ](https://pestphp.com/)

<br>

### Happy Coding!