プロジェクト作成
sailで作成する(最新バージョンで作成される)
curl -s https://laravel.build/プロジェクト名 | bash
composerで作成する(バージョン指定するならこっち)
composer create-project laravel/laravel プロジェクト名 --prefer-dist "^10.0"
cd プロジェクト名
composer require laravel/sail --dev
php artisan sail:install
sail up -d
バージョン9とBreezeは一緒に使わない。レイアウトがバグる。
以下のようなエラーが出る時があるが、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
開発環境の起動
./vendor/bin/sail up
# or
sail up -d
.bashrc
にエイリアスを貼ってあげると便利
開発環境の終了
$ sail stop
データベースへの接続
$ sail mysql -u sail -ppassword
$ sail mysql <dbName>
PHPMyAdmin コンテナの追加
phpmyadmin:
image: phpmyadmin/phpmyadmin
depends_on:
- mysql
ports:
- 8888:80
environment:
PMA_USER: '${DB_USERNAME}'
PMA_PASSWORD: '${DB_PASSWORD}'
PMA_HOST: mysql
networks:
- sail
初期設定
言語を日本語に
logをdaily
channelにする
サービスの追加
php artisan sail:add
php artisan sail:add mailpit
Mailpit コンテナの追加
mailpit:
image: 'axllent/mailpit:latest'
ports:
- '${FORWARD_MAILPIT_PORT:-1025}:1025'
- '${FORWARD_MAILPIT_DASHBOARD_PORT:-8025}:8025'
networks:
- sail
デバックバーのインストール
composer require barryvdh/laravel-debugbar
// .envで切り替えできる
APP_DEBUG=true
ページネーション
次のページへのリンクを整形する
php artisan vendor:publish --tag=laravel
コード整形
Code Sniffer の導入
composer require "squizlabs/php_codesniffer=*"
独自の phpcs.xml
を作成
./vendor/bin/phpcs --standard=phpcs.xml ./
./vendor/bin/phpcbf --standard=phpcs.xml ./
compser.json
のscriptとして登録する
"post-create-project-cmd": [
"@php artisan key:generate --ansi"
+ ],
+ "phpcs": [
+ "./vendor/bin/phpcs --standard=phpcs.xml ./"
+ ],
+ "phpcbf": [
+ "./vendor/bin/phpcbf --standard=phpcs.xml ./"
Husky の導入
npm install --save-dev husky
npx husky init
huskyのpre-commit.sh
に登録する
+./vendor/bin/sail composer phpcbf
./vendor/bin/sail test
Breeze(Inertia)の導入
composer require laravel/breeze --dev
php artisan breeze:install
php artisan migrate
npm install
npm run dev
モデルと他全てを一気に自動生成
php artisan make:model -a
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
-
-
-
さくらのレンタルサーバー
流れ
-
本番環境とリポジトリをSSH接続可能に
-
publicディレクトリ内にルーティングさせる
# / <IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^(.*)$ appName/public/$1 [L] </IfModule>
-
バックエンド
-
composer
cd app-name ~/bin/composer install
-
環境変数
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=mysql○○.<ユーザー名>.sakura.ne.jp 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
-
application encryption key
php artisan key:generate
-
dbのテーブル作成
php artisan migrate
-
セキュリティ
<Files .env> deny from all </Files>
-
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'); + } } }
-
さくらのレンタルサーバー改めて
-
リポジトリをtarしてデプロイ
-
ローカルでリモートリポジトリをベアリポジトリとしてクローンする。それを本番環境の/git以下に任意の名前でデプロイ
-
公開鯖上で鍵ペアを作って、秘密鍵をgithubアクションのsecretsに登録する
-
viteの設定を変える
base: process.env.APP_ENV === 'production' ? '/build/' : '/',
-
CD用のスクリプトを作成する
name: Deploy to Production
on:
push:
branches:
- master
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: setting .ssh
run: |
mkdir -p ~/.ssh
touch ~/.ssh/id_ecdsa.pem
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ecdsa.pem
chmod 600 ~/.ssh/id_ecdsa.pem
touch ~/.ssh/config
cat <<EOF > ~/.ssh/config
Host hoge-blog.sakura.ne.jp
HostName www1841.sakura.ne.jp
Port 22
User hoge-blog
IdentityFile /home/runner/.ssh/id_ecdsa.pem
StrictHostKeyChecking no
UserKnownHostsFile=/dev/null
EOF
- name: checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: master push to production repository
run: |
branch=$(git rev-parse --abbrev-ref HEAD)
echo "BRANCH=${branch}" >> $GITHUB_OUTPUT
git remote add production ssh://hoge-blog.sakura.ne.jp/~/git/production-repository-for-moga.git
git remote -v
git push -f production ${branch}
id: set-current-branch
- name: fetch and pull on server
run: |
ssh -tt hoge-blog.sakura.ne.jp '\
cd ~/www/moga &&\
git fetch -p origin &&\
git checkout origin/${{ steps.set-current-branch.outputs.BRANCH }} &&\
exit
'