Monday, December 31, 2018

How to Hide Pagination Link While Not Using Paginate() Method in Laravel

How to Hide Pagination Link While Not Using Paginate() Method in Laravel

Pagination in Laravel is so easy and powerful. Yet there is a problem that cause an error.

Considering a situation that two methods send result sets to the same view file, one is generated by the paginate() method and one isn’t. However, the pagination links() results in an error while the result set is not generated from the paginate() method. How to solve this issue? If we can test whether the result set is generated from the paginate() method in the controller, the problem can be solved.

controller: ProductsController.php

class ProductController extends Controller
{
public function index()
  {
    $products = Product::paginate(5);
    return view('products.index', compact('products'));
  }

public function search(Request $request)
  {
    $request->validate([
      'keyword' => 'required'
    ]);
    $keyword = $request->get('keyword'); 
    $products = Product::where('prod_name', 'like', '%'.$keyword.'%')
      ->orWhere('prod_desc', 'like', '%'.$keyword.'%')->get();
    return view('products.index', compact('products'));
  }
}

view: index.blade.php (before)

    :
<div class="pagination justify-content-center">
  {{ $products->links() }}
</div> 
    :

If the result set is an instance of the class \Illuminate\Pagination\LengthAwarePaginator, then we can make sure that the result set is generated from the method paginate(). Therefor, a pagination link method is required in the view file. On the other hand, if the result set is not the instance of the class mentioned before, then the pagination link should be hidden. Thus, an if() statement is added to the view file as follows:

index.blade.php (after)

@if ($products instanceof \Illuminate\Pagination\LengthAwarePaginator)
  <div class="pagination justify-content-center">
	  {{ $products->links() }}
  </div> 
@endif

It solves the problem!

Sunday, December 30, 2018

Set the Current Timestamp as the Default Value of A Timestamp Column in A Table with Laravel Migrations

Set the Current Timestamp as the Default Value of A Timestamp Column in A Table with Laravel Migrations

How to Set the current timestamp as the default value of a timestamp column in a table with Laravel migrations? Let’s find out:

SQL Statement

Use DEFAULT CURRENT_TIMESTAMP.

CREATE TABLE `products` (
         :
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
         :
) 

Laravel Migrations

Just use a raw expression, DB::raw() to set CURRENT_TIMESTAMP as a default value for a column:

$table->timestamp('created_at')
      ->default(DB::raw('CURRENT_TIMESTAMP'));

This works for every database driver.

Saturday, December 29, 2018

A Simple Laravel CRUD App

A Simple Laravel CRUD App

A Laravel CRUD Sample

Laravel is an excellent PHP framework for web development. It creates a RESTful web app with just a few commands. The procedures are shown as the following steps:

1. Create a New Project

$> laravel new laravel_product
Crafting application...
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Package operations: 86 installs, 0 updates, 0 removals
  - Installing doctrine/inflector (v1.3.0): Loading from cache
  - Installing doctrine/lexer (v1.0.1): Loading from cache
  - Installing dragonmantank/cron-expression (v2.2.0): 
                    :
                    :
Package manifest generated successfully.
Application ready! Build something amazing.

After creating a new project named 'laravel_product', the files needed have been created under the directory.

$> cd laravel_product
$> php artisan -v
Laravel Framework 5.7.19

2: Configure MySQL Database

Edit .env file

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_product
DB_USERNAME=xxxx
DB_PASSWORD=xxxx

Add a database in MySQL server

Add a database manually by using Sequel Pro and following parameters.

  • Database Name: laravel_product
  • Database Encoding: UTF-8 Unicode (utf8mb4)
  • Database Collation: Default (utf8mb4_general_ci)

Create database

Create tables

$> php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table

3: Create a Model 'Product' and a Migration File.

$> php artisan make:model Product -m
Model created successfully.
Created Migration: 2018_12_26_181923_create_products_table

Edit migration file 2018_12_26_181923_create_products_table.php

Insert fields between id and timestamps:

  $table->increments('id');
    :
  $table->string('prod_name');
  $table->text('prod_desc');
  $table->integer('prod_price');
  $table->integer('prod_qty'); 
    :
  $table->timestamps();

Create table 'products'

$> php artisan migrate
Migrating: 2018_12_26_181923_create_products_table
Migrated:  2018_12_26_181923_create_products_table

Add the fillable property inside Product.php file.

<?php
  namespace App;
  use Illuminate\Database\Eloquent\Model;

  class Product extends Model {
      protected $fillable = [
        'prod_name',
        'prod_desc',
        'prod_price',
        'prod_qty'
      ];
  }

4: Create Routes and Controller

Create ProductController.php

Use following command to create controller.

  • php artisan make:controller
$> php artisan make:controller ProductController --resource
Controller created successfully.

Add routes code in /routes/web.php file.

