Blade
Introduction
Route::get('/', function () {
return view('greeting', ['name' => 'Finn']);
});
Additional Attributes
<input type="checkbox"
name="active"
value="active"
@checked(old('active', $user->active)) />
- 与えられた条件を評価して、
true
の場合にchecked
を出力する。
@checked((old('active') === "active") || old('active') === null)
- radioボタンの場合はこんな感じで使えるよ。
<select name="version">
@foreach ($product->versions as $version)
<option value="{{ $version }}" @selected(old('version') == $version)>
{{ $version }}
</option>
@endforeach
</select>
ここから下はなんかHTMLディレクティブに直接関係あるやつ。
<button type="submit" @disabled($errors->isNotEmpty())>Submit</button>
<input type="email"
name="email"
value="email@laravel.com"
@readonly($user->isNotAdmin()) />
<input type="text"
name="title"
value="title"
@required($user->isAdmin()) />
Displaying Data
Route::get('/', function () {
return view('welcome', ['name' => 'Samantha']);
});
Route::get('/', function () { return view('welcome', ['name' => 'Samantha']); return view('admin.index', ['name' => 'Samantha']); });
- ディレクトリを掘る時はこんな感じにする。
Hello, {{ $name }}.
The current UNIX timestamp is {{ time() }}.
- blade echo statement 内にPHP関数も使える。
Displaying Unescaped Data
Hello, {!! $name !!}.
- blade echo statement はデフォルトで
htmlspecialchars()
を実行している。XSS対策にね。 - エスケープ無しで出力したい場合に使う。
Forms
CSRF Field
<form method="POST" action="/profile">
@csrf
...
</form>
Method Field
<form action="/foo/bar" method="POST">
@method('PUT')
...
</form>
- HTMLフォームは
PUT
、PATHC
、DELETE
リクエストを作成できないので、Bladeで変わりにやって上げられる。
Validation Errors
<!-- /resources/views/post/create.blade.php -->
<label for="title">Post Title</label>
<input id="title"
type="text"
class="@error('title') is-invalid @enderror">
@error('title')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
<!-- /resources/views/auth.blade.php -->
<label for="email">Email address</label>
<input id="email"
type="email"
class="@error('email') is-invalid @else is-valid @enderror">
<!-- /resources/views/auth.blade.php -->
<label for="email">Email address</label>
<input id="email"
type="email"
class="@error('email', 'login') is-invalid @enderror">
@error('email', 'login')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
print debug
@dd() # こっちはexitも含まれている感じ
@dump() # こっちは出力してその後も続く
Collections
Introduction
$collection = collect(['taylor', 'abigail', null])
->map(function (?string $name) {
return strtoupper($name);
})
->reject(function (string $name) {
return empty($name);
});
- immutable
-
collection()
メソッドは実行される度に、新しいインスタンスを作る
Creating Collections
$collection = collect([1, 2, 3]);
-
Eloquet
クエリの返値はいつもCollection
になっているらしい。つまり、Model経由で取ってきたデータは全てCollectionになっている。
Extending Collections
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
Collection::macro('toUpper', function () {
return $this->map(function (string $value) {
return Str::upper($value);
});
});
$collection = collect(['first', 'second']);
$upper = $collection->toUpper();
// ['FIRST', 'SECOND']
-
macro()
メソッドを使って、カスタムの関数を追加できる。上記は全て大文字にする関数を追加している例。 - 通常、Service Provider の
boot()
メソッドに追加する。 - Collection Macroと呼ばれている?
Available Methods
Constants
Controller
# 作成
$ php artisan make:controller ApiProductController
# モデルに紐づけながら作成
$ php artisan make:controller ApiProductController --model=Product
$ php artisan route:list
$ php artisan route:list -help
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\View\View;
class UserController extends Controller
{
public function show(string $id): View
{
return view('user.profile', [
'user' => User::findOrFail($id)
]);
}
}
resource
https://laravel.com/docs/11.x/controllers#resource-controllers
https://laravel.com/docs/11.x/controllers#specifying-the-resource-model
一般的なCRUDに必要なメソッドを含ませながらコントローラーを作成する
$ php artisan make:controller PhotoController --resource
$ php artisan make:controller PhotoController --model=Photo --resource
class PhotoController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index() {}
/**
* Show the form for creating a new resource.
*/
public function create() {}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request) {}
/**
* Display the specified resource.
*/
public function show(News $news) {}
/**
* Show the form for editing the specified resource.
*/
public function edit(News $news) {}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, News $news) {}
/**
* Remove the specified resource from storage.
*/
public function destroy(News $news) {}
}
use App\Http\Controllers\PhotoController;
Route::resource('photos', PhotoController::class);
Route::resources([
'photos' => PhotoController::class,
'posts' => PostController::class,
]);
single controller
Database
driver
SQLiteを使う
データ格納用のファイルを作成
$ touch database/database.sqlite
.envの更新
+ DB_CONNECTION=sqlite
- DB_CONNECTION=mysql
- DB_HOST=mysql
- DB_PORT=3306
- DB_DATABASE=laravel_breeze_multi_auth
- DB_USERNAME=sail
- DB_PASSWORD=password
マイグレート
$ php artisan migrate
テーブルの確認方法
tinker
$ php artisan tinker
$ sail tinker
$ App\Models\User::all()
$ DB::table('users')->get();
$ DB::table('users')->find(3);
$ DB::table('users')->where('name', 'John')->first();
$ DB::table('users')->where('name', 'John')->value('email');
$ DB::table('users')->pluck('title'); # 全ての行の title が collection で返ってくる
$ DB::table('users')->pluck('title', 'name'); # name がキーとなる形で collection が返ってくる
$ DB::table('users')->where('name', 'john')->exists();
$ DB::table('users')->where('name', 'john')->doesntExist();
https://laravel.com/docs/11.x/artisan#tinker
https://github.com/bobthecow/psysh
https://laravel.com/docs/11.x/queries#running-database-queries
mysql
sail mysql
sail shell
mysql -u sail -ppassword -h mysql
mysql -u root -ppassword -h mysql
dumpはrootでしかできないから注意。
Environment
https://laravel.com/docs/11.x/installation#initial-configuration
# .env
APP_NAME=Laravel
APP_TIMEZONE=Asia/Tokyo
APP_LOCALE=ja
APP_FALLBACK_LOCALE=ja
APP_FAKER_LOCALE=ja_JP
# config/app.php
return [
'timezone' => 'Asia/Tokyo',
'locale' => 'ja',
'fallback_locale' => 'ja',
'faker_locale' => 'ja_JP',
],
# 日本語の翻訳ファイルを追加
$ composer require --dev laravel-lang/lang laravel-lang/publisher
$ php artisan lang:add ja
# インストール後はライブラリ不要なのでアンインストールする
$ composer remove --dev laravel-lang/lang laravel-lang/publisher
Factory
$ php artisan make:factory PostFactory
class FlightFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var class-string<\Illuminate\Database\Eloquent\Model>
*/
protected $model = Flight::class;
}
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => static::$password ??= Hash::make('password'),
'remember_token' => Str::random(10),
];
}
Migration
Generating Migrations
$ php artisan make:migration create_flights_table
$ php artisan make:migration alter_users_table --table=users
- テーブル編集の場合は
--table
を後ろにつける。 - 参考記事
$ php artisan make:migration create_users_table --create=users
- 新規作成の場合は
--create
を後ろにつける。 - 参考記事
マイグレーションファイルの命名について
$ php artisan make:migration create_users_table --create=users
- 新規作成
$ php artisan make:migration add_name_column_to_users_table --table=users
$ php artisan make:migration add_columns_to_users_table --table=users
- カラム追加と複数カラム追加
$ php artisan make:migration remove_name_column_from_users_table --table=users
$ php artisan make:migration remove_columns_to_users_table --table=users
- カラム削除と複数カラム削除
$ php artisan make:migration modify_name_column_of_users_table --table=users
$ php artisan make:migration modify_name_columns_of_users_table --table=users
- カラム修正と複数カラム修正
$ php artisan make:migration update_users_table --table=users
- テーブル修正
Running Migrations
$ php artisan migrate
$ php artisan migrate:status
$ php artisan migrate --pretend
Rolling Back Migrations
# 最新を戻す
$ php artisan migrate:rollback
# 5個戻す
$ php artisan migrate:rollback --step=5
# バッチを3個戻す
$ php artisan migrate:rollback --batch=3
# dry-run
$ php artisan migrate:rollback --pretend
# すべてを
$ php artisan migrate:reset
Roll Back and Migrate Using a Single Command
$ php artisan migrate:refresh
# Refresh the database and run all database seeds...
$ php artisan migrate:refresh --seed
- 全てのmigrationをrollbackした後、migrateする。テーブルをdropする訳ではない。
- データを一旦綺麗にするというイメージで良い。
$ php artisan migrate:refresh --step=5
- これも、データを一旦綺麗にするというイメージ。
- 大量にmigrationがある状況で、全部rollbackするよりは早いよね?というのが利点だろうと思う。
Drop All Tables and Migrate
$ php artisan migrate:fresh
$ php artisan migrate:fresh --seed
- 全テーブルをdropした後、migrateする。
Tables
Creating Tables
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email');
$table->timestamps();
});
Updating Tables
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});
Renaming / Dropping Tables
use Illuminate\Support\Facades\Schema;
Schema::rename($from, $to);
Schema::drop('users');
Schema::dropIfExists('users');
Columns
Creating Columns
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->integer('votes');
});
php artisan make:migration add_image_column_of_ramens_table --table=ramens
public function up(): void
{
Schema::table('ramens', function (Blueprint $table) {
$table->string('image');
});
}
public function down(): void
{
Schema::table('ramens', function (Blueprint $table) {
$table->dropColumn('image');
});
}
Available Column Types
$table->id(); |
$table->boolean('confirmed'); |
$table->timestamp('added_at', precision: 0); |
$table->foreignId('user_id'); |
$table->integer('votes'); |
$table->longText('description'); |
$table->string('name', length: 100); |
$table->text('description'); |
Column Modifiers
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->nullable();
});
- カラム型定義の後に続ける修飾子.
- 要は制約のこと。
->autoIncrement() |
->nullable($value = true) |
->useCurrent() |
->useCurrentOnUpdate() |
->after('column') |
- uniqueは違うよ!
Column Order
$table->after('password', function (Blueprint $table) {
$table->string('address_line1');
$table->string('address_line2');
$table->string('city');
});
- MySQLを使っている時に利用できる。
-
after()
メソッドで、第一引数で指定したカラムの後に追加できる。
Modifying Columns
Schema::table('users', function (Blueprint $table) {
$table->string('name', 50)->change();
});
Schema::table('users', function (Blueprint $table) {
$table->integer('votes')->unsigned()->default(1)->comment('my comment')->change();
});
- 全ての保持させたい定義を記述した上で、
change()
メソッドを使う。 - 含めていない定義は削除されるから注意。
// Add an index...
$table->bigIncrements('id')->primary()->change();
// Drop an index...
$table->char('postal_code', 10)->unique(false)->change();
- indexは削除されない。
- indexの追加・削除・修正をする場合は、明示的に指定する必要がある。
Renaming Columns
Schema::table('users', function (Blueprint $table) {
$table->renameColumn('from', 'to');
});
Dropping Columns
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('votes');
});
Schema::table('users', function (Blueprint $table) {
$table->dropColumn(['votes', 'avatar', 'location']);
});
Available Command Aliases
Command |
---|
$table->dropRememberToken(); |
$table->dropTimestamps(); |
Indexes
Creating Indexes
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('users', function (Blueprint $table) {
$table->string('email')->unique();
});
- 1行で実行しちゃう。
$table->unique('email');
- カラム定義したあとに、追加もできる。
- あまり使わないかも?
$table->index(['account_id', 'created_at']);
- 複数カラムを同時にもできる。
- カラム定義して、その後まとめて、indexつけるって感じで、こちらの方が使いそう。
$table->unique('email', 'unique_email');
- 第二引数で付けたいindex名を指定できる。
- 指定しない限りは、Laravelが勝手に良きにindex名を振ってくれる。
Available Index Types
Command |
---|
$table->primary('id'); |
$table->unique('email'); |
$table->index('state'); |
uniqueでnullableにしたい場合がある。
空の場合はunique制約を効かせず、値が入った時には効かせるという。普通にチェーンすれば大丈夫。
$table->string('email')->nullable()->unique();
空文字列は
null
ではないので注意する。
Foreign Key Constraints
WIE
注意
- 外部キー制約の前に、他のカラム定義を書く。
-
up()
で作成し、down()
で削除する場合は、カラム削除の命令も書いておく必要がある。
$table->foreign('user_id')->references('id')->on('users');
$table->foreignId('user_id')->constrained();
$table->foreignId('user_id')->constrained(
table: 'users', indexName: 'posts_user_id'
);
$table->foreignId('user_id')
->constrained()
->onUpdate('cascade')
->onDelete('cascade');
$table->foreignId('user_id')
->constrained()
->onUpdate('cascade')
->onDelete('cascade');
$table->cascadeOnUpdate();
$table->restrictOnUpdate();
$table->noActionOnUpdate();
$table->cascadeOnDelete();
$table->restrictOnDelete();
$table->nullOnDelete();
$table->dropForeign('posts_user_id_foreign');
$table->dropForeign(['user_id']);
Model
show
$ php artisan model:show Flight
Create model and migration simultaneously
$ php artisan make:model Product -m
Inserting and Updating Models
Inserts
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Flight;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class FlightController extends Controller
{
/**
* Store a new flight in the database.
*/
public function store(Request $request): RedirectResponse
{
// Validate the request...
$flight = new Flight;
$flight->name = $request->name;
$flight->save();
return redirect('/flights');
}
}
- Eloquentを使うおかげで、データベースからモデルを取ってくる必要がない。
- データベースにデータを登録するには、モデルのインスタンスを作成し、各attributeを設定するだけ。
-
save()
メソッドを呼んだタイミングで、created_at
とupdated_at
にタイムスタンプがセットされるため、手動でセットする必要はない。
use App\Models\Flight;
$flight = Flight::create([
'name' => 'London to Paris',
]);
- よりシンプルに書けるね。
- 登録されたモデルのインスタンスが返値で返ってくる。
-
fillabel
プロパティかguarede
プロパティを設定しておく必要がある。
Updates
Mass Assignment
use App\Models\Flight;
$flight = Flight::create([
'name' => 'London to Paris',
]);
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name'];
}
-
create()
メソッドを使う場合、上記のように、fillable
プロパティをモデルクラスに設定する必要がある。 - これは、Eloquent models が DB への mass assignment vulnerability から守るため。
- 基本的には、 mass assignment を使ってデータを格納していくので、設定してあげる。
Allowing Mass Assignment
/**
* The attributes that aren't mass assignable.
*
* @var array
*/
protected $guarded = [];
- 格納されたくないカラムを配列に書く。
- 逆に全てのカラムを許可する場合は、
fillable
プロパティではなく、こちらで設定する方が簡単かも。
Request
Route
group
prefix
Route::prefix('admin')->name('admin.')->group(function () {
Route::get('/users', function () {
// Matches The "/admin/users" URL
// Route assigned name "admin.users"...
})->name('users');
});
route model binding
URLのセグメント名と対応するModel名を一致させることで、Laravelが良きに解決してくれる。
use App\Models\User;
Route::get('/users/{user}', function (User $user) {
return $user->email;
});
use App\Http\Controllers\UserController;
use App\Models\User;
// Route definition...
Route::get('/users/{user}', [UserController::class, 'show']);
// Controller method definition...
public function show(User $user)
{
return view('user.profile', ['user' => $user]);
}
Resourcesでまとめてnameを付ける
Route::resource('/admin/ramen', RamenController::class)
->names('admin');
Resourcesのパラメータを書き替えたい
※urlが深いとできないから注意。
Route::resource('/ramen', RamenController::class)
->parameter('raman', 'ramen');
Formでの基本的なルート設定
Route::get('/', [AdmissionController::class, 'show'])
->name('show');
Route::post('/', [AdmissionController::class, 'post'])
->name('post');
Route::get('/confirm', [AdmissionController::class, 'confirm'])
->name('confirm');
Route::post('/confirm', [AdmissionController::class, 'send'])
->name('send');
Route::get('/thanks', [AdmissionController::class, 'complete'])
->name('complete');
- get 問い合わせフォームを表示
- post 問い合わせフォーム遷移先
- get 確認画面
- post 確認画面からフォーム遷移先
- get 完了画面
viewでの書き方は複数ある
<a href="{{ url('/form') }}">お問い合わせはこちら</a>
<a href="{{ route('form.show') }}">お問い合わせはこちら</a>
<a href="{{ action('SampleFormController@show') }}">お問い合わせはこちら</a>
■ url()
長所:URLがどうなるかわかりやすい
短所:各機能のURLを知っておく必要がある
■ route()
長所:記述がシンプル。URLを書き換える時ルーティングの設定ファイルだけで良い
短所:URLがどうなるかわかりにくい
■ action()
長所:クラス名と関数名がわかるので、遷移先の処理が追いかけやすい
短所:クラス名が長いのテンプレートが読みづらくなる
新しいルートを追加したのにNotFoundになる
ルーティングの順番に問題がある場合が多い。
上から読み込まれるので、
Route::get('/users/{user}', 'User@show');
Route::get('/users/hoge', 'User@hoge');
の順番にすると、hogeが動かない。
Response
redirect
redirecting to named routes
return redirect()->route('login');
// For a route with the following URI: /profile/{id}
return redirect()->route('profile', ['id' => 1]);
// For a route with the following URI: /profile/{id} ※
return redirect()->route('profile', [$user]);
If you would like to customize the value that is placed in the route parameter, you can specify the column in the route parameter definition (/profile/{id:slug}
) or you can override the getRouteKey
method on your Eloquent model:
/**
* Get the value of the model's route key.
*/
public function getRouteKey(): mixed
{
return $this->slug;
}
https://laravel.com/docs/11.x/responses#populating-parameters-via-eloquent-models
redirecting with flashed session data
https://laravel.com/docs/11.x/responses#redirecting-with-flashed-session-data
Route::post('/user/profile', function () {
// ...
return redirect('dashboard')->with('status', 'Profile updated!');
});
@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
Shell
シェルにアクセス
sail shell
Seeding
基本
$ php artisan make:seeder UserSeeder
# database/seeders/UsersTableSeeder.php
class UsersTableSeeder extends Seeder
{
public function run()
{
DB::table('users')->insert([
'name' => Str::random(10),
'email' => 'john@doe.com',
'password' => Hash::make('password')
]);
News::factory()->count(10)->create();
}
}
$ php artisan db:seed --class=UserSeeder
Model factory
まず、seedingを考える前に、[factory](# Factory) を作成しないといけない。
public function run(): void
{
User::factory()
->count(50)
->hasPosts(1)
->create();
}
hasPosts(1)
メソッドは 1つの関連するPostデータを持っている。
Calling Additional Seeders
# database/seeders/DatabaseSeeder.php
public function run(): void
{
$this->call([
UserSeeder::class,
PostSeeder::class,
CommentSeeder::class,
]);
}
Running
$ php artisan db:seed
$ php artisan db:seed --class=UserSeeder
Test
php artisan make:test FirstTest
php artisan make:test FirstTest --unit
php artisan test
Validation
Validation Quickstart
Writing the Validation Logic
- validationが失敗すると、これは自動的に適切な処理である、
Illuminate\Validation\ValidationException
exceptionが投げられる。 - 挙動としては、元居た場所に戻される。
- 全てのバリエーションエラーとリクエストをflashデータとしてセッションに格納する。
- XHR requestの場合は、jsonが返される。
/**
* Store a new blog post.
*/
public function store(Request $request): RedirectResponse
{
$validated = $request->validate([
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
// The blog post is valid...
return redirect('/posts');
}
$validatedData = $request->validate([
'title' => ['required', 'unique:posts', 'max:255'],
'body' => ['required'],
]);
- 配列で区切ることもできるよ
$validatedData = $request->validateWithBag('post', [
'title' => ['required', 'unique:posts', 'max:255'],
'body' => ['required'],
]);
- 名前付きvalidation error bagでvalidation errorをグループ分けできる。
Displaying the Validation Errors
-
$errors
変数は、Illuminate\View\Middleware\ShareErrorsFromSession
ミドルウェアによって、アプリケーションの全てのビューと共有される。従って、このミドルウェアを適用させれば、自由に使えるということですね。 -
$errors
変数は、Illuminate\Support\MessageBag
のインスタンス。
<!-- /resources/views/post/create.blade.php -->
<h1>Create Post</h1>
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<!-- Create Post Form -->
The @error
Directive
- bladeのディレクティブ。
- 個別の attribute の validation error message が存在するか確認する。
- このディレクティブ内で、
$message
変数を書くことで、個別のエラーメッセージを出せる。
<!-- /resources/views/post/create.blade.php -->
<label for="title">Post Title</label>
<input id="title"
type="text"
name="title"
class="@error('title') is-invalid @enderror">
@error('title')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
<input ... class="@error('title', 'post') is-invalid @enderror">
- named error bag を使っている時は、第二引数で指定してあげる。
Repopulating Forms
- 検証エラーのためにリダイレクトレスポンスを生成すると、リクエストの入力値全てをセッションにフラッシュする。
- これは、次のリクエスト中に入力に簡単にアクセスしやすくするため。
- 従って、ユーザーが送信しようとしたフォームを再入力できるようになる。
$title = $request->old('title');
- 以前のリクエストからフラッシュされた入力値を取得する。
<input type="text" name="title" value="{{ old('title') }}">
-
old
ヘルパーが提供されているので、bladeではそれを使ってアクセスする。わざわざコントローラーで詰め込みみたいなのは、不要。 - 入力がない場合は、
null
が返されるので安心。
<input type="text" name="age" value="{{ old("name", "田中") }}">
- フォームのeditの時に、初期値を設定したい時に使う。
old()
ヘルパーの第二引数が初期値になる。- 参考記事
3つある
-
Validator
ファサードを使う方法 -
Request
クラスのvalidate()
メソッドを使う方法 -
FormRequest
クラスを使う方法
優先はFormRequest
クラスを使う方法。Fat Controllerを避けるのがベストプラクティス
継承した子クラスを作って実装していく。
php artisan make:request [任意のクラス名]
authorized
は認可。rule
がルール。
public function rules(): array
{
return [
'name' => 'required|max:20',
'tel' => 'nullable|regex:/^[0-9]{2,4}-[0-9]{2,4}-[0-9]{3,4}$/|regex:/^0\d{9,10}$/',
'body' => 'required|max:1000',
'email' => ['required', 'email:filter,dns', 'confirmed'],
'email_confirmation' => 'メールアドレス確認',
];
}
このバリデーションが通らなければ、直前の画面に302リダイレクトされる
コントローラーに依存性の注入。
use App\Http\Requests\InquiryRequest;
public function post(InquiryRequest $request)
{
// ここを通る時点で認可&バリデーションが通っている
}
バリデーションの最初の失敗で停止させる
/**
* 最初のルールの失敗でバリデーションが停止する。
* @var bool
*/
protected $stopOnFirstFailure = true;
リダイレクト先を変更する
通常、フォームをPostリクエストされた際、エラーが発生すると、リクエスト元のフォームがあったページへリダイレクトされる。
/**
* バリデーション失敗時に、/dashboardにリダイレクトさせる場合
* @var string
*/
protected $redirect = '/dashboard';
/**
* 名前付きルートで指定したい場合
*/
protected $redirectRoute = 'dashboard';
バリデーション前に処理を行う
protected function prepareForValidation()
{
// 入力データ取得 (例 03-1111ー2222
$tel = $this->input('tel');
// ハイフンに似た文字を半角ハイフンに変換(この処理はちゃんとやるともっと複雑)
$tel = str_replace(['-', '―', '‐', 'ー'], '-', $tel);
// 半角数字を全角数字に変換:結果→03-1111-2222
$tel = mb_convert_kana($tel, 'n');
// 変換後のtelをリクエストデータにセット
$this->merge(['tel' => $tel]);
}
追加バリデーションの実行(カスタムバリデーションのこと)
withValidator()
メソッドが用意されています。このメソッド内で$validator->after()
フックメソッドを定義することで、追加バリデーション機能を実現可能。
use Illuminate\Validation\Validator;
public function withValidator(Validator $validator): void
{
$validator->after(function (Validator $validator) {
if ($this->input('email') === 'admin@example.com') {
$validator->errors()->add('email', 'このメールアドレスは使用できません。');
}
});
}
バリデーション成功時に処理を行う
passedValidation()
メソッドの中で行うことで、コントローラのアクションに到達する前にデータを加工することができる。
protected function passedValidation()
{
// 'price' の値を整数として扱いたい場合
$this->merge([
'price' => intval($this->price)
]);
}
バリデーション失敗時に処理を行う
failedValidation()
メソッドをオーバーライドすることで、バリデーション失敗時に処理を行うことが可能.
ここでは15行目で独自のレスポンスを返していますが、そうしない場合は必ず、親クラスの同メソッドを呼ぶのを忘れない
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;
class CustomRequest extends FormRequest
{
// ~略~
protected function failedValidation(Validator $validator)
{
$response = [
'status' => 422,
'message' => 'Validation failed!',
'errors' => $validator->errors()
];
throw new HttpResponseException(response()->json($response, 422));
// parent::failedValidation($validator);
}
エラーメッセージのカスタマイズ
Laravelのインストール直後では、バリデーションエラーが英語で表示されます。そのため、日本語でのWebアプリケーションの場合、日本語化することが必須に。
-
Laravelの言語ファイルを作成&設定する
https://laranote.jp/laravel-language-file-validation-error-localization/
-
FormRequest
の子クラスで定義するここで定義する日本語のエラーメッセージは、Laravelの言語ファイルよりも優先される。そのクラスでのみ使いたいエラー表示には適している。
public function messages() { return [ 'title.required' => 'タイトルは必須です。', 'body.min' => '本文は最低10文字必要です。', ]; }
messages()
メソッドにプレースホルダー(:attribute
)を用意し、attribute()
メソッドで置き換える方法もある。public function messages() { return [ 'title.required' => ':attribute は必須です。', 'body.min' => ':attribute は最低 :min 文字必要です。', ]; } public function attributes() { return [ 'title' => 'タイトル', 'body' => '本文', ]; }
https://laranote.jp/laravel-formrequest-validation-error-localization/
カスタムバリデーション
コントローラー内に記述(Fat Controller の原因になるため非推奨)
直接的でシンプル。
特定のアクションや特定のコントローラでのみ使用するような一時的なバリデーションルールに適しています。
Form Requestクラスで記述
再利用性が高く、バリデーションルールと関連するロジックを1つのクラス内に集約できる。
コントローラがスリムに保たれ、テストも容易になります
public function rules()
{
return [
'field' => [
'required',
function ($attribute, $value, $fail) {
if (mb_strtoupper($value) !== $value) {
$fail('大文字である必要があります');
}
},
],
];
}
Service Provider内で定義
アプリケーション全体で使用できるカスタムバリデーションルールを定義するのに適している。
再利用性が高い。
public function boot()
{
Validator::extend('uppercase', function ($attribute, $value, $parameters, $validator) {
return mb_strtoupper($value) === $value;
});
Validator::replacer('uppercase', function ($message, $attribute, $rule, $parameters) {
return $attribute.' must be uppercase.';
});
}
$request->validate([
'field1' => 'required|uppercase',
'field2' => 'required|uppercase',
]);
bootメソッドは、Laravelのサービスプロバイダ内で使用され、サービスコンテナのバインディングや、他の起動時の処理を実行するための場所として提供されている。
Validator::extend: extendメソッドを使って新しいバリデーションルールを定義。
uppercase: 新しいバリデーションルールの名前を付ける。
無名関数: バリデーションのロジックを定義するコールバック関数。値がすべて大文字である場合にtrueを返う。
Validator::replacer: replacerメソッドを用いて、特定のバリデーションルールに関連するエラーメッセージのフォーマットを定義します。
2つのフィールドに対して同時にバリデーションを掛ける
// app/Providers/AppServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Validator;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Validator::extend('name_fields_required', function ($attribute, $value, $parameters, $validator) {
$data = $validator->getData();
$firstName = $data['first_name'] ?? '';
$lastName = $data['last_name'] ?? '';
// どちらも空、またはどちらかが空である場合、バリデーションエラー
return !empty($firstName) && !empty($lastName);
}, 'The first name and last name fields are required.');
}
}
// app/Http/Requests/YourFormRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class YourFormRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'first_name' => 'required_with:last_name|name_fields_required',
'last_name' => 'required_with:first_name|name_fields_required',
];
}
}
専用のバリデーションルールクラス(これ一番良さそう)
$ php artisan make:rule Uppercase
// Uppercase.php これ非推奨
public function passes($attribute, $value)
{
return mb_strtoupper($value) === $value;
}
public function message()
{
return ':attribute は大文字である必要があります';
}
// Upparcase.php 推奨 こっちが作られる
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
class Uppercase implements ValidationRule
{
/**
* Run the validation rule.
*/
// $attribute 属性名、$value 値、$fail 失敗時のメッセージ
public function validate(string $attribute, mixed $value, Closure $fail): void
{
// このコードは、値を大文字にした結果と一致するかどうかを検証している
// 一致しない場合は、:attribute(属性名)が大文字であるというエラーメッセージをセットで返す。
if (strtoupper($value) !== $value) {
$fail('The :attribute must be uppercase.');
}
}
}
// RequestやControllerでの使い方
$request->validate([
'field' => ['required', new Uppercase],
]);
passesメソッドは、属性の値がルールを満たすかどうかを判定します。
この例では、値がすべて大文字であるかをチェックしています。
すべて大文字であればtrueを、そうでなければfalseを返します。
messageメソッドは、バリデーションルールが失敗したときに表示するエラーメッセージを返します。
:attributeプレースホルダは、バリデーションを実行する際の属性名に置き換えられます。
2つのフィールドに対して同時にバリデーションを掛ける
$ php artisan make:rule DualField
# app/Rules/NamesRequired.php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class NamesRequired implements Rule
{
private $otherValue;
public function __construct($otherValue)
{
$this->otherValue = $otherValue;
}
public function passes($attribute, $value)
{
// どちらのフィールドも空ではないことを確認
return !empty($value) && !empty($this->otherValue);
}
public function message()
{
return 'Both first name and last name are required.';
}
}
use App\Rules\NamesRequired;
public function rules()
{
return [
'first_name' => ['nullable', 'string', new NamesRequired(request('lastname'))],
'last_name' => ['nullable', 'string', new NamesRequired(request('firstname'))],
];
}
バリデーション失敗後のデータの復元
<input type="text" name="title" id="title" value="{{ old('title', 'default value') }}">
<select name="gender">
<option value="man" {{ old('gender', 'man') == 'man' ? 'selected' : '' }}>Man </option>
<option value="woman" {{ old('gender', 'man') == 'woman' ? 'selected' : '' }}>Woman</option>
</select>
<input type="checkbox" name="subscribe" value="1" {{ old('subscribe', '1') == '1' ? 'checked' : '' }}>
バリデーション成功後のデータの取得
全部のデータ
FormRequest
のvalidated
メソッドでバリデーション済みデータを取得可能。
$validated
は配列で返される。
public function post(InquiryRequest $request)
{
// ここを通る時点で認可&バリデーションが通っている
// バリデーション済みデータの取得
$validated = $request->validated();
dd($validated);
一部のデータ
$request->safe()
メソッドが返すIlluminate\Support\ValidatedInput
オブジェクトが持つonly()
やexcept()
メソッドを使う。
public function post(InquiryRequest $request)
{
// ここを通る時点で認可&バリデーションが通っている
// バリデーション済みの'name'と'email’のみ取得
$validated = $request->safe()->only(['name', 'email']);
// バリデーション済みの'name'と'email’以外を取得
$validated = $request->safe()->except(['name', 'email']);
prepare For Validation()で加工したデータをold()で表示させたい
バリデーションエラーをview(Blade)で表示させる
https://laranote.jp/laravel-blade-validation-error-display-methods/#toc1
@if ($errors->any())
<div class="error">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
@if ($errors->has('email'))
<div class="error">{{ $errors->first('email') }}</div>
@endif
// or
@error('name')
<div class="error">{{ $message }}</div>
@enderror
$messageは、@errorディレクティブを使用した際使える変数。直前に利用した名称のエラーを$messageに自動的に入れてくれるため、これでエラーが表示できる。
php artisan make:component ErrorMessage
<x-error-message for="name" />
# resources/views/components/error-message.blade.php
@props(['for'])
@error($for)
<span class="error">{{ $message }}</span>
@enderror
@props
ディレクティブを使用してfor
という名前の属性を受け取る。このfor
属性は、バリデーションエラーをチェックするフォーム項目名を示している。
Views
Introduction
Creating and Rendering Views
php artisan make:view greeting
-
blade.php
拡張子を持つファイルを、resources/view/
に作成してくれる。
Route::get('/', function () {
return view('greeting', ['name' => 'James']);
});
-
view()
ヘルパーでviewを作成。
use Illuminate\Support\Facades\View;
return View::make('greeting', ['name' => 'James']);
-
View
ファサードでviewを作成。
Nested View Directories
return view('admin.profile', $data);
Passing Data to Views
return view('greetings', ['name' => 'Victoria']);
- 普通に渡す。
return view('greeting')
->with('name', 'Victoria')
->with('occupation', 'Astronaut');
- こんなんでも渡せる。
- いつ使うのかな、、、?
Sharing Data With All Views
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// ...
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
View::share('key', 'value');
}
}
- 全てのViewに共有させたい場合に使う。
-
AppServiceProvider
クラスに実装してもいいし、切り出しても良い。
Optimizing Views
Viewを返すリクエストが実行された場合に、必要に応じてViewはコンパイルされる。
- コンパイル済みViewがある場合はそれを返す。
- 無ければ再コンパイルして返す。
- 更新されている場合も再コンパイルして返す。
毎回上記のようにリクエストの度に再コンパイルが実行されるとパフォーマンスに悪影響が出る。そのため、開発時でもコンパイルしてからリクエストを実行できる
$ php artisan view:cache
- パフォーマンス向上のためにキャッシュさせることができる。
$ php artisan view:clear
- View Cacheをクリアする。
開発環境について
どこの環境でやっているかによってもろもろのコマンドが異なる。
local
そのままコマンドを叩けば良い
sail(docker)
それぞれのコマンドの前に sail
をつけないといけない。
コンテナ内なのかローカルなのかの意識を持っておかないとここらへんで混乱してくる。コンテナ内での開発なら当然コンテナ内にインストールやらアップデートやらをしないといけないよね。sailコマンドはdockerをラップしているわけだから、sailコマンドを叩くということは、内部的にdockerコマンドを叩いていることになるよね。
development server
バックエンド用の開発サーバーとフロントエンド用の開発サーバーがそれぞれある
基本的には連携して使うことが多いから、両方立ち上げることが多いが、どっちかだけという場合もある。
sail up -d
やphp artisan serve
なんかがバックエンド用の開発サーバーの起動コマンド
npm run dev
がフロントエンド用の開発サーバーの起動コマンド
start project
プロジェクトの作成
sailで作成する
# 最新バージョンでプロジェクト作成
curl -s https://laravel.build/プロジェクト名 | bash
※ バージョンを指定したい場合はcomposerで作成する
composerで作成する
# バージョンを指定してプロジェクト作成
composer create-project laravel/laravel プロジェクト名 --prefer-dist "10.*"
cd プロジェクト名
composer require laravel/sail --dev
php artisan sail:install
sail up -d
以下のようなエラーが出る時があるが、composerのバージョンを最新にしてあげると解決する場合が多い
The "https://repo.packagist.org/p2/carbonphp/carbon-doctrine-types~dev.json" file could not be downloaded: Failed to open stream: Network is unreachable
開発環境の起動
$ sail up -d
> .bashrcにエイリアスを貼ってある。なければ ./vendor/bin/sail up
開発環境の終了
$ sail stop
DBへの接続
$ sail mysql -u sail -ppassword
$ sail mysql <dbName>
APIを作ってみる
$ php artisan make:model Product -mfs --api
INFO Model [app/Models/Product.php] created successfully.
INFO Factory [database/factories/ProductFactory.php] created successfully.
INFO Migration [database/migrations/2024_01_11_010607_create_products_table.php] created successfully.
INFO Seeder [database/seeders/ProductSeeder.php] created successfully.
INFO Controller [app/Http/Controllers/ProductController.php] created successfully.
-m
:マイグレーションファイル作成
-f
:ファクトリ作成
-s
:シーダー作成
--api
:APIのCRUD用のコントローラー作成
マイグレーションファイルの定義
#database/migrations/2024_01_11_010607_create_products_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('text'); //追加
$table->longText('description'); //追加
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('products');
}
};
モデルの定義
#app/Models/Product.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasFactory;
//以下4行追加
protected $fillable = [
'title',
'description',
];
}
ファクトリの定義
# database/factories/ProductFactory.php
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Product>
*/
class ProductFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'title' => $this->faker->title(), //追加
'description' => $this->faker->text(), //追加
];
}
}
シーダー定義
#database/seeders/ProductSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\Product; //追加
class ProductSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
Product::factory()->count(3)->create(); //追加
}
}
#database/seeders/DatabaseSeeder.php
<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
//以下3行追加
$this->call([
ProductSeeder::class,
]);
}
}
マイグレートとシーディング
$ php artisan migrate --seed
tinkerで確認
$ sail tinker
> \App\Models\Product::all()
= Illuminate\Database\Eloquent\Collection {#5699
all: [
App\Models\Product {#5956
id: 1,
title: "Mr.",
description: "Nulla sit facilis cumque et. Omnis non eligendi suscipit. Occaecati voluptatem quo porro occaecati. Qui sed est officiis ut nihil architecto.",
created_at: "2024-01-11 02:10:37",
updated_at: "2024-01-11 02:10:37",
},
App\Models\Product {#5957
id: 2,
title: "Dr.",
description: "Explicabo omnis perferendis repudiandae repudiandae. Fuga pariatur saepe cupiditate dolor.",
created_at: "2024-01-11 02:10:37",
updated_at: "2024-01-11 02:10:37",
},
App\Models\Product {#5958
id: 3,
title: "Dr.",
description: "Aut voluptate id officiis ea dolores. Cumque nihil totam maiores. Et odit placeat itaque ut est impedit. Nisi quo ab inventore nemo vel.",
created_at: "2024-01-11 02:10:37",
updated_at: "2024-01-11 02:10:37",
},
],
}
データの取得
controllerの定義
#app/Http/Controllers/ProductController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Product; //追加
class ProductController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
//以下4行追加
$products = Product::all();
return response()->json([
'products' => $products,
], 200);
}
...省略...
routesの定義
#routes/api.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController; //追加
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "api" middleware group. Make something great!
|
*/
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Route::apiResource('products', ProductController::class); //追加
postmanで確認
データの登録
requestの定義
$ sail php artisan make:request StoreProductRequest
# app/Http/Requests/StoreProductRequest.php
<?php
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException; //追加
class StoreProductRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true; //修正
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'title' => ['required', 'string'], //追加
'description' => ['required', 'string'], //追加
];
}
//以下追加
protected function failedValidation(Validator $validator)
{
$res = response()->json([
'message' => 'Failed create product',
'errors' => $validator->errors(),
], 400);
throw new HttpResponseException($res);
}
}
controllerの定義
# app/Http/Controllers/ProductController.php
...省略...
use App\Http\Requests\StoreProductRequest; //追加
class ProductController extends Controller
{
...省略...
public function store(StoreProductRequest $request) //修正
{
//以下5行追加
$product = Product::create($request->all());
return response()->json([
'message' => 'Product created successfully!',
'product' => $product,
], 200);
}
...省略...
postmanで確認
-
jsonオブジェクト無のボディでpostリクエストする
-
jsonオブジェクト有のボディでpostリクエストする
$ sail php artisan
> \App\Models\Product::all()
= Illuminate\Database\Eloquent\Collection {#5960
all: [
...省略...
App\Models\Product {#5965
id: 4,
title: "input title",
description: "input description",
created_at: "2024-01-11 02:51:08",
updated_at: "2024-01-11 02:51:08",
},
],
}
sanctum
laravelでapiを作成する時に使うもの
Formを作ってみる
確認画面をどう作るか
sessionを使う
大きな流れは
- フォームからの遷移先でセッションに入力値を保存
- 確認画面の表示はセッションの入力値を使う
- 確認画面からの遷移先もセッションの入力値を使う
- 送信処理(確認画面からの遷移先)で二重投稿にならないようにセッションの値を空にする
show→post(sessionに入力値を保存)→confirm(sessionから入力値を取り出す)→send(sessionから入力値を取り出して送信、sessionの入力値を削除)→complete
DBを使う
- 入力データをデータベースに一時保存し、確認画面でそのデータを参照する。最終的に送信する際に、データベースから情報を取得して処理を行う。
- この方法はデータが大量である場合や、複数ステップにわたるフォーム処理に適している。
inputの値を受け継いでいく
- こっちを基本的に使う
- sessionを上手く使っていく
File Upload
基本のコード
public function store(Request $request)
{
...
if ($request->file('image')) {
$imageName = $request->file('image')->store('public/upload');
$formData['image'] = $imageName;
}
Ramen::create($formData);
return to_route('admin.ramen.index');
}
public function store(Request $request)
{
...
// bladeの場合はこっちを使う
if ($request->file('image')) {
$imageName = $request->file('image')->store('public/upload');
$formData['image'] = $imageName;
}
// inertiaの場合はこっちを使う
if ($image = $request->file('image')) {
$imageName = $image->getFilename(). '.'. $image->getClientOriginalExtension();
$image->storeAs('public/upload', $imageName);
$formData['image'] = $imageName;
}
Ramen::create($formData);
return to_route('admin.ramen.index');
}
公開
- Laravelでは画像の参照先は
storage/app/public/
- ただし、そのままではビューで参照することがでない
-
storageディレクトリ
を参照するためにはシンボリックリンクが必要
php artisan storage:link
Inertia の場合は注意。
cd public
ln -s ../storage/public/upload
Deployしてみる
オートローダーの最適化
composer install --optimize-autoloader --no-dev
設定のキャッシュ
php artisan config:cache
ルートのキャッシュ
php artisan route:cache
ビューのキャッシュ
php artisan view:cache
デバッグモード
# .env or config/app.php
APP_DEBUG=false
Conoha Wing
流れ
-
本番環境とリポジトリをSSH接続可能に
-
publicディレクトリ内にルーティングさせる
# / <IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^(.*)$ appName/public/$1 [L] </IfModule>
-
バックエンド
-
composer
cd app-name ~/bin/composer install
-
application encryption key
php artisan key:generate
-
環境変数
cp .env.example .env
-bash-4.2$ diff -uwBb .env.example .env --- .env.example 2024-05-21 09:23:34.117917782 +0900 +++ .env 2024-05-21 09:37:47.499062046 +0900 @@ -1,19 +1,19 @@ -APP_NAME=Laravel -APP_ENV=local +APP_NAME=hoge +APP_ENV=production APP_KEY= -APP_DEBUG=true -APP_URL=http://localhost +APP_DEBUG=false +APP_URL=https://hoge +ASSET_URL=https://hoge LOG_CHANNEL=stack LOG_DEPRECATIONS_CHANNEL=null -LOG_LEVEL=debug +LOG_LEVEL=error DB_CONNECTION=mysql -DB_HOST=127.0.0.1 +DB_HOST=hoge_host DB_PORT=3306 -DB_DATABASE=app_name -DB_USERNAME=root -DB_PASSWORD= +DB_DATABASE=hoge_db +DB_USERNAME=hoge_user +DB_PASSWORD=hoge_pw BROADCAST_DRIVER=log CACHE_DRIVER=file
-
public/.htaccess
--- .old.htaccess 2024-05-22 21:14:32.710679534 +0900 +++ .htaccess 2024-05-22 21:14:55.664738128 +0900 @@ -1,8 +1,4 @@ <IfModule mod_rewrite.c> - <IfModule mod_negotiation.c> - Options -MultiViews -Indexes - </IfModule> - RewriteEngine On # Handle Authorization Header
-
AppServiceProvider
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 452e6b6..03e735c 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +use Illuminate\Support\Facades\URL; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider @@ -19,6 +20,8 @@ public function register(): void */ public function boot(): void { - // + if($this->app->environment('production')) { + URL::forceScheme('https'); + } } }
-
dbのテーブル作成
php artisan migrate
-
-
フロントエンド
-
ローカルでプロダクションビルドしてアップロード
"scripts": { "dev": "vite", "build": "vite build", + "build:prd": "vite build --mode production" },
sail npm run build:prd
-
本番環境でビルドする
-
nodeとnpmをインストールする
-
nodebrewのインストール
ダウンロードする
cd ~/bin wget git.io/nodebrew perl nodebrew setup
パスを通す
vim ~/.bash_profile > #以下に変更もしくは追記 > PATH=$HOME/.nodebrew/current/bin:$PATH:$HOME/.local/bin:$HOME/bin source ~/.bash_profile nodebrew -v
-
node.jsをインストール
nodebrew install-binary v16.20.0 nodebrew ls-remote nodebrew list nodebrew use v16.20.0 node -v npm -v
v20.9.0だと必要パッケージが無くて怒られたので注意。
-
-
Nodeパッケージのインストールとビルド
-
Nodeパッケージのインストール
cd app npm install
-
ビルド
npm run buil
-
-
-