Laravel CRUD

Aug 23, 2020 PHP Laravel Validation Database crud

Introduction

I will make CRUD with Laravel.

Do not do

What to make

Action Screen presence Content
index screen available list display screen
create Has screen New entry form
store No screen Additional processing (create registration button)
show Has screen Show details
edit With screen Change form (with existing values)
update No screen Change process (edit update button)
destroy No screen Delete process (show delete button)
index (list) ┳ create (new creation screen) ━ store (new save)
      ┗ show (detailed display) ┳ edit (edit screen) ━ update (overwrite save)
▼ ┗ destroy (delete)

Preparation

Create table

Table to create

id name telephone email created_at updated_at
ID Name Phone Number Email Address Created Date Updated Date

Creating model and migration files

php artisan make:model Models/Member -m

A migration file is also created with the -m option.

The following two files will be created. app\Models\Member.php database\migrations\xxxx_xx_xx_xxxxxx_create_members_table.php

Editing the migration file

public function up()
  {
    Schema::create('members', function (Blueprint $table) {
      $table->id();
      $table->string('name',20);
      $table->string('telephone',13)->nullable()->unique();
      $table->string('email',255)->nullable()->unique();
      $table->timestamps();
    });
  }
 
public function down()
  {
    Schema::dropIfExists('members');
  }

Run migration

php artisan migrate

The members table is created.

Insert record

Put a record in the members table for display confirmation.

Create seeder file

php artisan make:seeder MembersTableSeeder

database\seeds\MembersTableSeeder.php is created.

Edit seeder file

    public function run()
     {
         DB::table('members')->insert(
             [
               [
                 'name'=>'Yamada',
                 'telephone'=>'xxxx-xxxxx',
                 'email'=>'[email protected]',
                 'created_at'=>now(),
                 'updated_at'=>now(),
               ],
 
               ]
         );
     }

Registration with Database Seeder

Register the created MembersTableSeeder in DatabaseSeeder.

public function run()
  {
    $this->call(MembersTableSeeder::class);
  }

Run seeder file

php artisan db:seed

The record is entered in the members table.

Creating a #### controller

php artisan make:controller MemberController --resource

With the –resource option, a template of 7 actions is prepared in advance.

Edit #### controller Templates of 7 actions are prepared in advance.

//add to
use Illuminate\Support\Facades\DB;
use App\Models\Member;
 
public function index()
  {
    //
  }

public function create()
   {
     //
   }

public function store(Request $request)
  {
    //
  }
 
public function show($id)
  {
    //
  }

public function edit($id)
  {
    //
  }

public function update(Request $request, $id)
  {
    //
  }
   
public function destroy($id)
  {
    //
  }

List screen (index)

Add routing

Add a route for accessing /member/index.

// Addition
Route::group(['prefix'=>'member'], function () {
  Route::get('index','MemberController@index')->name('member.index');
});

Edit ### controller Fetch data from the members table and pass it to view.

public function index()
  {
    // store name, telephone, email from member table in $members
    $members=DB::table('members')
      ->select('id','name','telephone','email')
      ->get();
     
    //return view (pass $members to view with compact)
    return view('member/index', compact('members'));
  }

create new view

<h1>List display</h1>

<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>phone number</th>
<th>Email address</th>
</tr>
@foreach($members as $member)
<tr>
<td>{{$member->id}}</td>
<td>{{$member->name}}</td>
<td>{{$member->telephone}}</td>
<td>{{$member->email}}</td>
</tr>
@endforeach
</table>

Confirmation

Start a simple server.

php artisan serve

Access http://127.0.0.1:8000/member/index with a browser and confirm that the list is displayed. Terminate the simple server with Ctrl+C.

New registration (create)

Add routing

Add a route for accessing /member/create.

Route::group(['prefix'=>'member'], function () {
  Route::get('index','MemberController@index')->name('member.index');
      
  // Addition
  Route::get('create','MemberController@create')->name('member.create');
});

Edit ### controller Returns create.blade.php.

public function create()
  {
    return view('member/create');
  }

create new view

Create a new screen. Only the name is required.

<h1>New creation</h1>

<form method="POST" action="">
  @csrf

  <div>
    <label for="form-name">name</label>
    <input type="text" name="name" id="form-name" required>
  </div>
 
  <div>
    <label for="form-tel">phone number</label>
    <input type="tel" name="telephone" id="form-tel">
  </div>
 
  <div>
    <label for="form-email">email address</label>
    <input type="email" name="email" id="form-email">
  </div>
 
  <button type="submit">Register</button>
 
</form>
```### Conductor (index → create)
It is a link from the list display screen to the new creation screen.

```:resources\views\member\index.blade.php
<a href="{{ route('member.create') }}">{{ __('Create new') }}</a>