Route::resource('products', 'ProductController');

Show routes

$> php artisan route:list
+-----------+-------------------------+------------------+-----------+
| Method    | URI                     | Name             | Action    |
+-----------+-------------------------+------------------+-----------+
| GET|HEAD  | /                       |                  | Closure   |
| GET|HEAD  | api/user                |                  | Closure   |
| GET|HEAD  | products                | products.index   | *@index   |
| POST      | products                | products.store   | *@store   |
| GET|HEAD  | products/create         | products.create  | *@create  |
| GET|HEAD  | products/{product}      | products.show    | *@show    |
| PUT|PATCH | products/{product}      | products.update  | *@update  |
| DELETE    | products/{product}      | products.destroy | *@destroy |
| GET|HEAD  | products/{product}/edit | products.edit    | *@edit    |
+-----------+-------------------------+------------------+-----------+
* = App\Http\Controllers\ProductController

5: Create the views

a. Create a file layout.blade.php inside '/resources/views' folder.

b. Create a folder 'products' inside '/resources/views' folder.

c. Then, create the following three files inside '/resource/view/products'.

  • create.blade.php
  • edit.blade.php
  • index.blade.php

d. Edit layout.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-Compatiable" content="ie=edge">
 <title>Laravel 5.7 A simple CRUD Example</title>
    <link href="{{ asset('css/app.css') }}" rel="stylesheet" type="text/css">
</head>
<body>
 <!-- Navbar start -->
  <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
    <a class="navbar-brand" href="{{ route('products.index') }}">
    A Laravel CRUD Sample</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" 
      data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" 
      aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarsExampleDefault">
      <ul class="navbar-nav mr-auto">
        <li class="nav-item active">
          <a class="nav-link" href="{{ route('products.create') }}">
            Add A Product 
            <span class="sr-only">(current)</span></a>
        </li>
      </ul>
      <form method="post" action="#" class="form-inline my-2 my-lg-0">
        <input class="form-control mr-sm-2" type="text" placeholder="Search" 
          aria-label="Search">
        <button class="btn btn-outline-success my-2 my-sm-0" 
          type="submit">Search</button>
      </form>
    </div>
  </nav> 
  <!-- Navbar end -->
 <div class="container">
  @yield('content')
 </div>
 <script src="{{ asset('js/app.js') }}"></script>
</body>
</html>

e. Edit create.blade.php

Remember to add @csrf in the tag in order to have CSRF Protection.

<form method="post" action="{{ route('products.store') }}"> 
  @csrf  // must added.
     :
</form>

create.blade.php is as follows:

@extends('layout')

@section('content')
<div class="card uper">
 <div class="card-header">
  <h4>Add Product</h4>
 </div>
 <div class="card-body">
   @if ($errors->any())
  <div class="alert alert-danger">
    <ul>
      @foreach ($errors->all() as $error)
     <li>{{ $error }}</li>
     <button type="button" class="close" data-dismiss="alert" 
       aria-label="Close">
       <span aria-hidden="true">&times;</span>
              </button>
   @endforeach 
    </ul>
    </div><br/>
  @endif
  <form method="post" action="{{ route('products.store') }}">
    @csrf
    <div class="form-group">
      <label for="prod_name">Product Name:</label>
            <input type="text" class="form-control" name="prod_name"/>
    </div>
    <div class="form-group">
      <label for="prod_desc">Product Description:</label>
            <input type="text" class="form-control" name="prod_desc"/>
    </div>
          <div class="form-group">
      <label for="prod_price">Product Price:</label>
      <input type="text" class="form-control" name="prod_price"/>
    </div>
    <div class="form-group">
      <label for="prod_qty">Product Quantity:</label>
   <input type="text" class="form-control" name="prod_qty"/>
    </div>
    <button type="submit" class="btn btn-primary">Add</button>
    <a href="{{ route('products.index') }}" class="btn btn-info">Back</a>
   </form>
    </div>
  </div>
@endsection

f. Code 'create' function in ProductController.php

Remember to add use App\Product; in the controller in order to use the Model 'Product'.

<?php
  namespace App\Http\Controllers;
  use Illuminate\Http\Request;
  use App\Product;  // must add

  public function create() 
    {
      return view('shares.create');
    }

6: Save Data

Code the "store" function in the ProductController.php

public function store(Request $request)
  {
    $request->validate([
      'prod_name'  => 'required',
      'prod_desc'  => 'required',
      'prod_price' => 'required|integer',
      'prod_qty'   => 'required|integer'
    ]);
    $product = new Product([
      'prod_name'  => $request->get('prod_name'),
      'prod_desc'  => $request->get('prod_desc'),
      'prod_price' => $request->get('prod_price'),
      'prod_qty'   => $request->get('prod_qty')
    ]);
    $product->save();
    return redirect('/products')->with('success','Product has been added!');
  }

