Open5

10年ぶりにLaravelを勉強しながら個人開発

404_niro404_niro

セットアップ

開発機: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ページできてんだからすげぇよなぁ

404_niro404_niro

フロントエンド作成

composer require laravel/breeze --dev
php artisan breeze:install vue
php artisan migrate
npm install
npm run dev

はいこれでログイン機能とフロントエンドのセットアップが完了

404_niro404_niro

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>


ええやんええやん。

404_niro404_niro

詳細ページ

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>


ユーザの項目は追々増やしていこう