[Laravel]Udemyで学びながらメモするところ
受講講座
【Laravel】【Vue.js3】で【CRM(顧客管理システム)】をつくってみよう
仮想サーバー
フロント側の簡易サーバー
npm run dev
アプリ側の簡易サーバー
php artisan serve
名前付きルート
ziggyライブラリにより名前付きルートが使える
名前付きルートとは
名前付きルートは特定のルートへのURLを生成したり、リダイレクトしたりする場合に便利です。 ルート定義にnameメソッドをチェーンすることで、そのルートに名前がつけられます。 ルート定義に名前を付ければ、命名したルート名を指定することでURLの呼び出しができます。
<Link :href="route('inertia.index')"></Link>
use App\Http\Controllers\InertiaTestController;
~略~
Route::get('/inertia/index',[Inertia TestController::class,'index'])->name('inerta.index');
# php artisan make:controller InertiaTestController
INFO Controller [C:\xampp\htdocs\uCRM\app/Http/Controllers/InertiaTestController.php] created successfully.
# php artisan route:list
~略~
▼設定したものが表示されればOK
GET|HEAD inertia/index inertia.index › InertiaTestController@index
~略~
出てきたエラー
エラー2
[plugin:vite:vue] At least one <template> or <script> is required in a single file component.
/mnt/c/xampp/htdocs/uCRM/resources/js/Pages/Inertia/Index.vue
直訳
[plugin:vite:vue] 1 つのファイル コンポーネントには少なくとも 1 つの <template> または <script> が必要です。
解決
講座では文字だけだったが、<template></template>
をつける必要がある
(バージョンのせい?)
追記
8:40あたりでvueファイルを修正する工程がありました。
見逃していてすみません
<script setup>
</script>
<template>
ああああああ
</template>
ルートパラメータ
laravelは連想配列だったが、
{}
(オブジェクト)でパラメータで引数を渡す
<Link :herf="route('inertia.show', {id : 1 })">button</Link>
Route::get('/inertia/show/{id}', [InertiaTestController::class,'show'])->name('inertia.show');
public function show($id)
{
//dd($id);
return Inertia::render('Inertia/Show',[
'id' => $id
]);
}
dd($id)
をコメントアウトしなかった場合の実行結果
以下はVue3の機能
<script setup>
defineProps({
id : String
})
</script>
<template>
{{ id }}
</template>
モデルとマイグレーションファイルが生成される
php artisan make:model InertiaTest -m
DB
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('inertia_tests', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('content');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('inertia_tests');
}
};
# php artisan migrate
INFO Running migrations.
2023_11_25_211538_create_inertia_tests_table 8ms DONE
LINKコンポーネントでストア保存
InertiaTest.vueファイル
<script setup>
// C:\xampp\htdocs\uCRM\node_modules\@inertiajs\inertia-vue3\src\link.js
import { Link } from '@inertiajs/inertia-vue3';
// Linkコンポーネントでsutore保存
import { ref } from 'vue'
const newTitle = ref('')
const newContent = ref ('')
// defineProps({
// canLogin: Boolean,
// canRegister: Boolean,
// laravelVersion: String,
// phpVersion: String,
// })
</script>
<template>
Inertiaテストです。<br>
<a href="/">aタグ経由です</a><br>
<Link href="/">Link経由です</Link><br>
<!-- vue.jsの機能で、:hrefだと動的にリンクをかえることができる -->
<Link :href="route('inertia.index')">名前付きルートの確認です</Link><br>
<!-- ↓Linkルートパラメータ実装 -->
<Link :href="route('inertia.show', { id: 1 })">ルートパラメータのテストです</Link>
<!-- Linkコンポーネントでsutore保存 -->
<div class="mb-8"></div>
<input type="text" name="newTitle" v-model="newTitle"><br>
<input type="text" name="newContent" v-model="newContent"><br>
<Link as="button" :href="route('inertia.store')" :data="{
title: newTitle,
content: newContent
}">DB保存テスト</Link>
</template>
:::detailes InertiaTestContoroller.php
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
// 追加
use Inertia\Inertia;
// Linkコンポーネントでstore保存
use App\Models\InertiaTest;
class InertiaTestController extends Controller
{
public function index()
{
return Inertia::render('Inertia/Index');
}
public function show($id)
{
// dd()
// ララベルのデバッグ
// 処理を止めて変数の値をみることができる
// dd($id);
return Inertia::render('Inertia/Show',
[
// 引数として入ってきた値をvue側に渡す
'id' => $id
]);
}
// Linkコンポーネントでstore保存
public function store(Request $request)
{
$inertiaTest = new InertiaTest;
$inertiaTest->title = $request->title;
$inertiaTest->content = $request->content;
// DBに保存
$inertiaTest->save();
//laravel9の機能
return to_route('inertia.index');
}
}
:::
ルート側の設定
// Linkコンポーネントでsutore保存
Route::post('/inertia',[InertiaTestController::class, 'index'])->name('inertia.store');
web.phpの全コード
<?php
use App\Http\Controllers\ProfileController;
use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use App\Http\Controllers\InertiaTestController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
// Inertia
Route::get('/inertia-test', function () {
return Inertia::render('InertiaTest');
}
);
// 追加
Route::get('/inertia/index',[InertiaTestController::class, 'index'])->name('inertia.index');
// Linkコンポーネントでsutore保存
Route::post('/inertia',[InertiaTestController::class, 'store'])->name('inertia.store');
// ↓Linkルートパラメータ実装
Route::get('/inertia/show/{id}',[InertiaTestController::class, 'show'])->name('inertia.show');
Route::get('/', function () {
return Inertia::render('Welcome', [
'canLogin' => Route::has('login'),
'canRegister' => Route::has('register'),
'laravelVersion' => Application::VERSION,
'phpVersion' => PHP_VERSION,
]);
});
Route::get('/dashboard', function () {
return Inertia::render('Dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
Route::middleware('auth')->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});
require __DIR__.'/auth.php';
この時点で出てくるエラー
エラー解決
Postをいれる必要がある
<Link as="button" method="post" :href="route('inertia.store')" :data="{
title: newTitle,
content: newContent
}">DB保存テスト</Link>
フォーム(create)
ルート
//フォーム(create)
Route::get('/inertia/create',[InertiaTestController::class, 'create'])->name('inertia.create');
コントローラー
//フォーム(create) 一般的にはindexメソッドの下に書くことがおおい
public function create()
{
return Inertia::render('Inertia/Create'); //コンポーネント
}
コンポーネント作成
<script setup>
import { reactive } from 'vue';
import { Inertia } from '@inertiajs/inertia'
const form = reactive({
title: null,
content: null
})
// フォームを入力したときの処理
const submitFunction = () => {
Inertia.post('/inertia', form)
}
</script>
<template>
<!-- フォーム(create) -->
<form @submit.prevent="submitFunction">
<input type="text" name="title" v-model="form.title">
<input type="text" name="content" v-model="form.content">
<button>送信</button>
</form>
</template>
CSRF(シーサーフ)
Cross-Site Request Forgeries(偽造)
🫠詳しく
有名なWEB関連の攻撃方法
悪意のあるURLにアクセスし、思わぬリクエストを利用されてしまう
->正しいページからアクセスできているかトークンを発行して確認する
フラッシュメッセージ
🫠詳しく
保存・登録・削除した際に一度だけ表示させるメッセージ
// Linkコンポーネントでstore保存処理
public function store(Request $request)
{
$request->validate([
'title' => ['required','max:20'],
'content' => ['required'],
]);
$inertiaTest = new InertiaTest;
$inertiaTest->title = $request->title;
$inertiaTest->content = $request->content;
// DBに保存
$inertiaTest->save();
//laravel9の機能
return to_route('inertia.index')->with([ //リダイレクトに続けてwithをつけ、セッションメッセージを渡すことができる
'message' => '登録しました'
]);
}
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'auth' => [
'user' => $request->user(),
],
'ziggy' => function () use ($request) {
return array_merge((new Ziggy)->toArray(), [
'location' => $request->url(),
]);
},
//Inertiaのミドルウェア 部分リロード
'flash' => [
'message' => fn() => $request->session()->get('message')
]
]);
}
<script setup>
</script>
<template>
<div v-if="$page.props.flash.message" class="bg-blue-300">
{{ $page.props.flash.message }}
</div>
ああああああ
</template>
Indexにv-forを追加してみる
🫠コントローラー側
Laravelでモデル軽油でデータ取得する場合、配列を拡張したコレクション型になる
public function index()
{
//第二引数は連想配列でkeyとvalueを渡す
return Inertia::render('Inertia/Index',[
'blogs'=>InertiaTest::all()
]);
}
全コード
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
// 追加
use Inertia\Inertia;
// Linkコンポーネントでstore保存
use App\Models\InertiaTest;
class InertiaTestController extends Controller
{
public function index()
{
//第二引数は連想配列でkeyとvalueを渡す
return Inertia::render('Inertia/Index',[
'blogs'=>InertiaTest::all()
]);
}
//フォーム(create) 一般的にはindexメソッドの下に書くことがおおい
public function create()
{
return Inertia::render('Inertia/Create'); //コンポーネント
}
public function show($id)
{
// dd()
// ララベルのデバッグ
// 処理を止めて変数の値をみることができる
// dd($id);
return Inertia::render('Inertia/Show',
[
// 引数として入ってきた値をvue側に渡す
'id' => $id
]);
}
// Linkコンポーネントでstore保存処理
public function store(Request $request)
{
$request->validate([
'title' => ['required','max:20'],
'content' => ['required'],
]);
$inertiaTest = new InertiaTest;
$inertiaTest->title = $request->title;
$inertiaTest->content = $request->content;
// DBに保存
$inertiaTest->save();
//laravel9の機能
//リダイレクトに続けてwithをつけ、セッションメッセージを渡すことができる
return to_route('inertia.index')
->with([
'message' => '登録しました'
]);
}
}
🫠vue
blogs
-
v-for
ひとつずつ取り出すことができる-
v-for
を付けるときにはソートや削除した時に値を保持するために:key
もつける
-
<script setup>
// コントローラーから渡す際はdefinePropsを書く
defineProps({
blogs: Array
})
</script>
<template>
<!-- フラッシュメッセージなので、リロードしたら消える -->
<div v-if="$page.props.flash.message" class="bg-blue-300">
{{ $page.props.flash.message }}</div>
<ul>
<li v-for="blog in blogs" :key="blog.id">
件名:{{ blog.title }},
本文:{{ blog.content }}
</li>
</ul>
</template>
🫠実行結果
件名を表示するとDBのinertia_tests.id
にあたる数字が表示される
イベントコールバック
🫠詳しく
処理の前後にフックさせて処理する仕組み
削除→本当に削除しますか?など
🫠ルート
//イベントコールバック
Route::delete('/inertia/{id}',[InertiaTestController::class, 'delete'])->name('inertia.delete');
全コード
<?php
use App\Http\Controllers\ProfileController;
use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use App\Http\Controllers\InertiaTestController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
// Inertia
Route::get('/inertia-test', function () {
return Inertia::render('InertiaTest');
}
);
// 追加
Route::get('/inertia/index',[InertiaTestController::class, 'index'])->name('inertia.index');
//フォーム(create)
Route::get('/inertia/create',[InertiaTestController::class, 'create'])->name('inertia.create');
// Linkコンポーネントでsutore保存
Route::post('/inertia',[InertiaTestController::class, 'store'])->name('inertia.store');
// ↓Linkルートパラメータ実装
Route::get('/inertia/show/{id}',[InertiaTestController::class, 'show'])->name('inertia.show');
//イベントコールバック
Route::delete('/inertia/{id}',[InertiaTestController::class, 'delete'])->name('inertia.delete');
Route::get('/', function () {
return Inertia::render('Welcome', [
'canLogin' => Route::has('login'),
'canRegister' => Route::has('register'),
'laravelVersion' => Application::VERSION,
'phpVersion' => PHP_VERSION,
]);
});
Route::get('/dashboard', function () {
return Inertia::render('Dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
Route::middleware('auth')->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});
require __DIR__.'/auth.php';
🫠コントローラー
showメソッドに追記
public function show($id)
{
// dd()
// ララベルのデバッグ
// 処理を止めて変数の値をみることができる
// dd($id);
return Inertia::render('Inertia/Show',
[
// 引数として入ってきた値をvue側に渡す
'id' => $id,
'blog' => InertiaTest::findOrFail($id)
]);
}
コントローラーにデリートメソッドを追記
// 削除処理
public function delete($id)
{
$book = InertiaTest::findOrFail($id);
// 削除完了
$book->delete();
return to_route('inertia.index')
->with([
'message' => '削除しました'
]);
}
🫠vue
<!-- Linkルートパラメータ実装 -->
<script setup>
import { Inertia } from '@inertiajs/inertia';
defineProps({
id : String,
blog: Object
})
// 引数が一つの場合(id)ではなくidだけで良き
const deleteConfirm = id => {
// //確認用
// console.log(id)
//Inertiaコードをかく
Inertia.delete(`/inertia/${id}`,{
onBefore: () => confirm('本当に削除しますか')
})
}
</script>
<template>
{{ id }}<br>
{{ blog.title }}
<button @click="deleteConfirm(blog.id)">削除</button>
</template>
スロット ~Vue.jsの機能~
他のコンポーネントを使ってみる
🫠ルート
// 他のコンポーネントを使ってみる
Route::get('/component-test', function () {
return Inertia::render('ComponentTest');
}
);
🫠Vueファイル🆕
<script setup>
import GuestLayout from '@/Layouts/GuestLayout.vue'
import Label from '@/Components/InputLabel.vue'
import Input from '@/Components/TextInput.vue'
</script>
<template>
<GuestLayout>
やっほー
</GuestLayout>
</template>