Conductor (create → index)

It is a link from the new creation screen to the list display screen.

//add to
<a href="{{ route('member.index') }}">{{ __('back to list') }}</a>

Confirmation

Start a simple server.

php artisan serve

Access http://127.0.0.1:8000/member/create with a browser and confirm that the new input screen is created. (At this point, an error will occur even if you press the register button.) Terminate the simple server with Ctrl+C.

New store

Save the value entered in the Add New screen in DB.

Add routing

Add a route for accessing /member/store.

Route::group(['prefix'=>'member'], function () {
  Route::get('index','MemberController@index')->name('member.index');
  Route::get('create','MemberController@create')->name('member.create');
     
  //add to
  Route::post('store','MemberController@store')->name('member.store');
});

Edit ### controller Store the values entered in the form in the members table.

public function store(Request $request)
  {
    $member=new Member;
   
    $member->name=$request->input('name');
    $member->telephone=$request->input('telephone');
    $member->email=$request->input('email');
   
    $member->save();
   
    // redirect to the list display screen
    return redirect('member/index');
  }

create new view

None

Conductor (create → store)

It is a link from the list display screen to the new creation screen.

//<form method="POST" action="">
//↓ Change the form destination
<form method="POST" action="{{route('member.store')}}">

Conductor (store → index)]

The controller has already described the redirect.

Confirmation

Start a simple server.

php artisan serve

When you access http://127.0.0.1:8000/member/create with a browser, enter a value and send it, you will be redirected to member/index and confirm that the value is in the members table. Terminate the simple server with Ctrl+C.

Detailed display (show)

Add routing

Add a route for accessing /member/show/id.

Route::group(['prefix'=>'member'], function () {
  Route::get('index','MemberController@index')->name('member.index');
  Route::get('create','MemberController@create')->name('member.create');
  Route::post('store','MemberController@store')->name('member.store');
     
  //add to
  Route::get('show/{id}','MemberController@show')->name('member.show');
});

Edit ### controller Performs the process to display the details page of the member with the specified ID.

public function show($id)
  {
    $member=Member::find($id);
 
    return view('member/show', compact('member'));
  }

create new view

<h1>Detailed display</h1>
 
<div>
name
{{$member->name}}
</div>
 
<div>
phone number
{{$member->telephone}}
</div>
 
<div>
mail address
{{$member->email}}
</div>

Conductor (index → show)

Add one column to the list display screen and add a link to the detail screen.

<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>phone number</th>
<th>Email address</th>
<th>Details</th>
</tr>
@foreach($members as $member)
<tr>
<td>{{$member->id}}</td>
<td>{{$member->name}}</td>
<td>{{$member->telephone}}</td>
<td>{{$member->email}}</td>
<td><th><a href="{{route('member.show',['id'=>$member->id])}}">Details</a></th></td >
</tr>
@endforeach
</table>

Conductor (show → index)

<a href="{{ route('member.index') }}">{{ __('back to list') }}</a>

Confirmation

Start a simple server.

php artisan serve

Go to http://127.0.0.1:8000/member/index in your browser and press Details to see the details screen is displayed. Terminate the simple server with Ctrl+C.

edit

Add routing

Add a route for accessing /member/edit/id.

Route::group(['prefix'=>'member'], function () {
  Route::get('index','MemberController@index')->name('member.index');
  Route::get('create','MemberController@create')->name('member.create');
  Route::post('store','MemberController@store')->name('member.store');
  Route::get('show/{id}','MemberController@show')->name('member.show');
     
  //add to
  Route::get('edit/{id}','MemberController@edit')->name('member.edit');
});

Edit ### controller

public function edit($id)
  {
    $member=Member::find($id);
 
    return view('member/edit', compact('member'));
  }

create new view

<h1>Edit</h1>
 
 <form method="POST" action="">
  @csrf
 
 <div>
  name
  <input type="text" name=name value="{{$member->name}}">
  </div>
 
  <div>
  phone number
  <input type="text" name=telephone value="{{$member->telephone}}">>
  </div>
  
  <div>
  mail address
  <input type="text" name=email value="{{$member->email}}">
  </div>
 
 
  <input type="submit" value="Update">
 
  </form>

Conductor (show → edit)

//add to
<a href="{{route('member.edit',['id'=>$member->id])}}">{{ __('edit') }}</a>

Conductor (edit → show)

//add to
<a href="{{route('member.show',['id'=>$member->id])}}">{{ __('back to details') }}</a>

Confirmation

Start a simple server.

php artisan serve

Go to http://127.0.0.1:8000/member/index in your browser and make sure you can see the edit form which goes to Details → Edit. (At this point, an error will occur even if you press the update button.)

