0
0

僕なりの Laravel のTips

Posted at

プロジェクト作成

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をdailychannelにする

サービスの追加

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してみる

10.x デプロイ Laravel

オートローダーの最適化

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

流れ

  1. 本番環境とリポジトリをSSH接続可能に

  2. publicディレクトリ内にルーティングさせる

    # /
    
    <IfModule mod_rewrite.c>
    	RewriteEngine On
        RewriteRule ^(.*)$ appName/public/$1 [L]
    </IfModule>
    
  3. バックエンド

    1. composer

      cd app-name
      ~/bin/composer install
      
    2. application encryption key

      php artisan key:generate
      
    3. 環境変数

      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
      
    4. 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
      
    5. AppServiceProvider

      Laracasts

      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');
      +        }
           }
       }
      
    6. dbのテーブル作成

      php artisan migrate
      
  4. フロントエンド

    • ローカルでプロダクションビルドしてアップロード

          "scripts": {
              "dev": "vite",
              "build": "vite build",
      +       "build:prd": "vite build --mode production"
          },
      
      sail npm run build:prd
      
    • 本番環境でビルドする

      • nodeとnpmをインストールする

        【ConoHa WING】Laravelアプリを公開 | チグサウェブ

        • 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
          

さくらのレンタルサーバー

さくらのレンタルサーバでLaravelを動かす方法 | さくらのナレッジ

流れ

  1. 本番環境とリポジトリをSSH接続可能に

  2. publicディレクトリ内にルーティングさせる

    # /
    
    <IfModule mod_rewrite.c>
    	RewriteEngine On
        RewriteRule ^(.*)$ appName/public/$1 [L]
    </IfModule>
    
  3. バックエンド

    1. composer

      cd app-name
      ~/bin/composer install
      
    2. 環境変数

      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
      
    3. application encryption key

      php artisan key:generate
      
    4. dbのテーブル作成

      php artisan migrate
      
    5. セキュリティ

      <Files .env>
       deny from all
      </Files>
      
    6. AppServiceProvider

      https://laracasts.com/discuss/channels/vite/laravel-vite-assets-blockedmixed-content-issues-in-production-environment

      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
          '
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0