Open5
10年ぶりにLaravelを勉強しながら個人開発
勉強したことや進捗報告書いてく
セットアップ
開発機:M1 Macbook air
開発環境:Laravel Sail
PJ作成
curl -s https://laravel.build/punda | bash
今回はPundaというサービスを作りたいので上記で。
PJ名は好きに書き換えてね
pundaというディレクトリが作られるので移動してDockerを立ち上げる。
cd punda
sail up -d
もうこれでhttp://localhostへアクセスしたらWebページできてんだからすげぇよなぁ
フロントエンド作成
composer require laravel/breeze --dev
php artisan breeze:install vue
php artisan migrate
npm install
npm run dev
はいこれでログイン機能とフロントエンドのセットアップが完了
Crud作ってみる
Controller作成
php artisan make:controller UsersController --resource
オプションつけることでCrud関数がすでにある状態でControllerが作成される。
UsersController
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User;
use Inertia\Inertia;
class UsersController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
$users = User::paginate(20);
return Inertia::render('Users/Index', ['users' => $users]);
}
}
ページネーションでユーザ一覧を取得してフロントに渡してる。
フロント作成
折角なのでVuetifyのPagenationコンポーネントを使って実装。
<script setup>
import { ref, onMounted } from 'vue';
import { Head, router, usePage } from '@inertiajs/vue3';
import AdminLayout from '@/Layouts/AdminLayout.vue';
import { UserPlusIcon } from '@heroicons/vue/24/outline'
defineProps({
users: {
type: Object,
required: true,
},
});
const page = ref(1);
const users = ref(usePage().props.users);
const fetchUsers = () => {
if (!page.value) return;
router.get(route('admin.users', { page: page.value }), {}, {
preserveState: true,
onSuccess: ({ props }) => {
users.value = props.users || { data: [], last_page: 1, current_page: 1 };
},
});
};
onMounted(() => {
page.value = users.value?.current_page || 1;
});
</script>
<template>
<Head title="Admin" />
<AdminLayout>
<v-container>
<v-card flat border rounded="xl" v-card class="d-flex flex-column" style="height: calc(100vh - 96px);">
<v-card-title class="pa-0">
<v-toolbar>
<v-toolbar-title>ユーザ一覧</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn :icon="UserPlusIcon" variant="text" v-tooltip:bottom="'追加'"></v-btn>
</v-toolbar>
</v-card-title>
<v-card-text class="overflow-auto flex-grow-1">
<v-list lines="two" v-if="users?.data?.length">
<v-list-item v-for="user in users.data" :key="user.id" :subtitle="user.subtitle"
:title="user.name">
<template v-slot:prepend>
<v-avatar color="grey-lighten-1">
<v-icon color="white">mdi-user</v-icon>
</v-avatar>
</template>
<template v-slot:append>
<v-btn color="grey-lighten-1" icon="mdi-pen" variant="text"></v-btn>
</template>
</v-list-item>
</v-list>
<v-alert v-else type="info">ユーザーが見つかりません。</v-alert>
</v-card-text>
<v-divider></v-divider>
<v-card-action>
<v-pagination :model-value="page" :length="users.last_page"
@update:modelValue="val => { page = val; fetchUsers(); }"></v-pagination>
</v-card-action>
</v-card>
</v-container>
</AdminLayout>
</template>
ええやんええやん。
詳細ページ
Controller
詳細ページを作成
public function show($account)
{
$user = User::where(['account' => $account])->first();
if (!$user) {
return abort(404);
}
return Inertia::render('Users/Show', ['user' => $user]);
}
View
一覧ページにリンクを追加
Users/Index.vue
<Link v-for="user in users.data" :key="user.id"
:href="route('admin.users.show', { account: user.account })" as="v-list-item">
<v-list-item :subtitle="user.subtitle" :title="user.name" link>
<template v-slot:prepend>
<v-avatar color="grey-lighten-1">
<v-icon color="white">mdi-user</v-icon>
</v-avatar>
</template>
<template v-slot:append>
<v-btn color="grey-lighten-1" icon="mdi-pen" variant="text"></v-btn>
</template>
</v-list-item>
</Link>
詳細ページを作成
Uses/show.vue
<script setup>
import { ref, } from 'vue';
import { Head, usePage } from '@inertiajs/vue3';
import AdminLayout from '@/Layouts/AdminLayout.vue';
import { PencilIcon, UserIcon } from '@heroicons/vue/24/outline'
defineProps({
user: {
type: Object,
required: true,
},
});
const user = ref(usePage().props.user);
</script>
<template>
<Head :title="user.name" />
<AdminLayout>
<v-container>
<v-card class="profile-card" flat border rounded="xl" v-card>
<v-toolbar>
<v-list-item class="w-100">
<template v-slot:prepend>
<v-badge color="success" dot>
<v-avatar color="grey-darken-3"
image="https://avataaars.io/?avatarStyle=Transparent&topType=ShortHairShortCurly&accessoriesType=Prescription02&hairColor=Black&facialHairType=Blank&clotheType=Hoodie&clotheColor=White&eyeType=Default&eyebrowType=DefaultNatural&mouthType=Default&skinColor=Light"></v-avatar>
</v-badge>
</template>
<v-list-item-title v-text="user.name"></v-list-item-title>
<v-list-item-subtitle v-text="'@' + user.account"></v-list-item-subtitle>
<template v-slot:append>
<v-btn variant="flat" :icon="UserIcon" class="mr-1"></v-btn>
<v-btn variant="flat" :icon="PencilIcon"></v-btn>
</template>
</v-list-item>
</v-toolbar>
<v-card-text>
<v-row no-gutters>
<v-col cols="3">
<v-list-item>
<v-list-item-content>
<v-list-item-title class="font-weight-bold">ID</v-list-item-title>
<v-list-item-subtitle>{{ user.id }}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-col>
<v-col cols="9">
<v-list-item>
<v-list-item-content>
<v-list-item-title class="font-weight-bold">Hash</v-list-item-title>
<v-list-item-subtitle>{{ user.hash }}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-col>
<v-col cols="12">
<v-list-item>
<v-list-item-content>
<v-list-item-title class="font-weight-bold">タイトル</v-list-item-title>
<v-list-item-subtitle>{{ user.title ? user.title : 'なし' }}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-col>
<v-col cols="12">
<v-list-item>
<v-list-item-content>
<v-list-item-title class="font-weight-bold">自己紹介</v-list-item-title>
<v-list-item-subtitle>{{ user.bio ? user.bio : 'なし' }}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-col>
<v-col cols="6">
<v-list-item>
<v-list-item-content>
<v-list-item-title class="font-weight-bold">メール</v-list-item-title>
<v-list-item-subtitle>{{ user.email ? user.email : 'なし' }}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-col>
<v-col cols="6">
<v-list-item>
<v-list-item-content>
<v-list-item-title class="font-weight-bold">メール更新日</v-list-item-title>
<v-list-item-subtitle>{{ user.email_verified_at ? user.email_verified_at : 'なし'
}}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-col>
<v-col cols="6">
<v-list-item>
<v-list-item-content>
<v-list-item-title class="font-weight-bold">アカウント作成日</v-list-item-title>
<v-list-item-subtitle>{{ user.created_at ? user.created_at : 'なし'
}}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-col>
<v-col cols="6">
<v-list-item>
<v-list-item-content>
<v-list-item-title class="font-weight-bold">アカウント更新日</v-list-item-title>
<v-list-item-subtitle>{{ user.updated_at ? user.updated_at : 'なし'
}}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-col>
</v-row>
</v-card-text>
</v-card>
</v-container>
</AdminLayout>
</template>
ユーザの項目は追々増やしていこう