updateSet the operation when you press the “Update” button on the edit screen.

Add routing

Add a route for accessing /member/update/id.

Route::group(['prefix'=>'member'], function () {
  Route::get('index','MemberController@index')->name('member.index');
  Route::get('create','MemberController@create')->name('member.create');
  Route::post('store','MemberController@store')->name('member.store');
  Route::get('show/{id}','MemberController@show')->name('member.show');
  Route::get('edit/{id}','MemberController@edit')->name('member.edit');
     
  //add to
  Route::post('update/{id}','MemberController@update')->name('member.update');
});

Edit ### controller

public function update(Request $request, $id)
  {
    $member=Member::find($id);
 
    $member->name=$request->input('name');
    $member->telephone=$request->input('telephone');
    $member->email=$request->input('email');
 
    // Save to DB
    $member->save();
 
    // After processing, redirect to member/index
    return redirect('member/index');
}

create new view

None

Conductor (edit → update)

Specify the destination of the send button of edit.

//<form method="POST" action="">
//↓
<form method="POST" action="{{route('member.update',['id' =>$member->id])}}">

Conductor (update → index)

redirected by controller

Confirmation

Start a simple server.

php artisan serve

Access http://127.0.0.1:8000/member/index with a browser, go to the details screen → edit screen, change the value and press the “Update” button, and the data of /member/index is changed. Check that Terminate the simple server with Ctrl+C.

Delete (destroy)

Add routing

Add a route for accessing /member/destroy/id.

Route::group(['prefix'=>'member'], function () {
  Route::get('index','MemberController@index')->name('member.index');
  Route::get('create','MemberController@create')->name('member.create');
  Route::post('store','MemberController@store')->name('member.store');
  Route::get('show/{id}','MemberController@show')->name('member.show');
  Route::get('edit/{id}','MemberController@edit')->name('member.edit');
  Route::post('update/{id}','MemberController@update')->name('member.update');
     
  //add to
  Route::post('destroy/{id}','MemberController@destroy')->name('member.destroy');
});

Edit ### controller Write the process to delete the specified ID.

public function destroy($id)
  {
    $member=Member::find($id);
         
    $member->delete();
 
    return redirect('member/index');
  }

create new view

None

Conductor (show → destroy)

//add to
<form method="POST" action="{{route('member.destroy',['id'=>$member->id])}}">
  @csrf
  <button type="submit">Delete</button>
</form>

Conductor (destroy → index)

redirected by controller

Confirmation

Start a simple server.

php artisan serve

Access http://127.0.0.1:8000/member/index with a browser, go to the details screen, click the “Delete” button, and confirm that the data in /member/index has been deleted. Terminate the simple server with Ctrl+C.

Preparation for validation

Localization of error messages

Place the following ja folder in resources/lang/ in the same hierarchy as the en folder. https://github.com/minoryorg/laravel-resources-lang-ja

//'attributes' => [],
//↓
'attributes' => ['email'=>'email address',
'name'=>'name'
],

Validation (new save)

form request creation

php artisan make:request StoreMember

app\Http\Requests\StoreMember.php is newly created.

edit form request

Specify validation rules.

//add to
use Illuminate\Validation\Rule;
 
public function authorize()
  {
    //return false;
    //↓ change false to true
    return true;
  }
  
public function rules()
  {
    return [
         
      //add to
      'name' => [
        'string',
        'required',
        'max:20'
         ],
           
      'telephone' => [
        'string',
        'nullable',
        'max:13',
        'unique:members'
        ],
           
      'email' => [
        'nullable',
        'max:255',
        'email',
        'unique:members'
        ]
    ];
  }
Keywords Content
required Required
max maximum length
unique: table name unique for the specified table
nullable nullable
accepted Checked
string string type
email email type
url url type

controller

//add to
use App\Http\Requests\StoreMember;
 
 
//public function store(Request $request)
//↓ change
public function store(StoreMember $request)

view

Place the error message where you want it to appear.

<form method="POST" action="{{route('member.store')}}">
  @csrf
 
  <div>
    <label for="form-name">name</label>
 
    // <input type="text" name="name" id="form-name" required>
    // Add ↓value to hold the input value.
    <input type="text" name="name" id="form-name" required value="{{old('name')}}">
 
    //add to
    @error('name')
    {{$message}}
    @enderror
 
  </div>
 
  <div>
    <label for="form-tel">phone number</label>
 
    //<input type="tel" name="telephone" id="form-tel">
    // Add ↓value to hold the input value.
    <input type="tel" name="telephone" id="form-tel" value="{{old('telephone')}}">
 
   //add to
   @error('telephone')
   {{$message}}@enderror
 
  </div>
 
  <div>
 
    <label for="form-email">email address</label>
 
    //<input type="email" name="email" id="form-email">
    // Add ↓value to hold the input value.
    <input type="email" name="email" id="form-email" value="{{old('email')}}">
 
    //add to
    @error('email')
    {{$message}}
    @enderror
 
  </div>
 
  <button type="submit">Send</button>
 