Add some testing data and save.

7: Display the data.

Code index.blade.php

@extends('layout')

@section('content')
<div class="uper">
 @if(session()->get('success'))
  <div class="alert alert-success">
    {{ session()->get('success') }}
    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
   <span aria-hidden="true">&times;</span>
          </button>
   </div><br/>
 @endif
</div>
<table class="table table-hover">
  <thead> 
 <tr>
  <td><b>ID</b></td>
  <td><b>Product Name</b></td>
  <td><b>Product Description</b></td>
  <td><b>Product Price</b></td>
  <td><b>Product Qty</b></td>
  <td colspan="2"><b>Action</b></td>
 </tr>
  </thead>
  <tbody>
   @foreach($products as $product)
   <tr>
     <td>{{$product->id}}</td>
     <td>{{$product->prod_name}}</td>
     <td>{{$product->prod_desc}}</td>
     <td>{{$product->prod_price}}</td>
     <td>{{$product->prod_qty}}</td>
     <td><a href="{{ route('products.edit', $product->id) }}" 
    class="btn btn-primary">Edit</a></td>
     <td>
        <form method="post" action="{{ route('products.destroy', $product->id) }}">
          @method('DELETE')
          @csrf
          <button type="submit" class="btn btn-danger">Delete</button>
        </form>
      </td>
   </tr>
   @endforeach
  </tbody>
</table>
<div class="pagination justify-content-center">
 {{ $products->links() }}
</div>
@endsection

Code the "index" function in the ProductController.php

public function index() 
  {
    $products = Product::all();
    return view('products.index', compact('products'));
  }

8: Edit and Update Data

Code the "edit" function in the ProductController.php

public function edit($id) 
  {
    $product = Product::find($id);
    return view('products.edit', compact('product'));
  }

Code "edit.blade.php"

@extends('layout')

@section('content')
<div class="card uper">
  <div class="card-header">
   <h4>Edit Product</h4>
  </div>
  <div class="card-body">
   @if ($errors->any())
     <div class="alert alert-danger">
      <ul>
        @foreach ($errors->all() as $error)
          <li>{{ $error }}</li>
          <button type="button" class="close" data-dismiss="alert" 
            aria-label="Close">
     <span aria-hidden="true">&times;</span>
            </button>
        @endforeach
      </ul>
     </div><br/>
   @endif 
   <form method="post" action="{{ route('products.update', $product->id) }}">
     @method('PATCH')
     @csrf
     <div class="form-group">
      <label for="prod_name">Product Name</label>
      <input type="text" class="form-control" name="prod_name" 
        value={{ $product->prod_name }} /> 
     </div>
     <div class="form-group">
      <label for="prod_desc">Product Description</label>
      <input type="text" class="form-control" name="prod_desc" 
        value={{ $product->prod_desc }} /> 
     </div>
     <div class="form-group">
      <label for="prod_price">Product Price</label>
      <input type="text" class="form-control" name="prod_price" 
        value={{ $product->prod_price }} /> 
     </div>
     <div class="form-group">
      <label for="prod_qty">Product Qty</label>
    <input type="text" class="form-control" name="prod_qty" 
      value={{ $product->prod_qty }} /> 
   </div>
   <button type="submit" class="btn btn-primary">Update</button>
    </form>
  </div>
</div>
@endsection

Code the "update" function in the ProductController.php

public function update(Request $request, $id)
  {
    $request->validate([
      'prod_name'  => 'required',
      'prod_desc'  => 'required',
      'prod_price' => 'required|integer',
      'prod_qty'   => 'required|integer'
    ]);
    $product = Product::find($id);
    $product->prod_name  = $request->get('prod_name');
    $product->prod_desc  = $request->get('prod_desc');
    $product->prod_price = $request->get('prod_price');
    $product->prod_qty   = $request->get('prod_qty');
    $product->save();
    return redirect('/products')->with('success', 'Product has been updated!');
  }

9: Delete the data

Code the "delete" function in ProductController.php

public function destroy($id)
  {
    $product = Product::find($id);
    $product->delete();
    return redirect('/products')->with('success', 'Product has been deleted!');
  }

10: Start the CRUD web app.

Start the server:

$> php artisan serve

Go to "http://localhost:8000/products" and will see the product index page.

11: Pagination

If it needs to have the pagination functionality, it's just as easy as doing two things.

Modify the 'index' function in ProductController.php.

a. change to pagination method.

Just change

$products = Product::all();

to:

// number: the record number per page.
$products = Product::paginate(number);  

Pagination links:

  • $products->links()
     :
    </table>
  <div class="pagination justify-content-center">
    {{ $products->links() }}
  </div>
@endsection

That's all! Isn't it simple and easy!