必要に駆られて仕方なしに下調べした時のメモ。
- Laravel11
- Vue3
- Vuetify3
あたりを使う。
TODOアプリ作ろうかと思ったけど、設定以降は目新しい事もなく単調なのでjsonplaceholder使った。
フレームワークを追うのは疲れる。
Laravel Sailの導入
環境構築が面倒なので今回はSailを使ってみることにした。
WSL2環境で試した。以下を参考。
Docker Installation Using Sail
以下のコマンドでプロジェクトを作れる。「todo-app」の部分を好きな名前にすればよい。
curl -s "https://laravel.build/todo-app" | bash
時間がかかるが、準備ができるとローカルにLaravelのプロジェクトディレクトリができる。
ターミナル出力の指示通り実行する。
cd todo-app && ./vendor/bin/sail up
sailは以下のようなコマンドが使える。
基本的にはdocker composeのエイリアスっぽい。
コマンド | 機能 |
---|---|
sail up [-d] | コンテナ起動 |
sail down | コンテナ終了 |
sail start | コンテナの再開 |
sail stop | コンテナの停止 |
sail shell | コンテナのシェルに入る |
sail test | テスト実行 |
sail artisan | コンテナ内でartisanを使う |
sail npm | コンテナ内でnpmを使う |
sail node | コンテナ内でnodeを実行 |
sail exec mysql mysql -u sail -p | mysqlクライアントで接続。パスワードはpassword |
参考: Laravel sail を使って Laravel9 の環境構築を行う
セッション用テーブルを準備して表示確認
とりあえず初期のマイグレーションを実行して動作確認する。
./vendor/bin/sail artisan migrate
これで以下のURLでアプリケーションへアクセスできる。
http://localhost
認証を追加する
とりあえず標準で入っているやつで追加したい。
コンテナ入って。
./vendor/bin/sail shell
モジュール入れて。
composer require laravel/ui --dev php artisan ui vue --auth npm install && npm run dev # 次回以降は ./vendor/bin/sail npm run devの方が便利
以下にアクセスし直して登録ページやログインページを動かしてみる。動くはず。
http://localhost
一応mysqlにデータが入っているかも見てみる。
./vendor/bin/sail exec mysql mysql -u sail -p > use laravel # laravelデータベースへ接続 > show tables # テーブル一覧を一応確認 > select * from users \G #ユーザーテーブルを確認 > \q
認証済みのユーザーだけが見れるページを確認する
一応確認。
以下は認証済みでないと見れなくなっている。
http://localhost/home
生成されたコントローラーを見ると、middleware('auth')で認証チェックされている。
class HomeController extends Controller { /** * Create a new controller instance. * * @return void */ public function __construct() { $this->middleware('auth'); }
認証機能を変更する
メールアドレスとパスワードではなく、メールアドレスと電話番号を使って認証するようにする。
今回はユーザー登録とログインだけ考えてみる。
なぜこんな変な事をするかと言えば似たような事が仕事の要件になりそうだから。
DBを変更
電話番号のカラムを加えるマイグレーションを作る。
./vendor/bin/sail artisan make:migration add_tel_to_users --table=users
内容は雑だけどこんな感じで。
/** * Run the migrations. */ public function up(): void { Schema::table('users', function (Blueprint $table) { // nameの後にtelを追加 $table->string('tel', 25)->after('name'); }); } /** * Reverse the migrations. */ public function down(): void { Schema::table('users', function (Blueprint $table) { $table->dropColumn('tel'); }); }
一応状態を確認して。
./vendor/bin/sail artisan migrate:status
マイグレーションする。
./vendor/bin/sail artisan migrate
一応mysqlつないで確認してみる。
./vendor/bin/sail exec mysql mysql -u sail -p # パスワードはpassword > use laravel > select * from users \G
認証用のコードを変更
ちょっと極端な例だけど、メールアドレスと電話番号でログインできるようにしてみる。
表示部分
とりあえず表示から変えてみる。
以下2ファイルに電話番号の入力欄を追加して、余分なものを消した。
- resources/views/auth/login.blade.php
- resources/views/auth/register.blade.php
ユーザーモデルの変更
userモデルのfillableにtel加えただけ。この例だとパスワードとかもホントはいらない。
protected $fillable = [ 'name', 'tel', 'email', 'password', ];
ユーザー登録用コントローラーの変更
バリデーションと登録処理をちょっと変更。
protected function validator(array $data) { return Validator::make($data, [ 'name' => ['required', 'string', 'max:255'], 'tel' => ['required', 'string', 'max:25', 'regex:/^[0-9]+$/'], # 数字だけにした 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 'password' => ['required', 'string', 'min:8', 'confirmed'], ]); } protected function create(array $data) { return User::create([ 'name' => $data['name'], 'tel' => $data['tel'], # 追加した 'email' => $data['email'], 'password' => Hash::make($data['password']), ]); }
とりあえず登録はできるようになった。
認証処理の変更
仕組みをちょっと調べる
仕組みを調べるにあたって軽く以下を眺めた。
ただ、見るべきコードはLaravel11では以下な気がする。
vendor/laravel/ui/auth-backend/
ここにあるAuthenticatesUsers.phpがLoginControllerで使われているtraitのよう。
このtraitのloginをオーバーライドするだけでも好き勝手できそう。
もうちょい良い方法はないかと探すと以下が見つかる。
認証するユーザを探すプロバイダを作って提供すればよいらしい。
継承して差し替える元のコードはおそらくこれ。
vendor/laravel/framework/src/Illuminate/Auth/EloquentUserProvider.php
ちょっとしんどいな。。。でも正しいアプローチだと思う。
あるいは強引にログインさせてしまうアプローチもあるらしい。
Laracast - Using Auth::attempt() without password
LoginControllerでオーバーライドして実装してみる
traitのloginをオーバーライドする方法を試してみる。
+use Illuminate\Http\Request; use App\Http\Controllers\Controller; use Illuminate\Foundation\Auth\AuthenticatesUsers; +use App\Models\User; +use Illuminate\Validation\ValidationException; +use Illuminate\Support\Facades\Auth; class LoginController extends Controller { @@ -37,4 +41,28 @@ public function __construct() $this->middleware('guest')->except('logout'); $this->middleware('auth')->only('logout'); } + + /** + * 認証を行う + * vendor/laravel/ui/auth-backend/AuthenticatesUsers.phpをオーバーライド + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse + * + * @throws \Illuminate\Validation\ValidationException + */ + public function login(Request $request) { + $user = User::where([ + 'email' => $request->email, + 'tel' => $request->tel, + ])->first(); + if ($user) { + Auth::loginUsingId($user->id); + return redirect('/home'); + } + throw ValidationException::withMessages([ + 'email' => 'メールアドレスか電話番号に誤りがあります', + ]); + } +
強引な感じもするが、単純な業務アプリならこのくらいシンプルじゃないと実装しんどい。
TODOアプリの見た目を作る
この辺を参考にしつつやった。ほぼリンクそのままやる。
/app以下をSPAにした。
たらおブログ - Vue3 × Vuetify3 × Laravelでタスク管理アプリ作ってみた
vue3自体は認証を作る時にlaravel-uiと一緒に入ったはずなので、追加で以下を導入する。
- vue-router
- vuetify
vue-routerの導入
./vendor/bin/sail shell npm install vue-router
resources/js/router.jsを用意する。参考サイトそのまんま。
import { createRouter, createWebHistory } from 'vue-router'; import Task from './components/Task.vue'; import Show from './components/Show.vue'; const routes = [ { path: '/app/tasks', name: 'tasks', component: Task }, { path: '/app/tasks/:id', name: 'show', component: Show } ]; const router = createRouter({ history: createWebHistory(), routes }); export default router;
resources/js/app.jsを編集してrouterを使うようにする。
// これを加えて import router from './router'; // ExampleComponentはやめてAppを用意することにした import AppComponent from './App.vue'; app.component('app', AppComponent); // useを挟む app.use(router).mount('#app');
次に仮のコンポーネントを用意する。
まずタスク一覧。resources/js/components/Task.vue
<script setup> </script> <template> <h1>タスク一覧</h1> </template>
次にタスク詳細。resources/js/components/Show.vue
<script setup> </script> <template> <h1>タスク詳細</h1> </template>
最後にルーティングするメインのコンポーネント。resources/js/App.vue
<script setup> import { RouterView } from 'vue-router'; </script> <template> <RouterView /> </template>
laravelのテンプレートを用意する。
resources/view/app.blade.php
@extends('layouts.app') @section('content') <app></app> @endsection
Laravelのルーティングを追加する。app以下はvue-routerのページに任せる。
Route::prefix('app')->middleware('auth')->group(function() { Route::get('/{any}', function () { return view('app'); })->where('any', '.*'); });
vuetifyを導入する
とりあえず入れる。
./vendor/bin/sail shell npm install vuetify npm install @mdi/font -D # アイコンフォント
resources/js/app.jsを編集する。
// Vuetifyのインポートを加えてuseする import 'vuetify/styles' import { createVuetify } from 'vuetify' import * as components from 'vuetify/components' import * as directives from 'vuetify/directives' const vuetify = createVuetify({ components, directives, icons: { defaultSet: 'mdi', }, }) createApp(App).use(vuetify).use(router).mount('#app');
ここまでで設定できた。
resources/js/components/Task.vueとかに適当なコンポーネントを書けばとりあえず動く。
vuetifyはとりあえずdatepickerを出した。この辺りを適当にみる。
https://vuetifyjs.com/en/components/date-pickers/#date-pickers
https://vuetifyjs.com/en/api/v-date-picker/#links
データはjsonplaceholderでとってそのまま出した。
<script setup> import { onMounted } from 'vue' import { ref } from 'vue' import axios from 'axios' const selectedDate = ref(new Date) const todos = ref([]) const menu = ref(false) const handleOpen = () => { menu.value = true } const getTodos = async () => { const todos = await axios.get('https://jsonplaceholder.typicode.com/todos') return todos.data } onMounted(async () => { todos.value = await getTodos() }) </script> <template> <h1>タスク一覧</h1> <label>{{ selectedDate?.toLocaleDateString('ja-jp', 'YYYY-MM-DD') }}</label> <button @click="handleOpen">open</button> <v-dialog v-if="menu" v-model="menu" :close-on-content-click="true" full-screen > <v-locale-provider locale="ja"> <v-date-picker title="日付選択" v-model="selectedDate" color="primary" ></v-date-picker> </v-locale-provider> </v-dialog> <ul> <li v-for="(todo, index) in todos"> {{ todo.title }} </li> </ul> </template>