</form>

Validation (save)

If you keep validating the new registration, you will need to change the phone number and email address that you want to make unique.

form request creation

php artisan make:request UpdateMember

app\Http\Requests\UpdateMember.php is newly created.

edit form request

It’s almost the same as a new validation, but it’s modified to allow existing values as well.

//add to
use Illuminate\Validation\Rule;

public function authorize()
  {
    //return false;
    //↓ change false to true
    return true;
  }

public function rules()
  {
    return [
             
      //add to
      'name' => [
        'string',
        'required',
        'max:20'
        ],
 
      'telephone' => [
         'string',
         'nullable',
         'max:13',

         //Allow existing values
         Rule::unique('members')->ignore($this->id)
       ],
 
      'email' => [
        'nullable',
        'max:255',
        'email',

         //Allow existing values
         Rule::unique('members')->ignore($this->id)
         ]
             
     ];
   }

controller

//add to
use App\Http\Requests\UpdateMember;
 
//public function update(Request $request, $id)
//↓ change
public function update(UpdateMember $request, $id)

view

Place the error message where you want it to appear.

<form method="POST" action="{{route('member.update',['id' =>$member->id])}}">
 @csrf

  <div>
    name
    <input type="text" name=name value="{{$member->name}}">
    @error('name')
    {{$message}}
    @enderror
  </div>

  <div>
    phone number
    <input type="text" name=telephone value="{{$member->telephone}}">>
    @error('telephone')
    {{$message}}
    @enderror
  </div>

  <div>
    mail address
    <input type="text" name=email value="{{$member->email}}">
    @error('email')
    {{$message}}
    @enderror
  </div>

  <input type="submit" value="Update">

</form>

Pagination

controller

When the number of items displayed in the list increases, divide the page.

public function index()
  {
    $members=DB::table('members')
      ->select('id','name','telephone','email')
      //->get();
      //↓ Specify the number of items to be displayed on one page
      ->paginate(20);
 
      //return view (pass $members to view with compact)
      return view('member/index', compact('members'));
  }

view

Add page feed UI to the list screen.

//add to
{{$members->links()}}

The description is one line, but the html is generated as shown below, so please arrange it with CSS.

<nav>
  <ul class="pagination">
             
    <li class="page-item disabled" aria-disabled="true" aria-label="« Previous"> <span class="page-link" aria-hidden="true"> ‹</span></ li>
    <li class="page-item active" aria-current="page">
      <span class="page-link">1</span>
    </li>
    <li class="page-item">
      <a class="page-link" href="http://127.0.0.1:8000/member/index?page=2">2</a>
    </li>
    <li class="page-item">
      <a class="page-link" href="http://127.0.0.1:8000/member/index?page=2" rel="next" aria-label="Next »">›</a>
    </li>
     
  </ul>
</nav>

Search function

Add routing

Route::group(['prefix'=>'member'], function () {
  Route::get('index''MemberController@index')->name('member.index');
  Route::get('create','MemberController@create')->name('member.create');
  Route::post('store','MemberController@store')->name('member.store');
  Route::get('show/{id}','MemberController@show')->name('member.show');
  Route::get('edit/{id}','MemberController@edit')->name('member.edit');
  Route::post('update/{id}','MemberController@update')->name('member.update');
  Route::post('destroy/{id}','MemberController@destroy')->name('member.destroy');
     
  //add to
  Route::get('search','MemberController@search')->name('member.search');
});

Edit ### controller

public function search(Request $request)
  {
    $serach=$request->input('q');
 
    $query=DB::table('members');
 
    // Convert full-width space of search word to half-width space
    $serach_spaceharf=mb_convert_kana($serach,'s');
 
 
    // Separate search words with a space
    $keyword_array=preg_split('/[\s]+/', $serach_spaceharf, -1, PREG_SPLIT_NO_EMPTY);
 
    // Rotate the search word in a loop to find a matching record
    foreach ($keyword_array as $keyword) {
        $query->where('name','like','%'.$keyword.'%');
      }
 
    $query->select('id','name','telephone','email');
    $members=$query->paginate(20);
 
    return view('member/index', compact('members'));
  }

edit view

Add a search form to the list display screen.

//add to
<form method="GET" action="{{route('member.search')}}">
  @csrf
  <div>
    <label for="form-search">Search</label>
    <input type="search" name="q" id="form-search">
  </div><button type="submit">検索</button>
 
</form>