はじめに
Laravelとは、Webに特化したPHPフレームワーク。セキュリティ対策(CSRF対策など)もこれでできます。MVCアーキテクチャを採用しています。今回は、データの更新と削除をしていきたいと思います。
Laravelで簡単なメモアプリを作る(1)~Viewの作成と表示~
Laravelで簡単なメモアプリを作る(2)~データの取得と保存~
今回の目標物


データの更新
更新するデータの取得
id=1のデータを取得する時は、このように書く。
$memo = Memo::find(1);
whereメソッドでも、取得することができる。ただ、whereメソッドは、findメソッドと異なって、条件に合うものを全て取ってくるため、たとえ条件に合うものが一つであったとしても配列として取得するので注意。なのでfirstメソッドで、要素として取得する必要がある。
$memo = Memo::where('id', 1)->first();
データの更新
updateメソッドで、データベース上のデータを書き換えることができる。
$memo->update([
'title' => $title,
'content' => $content
]);
MemoControllerを以下のように編集する。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Memo;
class MemoController extends Controller
{
public function showHome()
{
$memos = Memo::get();
return view("home", ['memos' => $memos]);
}
public function showSubmit($id = 0)
{
if ($id != 0) {
$memo = Memo::where('id', $id)->get()->first();
} else {
$memo = (object) ["id" => 0, "title" => "", "content" => ""];
}
return view("submit", ['memo' => $memo]);
}
public function postSubmit(Request $request, $id = 0)
{
$title = $request->input('title');
$content = $request->input('content');
if ($id == 0) {
Memo::create([
'title' => $title,
'content' => $content
]);
} else {
$memo = Memo::find($id);
$memo->update([
'title' => $title,
'content' => $content
]);
}
return redirect()->route('home');
}
}
データの削除
メモを削除する関数の作成
destroyメソッドを使うと、引数に指定したidのデータだけが削除される。下のコードをMemoControllerに追加する。
public function deleteMemo($id)
{
Memo::destroy($id);
return redirect()->route('home');
}
web.phpにdeleteMemoメソッドの登録
/delete/{id}
というURLを受け取ったら、メモが削除されるようにする。下のコードをweb.phpに追加する。
Route::get('/delete/{id}', 'MemoController@deleteMemo')->name('delete');
削除ボタンを押したら削除されるようにする
resources/views/home.blade.phpの削除ボタンを以下のように修正する。
<td><a href="{{ route('delete', ['id' => $memo->id])}}">削除</a></td>
おまけ
モーダルを使って、削除の確認をする
bootstrap4のモーダルを使用する。
https://getbootstrap.com/docs/4.3/components/modal/
@extends('layouts.app')
@section('css')
<style>
header {
height: 50px;
background-color: #000;
color: white;
padding-left: 20px;
font-size: large;
color: #ddd;
}
.title {
position: absolute;
top: 10px;
}
.card {
margin-top: 40px;
}
.left {
width: 70%;
}
.submit {
position: absolute;
top: 10px;
right: 20px;
}
</style>
@endsection
@section('content')
<div class="card" style="width: 100%;">
<div class="card-header">
メモ一覧
<a href="{{ route('submit')}}" class="submit">メモを追加</a>
</div>
<table class="table">
<tbody>
@foreach ($memos as $memo)
<tr>
<td class="left">{{$memo->title}}</td>
<td><a href="{{ route('submit', ['id' => $memo->id])}}">編集</a></td>
<td><a type="button" data-toggle="modal" data-target="#modal{{$memo->id}}">削除</a></td>
</tr>
<!-- Modal -->
<div class="modal fade" id="modal{{$memo->id}}" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">以下のメモを本当に削除しますか?</h5>
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
{{$memo->title}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">閉じる</button>
<button type="button" class="btn btn-primary"
onclick="location.href='{{ route('delete', ['id' => $memo->id])}}'">
削除
</button>
</div>
</div>
</div>
</div>
@endforeach
</tbody>
</table>
</div>
@endsection
submitページのボタンを新規作成の時と編集の時で変える
新規作成の時は$memo->id == 0
で、編集の時は$memo->id != 0
なので、if文で条件分岐する。
resources/views/submit.blade.phpの追加ボタンを以下のように書き換える。
@if($memo->id == 0)
<button type="submit" class="btn btn-success">追加</button>
@else
<button type="submit" class="btn btn-success">適用</button>
@endif
テーブルの列をクリックしたら、詳細画面に飛べるようにする
下のコードを、app.blade.phpのbodyタグの一番下に追加する。
<script>
jQuery(function($) {
$('tbody tr[data-href]').addClass('clickable').click(function() {
window.location = $(this).attr('data-href');
}).find('a').hover(function() {
$(this).parents('tr').unbind('click');
}, function() {
$(this).parents('tr').click( function() {
window.location = $(this).attr('data-href');
});
});
});
</script>
home.blade.phpの編集ボタンを消して、trタグにdata-href属性を追加する。
<tr data-href="{{route('submit', ['id' => $memo->id])}}">
<td class="left">{{$memo->title}}</td>
<td><a type="button" data-toggle="modal" data-target="#modal{{$memo->id}}">削除</a></td>
</tr>
テーブルの列をホバーすると色が変わるようにする
trタグにclass="table-row"
を追加する。
<tr data-href="{{route('submit', ['id' => $memo->id])}}" class="table-row">
<td class="left">{{$memo->title}}</td>
<td><a type="button" data-toggle="modal" data-target="#modal{{$memo->id}}">削除</a></td>
</tr>
.table-row {
background-color: #fff;
}
.table-row:hover {
background-color: #ddd;
}
追加ボタンをいい感じにする。ヘッダーも固定する。
app.blade.phpでFont Awesomeを読み込む。
<link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet">
app.blade.phpを以下のように編集する。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>MemoApp</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.0/css/bootstrap.min.css"
integrity="sha384-SI27wrMjH3ZZ89r4o+fGIJtnzkAnFs3E4qz9DIYioCQ5l9Rd/7UAa8DHcaL8jkWt" crossorigin="anonymous">
<link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous">
</script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.0/js/bootstrap.min.js"
integrity="sha384-3qaqj0lc6sV/qpzrc1N5DC6i1VRn/HyX4qdPaiEFbn54VjQBEU341pvjz7Dv3n6P" crossorigin="anonymous">
</script>
</head>
<style>
header {
background-color: #000;
background-position: 0px 50px;
padding-left: 20px;
font-size: large;
width: 100%;
height: 50px;
clear: both;
position: fixed;
top: 0;
margin-top: 0px;
z-index: 1;
}
.title {
position: absolute;
top: 10px;
color: #fff;
}
.container {
margin-top: 70px;
}
</style>
@yield('css')
<body>
<header>
<span class="title">MemoApp</span>
</header>
<div class="container">
@yield('content')
</div>
<script>
jQuery(function($) {
$('tbody tr[data-href]').addClass('clickable').click(function() {
window.location = $(this).attr('data-href');
}).find('a').hover(function() {
$(this).parents('tr').unbind('click');
}, function() {
$(this).parents('tr').click( function() {
window.location = $(this).attr('data-href');
});
});
});
</script>
</body>
</html>
home.blade.phpを以下のように編集する。
@extends('layouts.app')
@section('css')
<style>
.table-row {
background-color: #fff;
}
.table-row:hover {
background-color: #ddd;
}
.card {
margin-top: 40px;
}
.circle-button {
position: fixed;
display: inline-block;
text-decoration: none;
color: rgba(152, 152, 152, 0.43);
width: 80px;
height: 80px;
line-height: 80px;
font-size: 40px;
border-radius: 50%;
text-align: center;
overflow: hidden;
font-weight: bold;
background-image: linear-gradient(#e8e8e8 0%, #d6d6d6 100%);
text-shadow: 1px 1px 1px rgba(255, 255, 255, 0.66);
box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.5), 0 2px 2px rgba(0, 0, 0, 0.19);
border-bottom: solid 2px #b5b5b5;
}
.circle-button i {
line-height: 80px;
}
.circle-button:active {
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5), 0 2px 2px rgba(0, 0, 0, 0.19);
border-bottom: none;
}
@media screen and (min-width:0px) {
.circle-button {
bottom: 20px;
right: 30px;
}
}
@media screen and (min-width:768px) and (max-width:1024px) {
.circle-button {
bottom: 20px;
right: 50px;
}
}
@media screen and (min-width:1024px) {
.circle-button {
bottom: 30px;
right: 150px;
}
}
.delete-button {
display: inline-block;
text-decoration: none;
width: 20px;
height: 20px;
line-height: 20px;
font-size: 7px;
border-radius: 50%;
text-align: center;
overflow: hidden;
background-color: #cd5c5c;
margin-right: 10px;
margin-top: 5px;
}
.delete-button i {
line-height: 20px;
color: #fff;
}
.td-left {
width: 10px;
}
</style>
@endsection
@section('content')
<div class="card" style="width: 100%;">
<div class="card-header">
メモ一覧
</div>
<table class="table">
<tbody>
@foreach ($memos as $memo)
<tr data-href="{{route('submit', ['id' => $memo->id])}}" class="table-row">
<td class="td-left">
<a class="delete-button" type="button" data-toggle="modal" data-target="#modal{{$memo->id}}">
<i class="fa fa-minus"></i>
</a>
</td>
<td class="td-right">
{{$memo->title}}
</td>
</tr>
<!-- Modal -->
<div class="modal fade" id="modal{{$memo->id}}" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">以下のメモを本当に削除しますか?</h5>
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
{{$memo->title}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">閉じる</button>
<button type="button" class="btn btn-primary"
onclick="location.href='{{ route('delete', ['id' => $memo->id])}}'">
削除
</button>
</div>
</div>
</div>
</div>
@endforeach
</tbody>
</table>
</div>
<a href="{{route('submit')}}" class="circle-button">
<i class="fa fa-plus"></i>
</a>
@endsection
submit.blade.phpのcss部分を消しておく。inputもついでに文字数制限をかける。
@extends('layouts.app')
@section('content')
<form method="POST" action="{{ route('submit', ['id' => $memo->id])}}">
@csrf
<div class="form-group">
<label for="title">タイトル</label>
<input type="text" class="form-control" id="title" name="title" value="{{$memo->title}}" maxlength="24"
required>
</div>
<div class="form-group">
<label for="content">内容</label>
<input type="text" class="form-control" id="content" name="content" value="{{$memo->content}}" maxlength="60"
required>
</div>
<a href="{{ route('home')}}" class="btn btn-primary">戻る</a>
@if($memo->id == 0)
<button type="submit" class="btn btn-success">追加</button>
@else
<button type="submit" class="btn btn-success">適用</button>
@endif
</form>
@endsection
