CartController.php

   public function success(){
        $carts = Cart::where('user_id', auth()->user()->id)->get();
        $user = auth()->user();
        $firstAddress = $user->addresses()->first();

        if (!$firstAddress) {
        // 住所が登録されていない場合の処理
        }

        $order = Order::create([
                'user_id' => $user->id,
                'address_id' =>$firstAddress->id,
            ]);

        $total = 0; // 合計金額
        $orderItems = []; // 注文アイテムの情報を格納する配列

           // カート内のアイテムを処理
        foreach ($carts as $cart) {
            $post = $cart->post;
            $subtotal = $post->price * $cart->quantity;
            $total += $subtotal;

            OrderItem::create([
                'order_id' => $order->id,
                'post_id' => $cart->post_id,
                'quantity' => $cart->quantity,
            ]);

            array_push($orderItems, [
                'title' => $post->title,
                'quantity' => $cart->quantity,
                'price' => $post->price,
                'subtotal' => $subtotal
            ]);
        }

        $order_info = [
            'user' => $user,
            'address' => $firstAddress,
            'orderItems' => $orderItems,
            'total' => $total,
        ];


        // 購入者に「注文内容ご確認」メールを送る
        Mail::to($user->email)->send(new \App\Mail\NewOrder($order_info));
        Mail::to('xxx.com')->send(new \App\Mail\NewOrder($order_info));

        Cart::where('user_id', auth()->user()->id)->delete();

        return redirect()->route('post.index')->with('message',
'支払いが完了しました。');
    }

    public function cancel(){
        $carts = Cart::where('user_id', auth()->user()->id)->get();

        foreach($carts as $cart){
            $post = Post::find($cart->post_id);
            $quantity = $cart->quantity;
            $post->increment('stock', $quantity);
        }
        return redirect()->route('cart.index')->with('message',
'支払いが取り消されました。');;
 
 
 
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Cart extends Model
{
    use HasFactory;
    protected $fillable = [
        'user_id',
        'post_id',
        'quantity',
    ];

    public function post()
    {
        return $this->belongsTo(Post::class, 'post_id');
    }
}
 
 
//cart/index.blade.php
<x-app-layout>
      <x-slot name="header">
        <h2>
            カート
        </h2>
        {{-- @if(session('message'))
            {{session('message')}}
        @endif --}}
        {{-- <x-input-error class="mb-4" :messages="$errors->all()"/> --}}
        <x-validation-errors class="mb-4" :errors="$errors" />
        <x-message :message="session('message')" />
    </x-slot>

  <div class="py-12">
      <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
          <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
              <div class="p-6 bg-white border-b border-gray-200">
                  @if (count($carts) > 0)
                    @foreach ($carts as $cart )
                      <div class="md:flex md:items-center mb-2">
                        <div class="md:w-3/12">
                          @if ($cart->post->image !== null)
                          <img src="{{ asset('storage/images/
'.$cart->post->image)}}">
                          @else
                          <img src="">
                          @endif
                        </div>
                        <div class="md:w-4/12 md:ml-2">
{{ $cart->post->title }}</div>
                        <div class="md:w-3/12 flex justify-around">
                          <div>{{ $cart->quantity }}冊</div>
                          <div>{{ number_format($cart->quantity
* $cart->post->price )}}
<span class="text-sm text-gray-700">円(税込)</span>
</div>
                        </div>
                        <div class="md:w-2/12">
                          <form method="post" action="{{route('cart.delete',
['item' => $cart->post->id ])}}">
                            @csrf
                            <button>
                              <svg xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="w-6 h-6">
                                <path stroke-linecap="round"
stroke-linejoin="round"
                              </svg>
                            </button>
                          </form>
                        </div>
                      </div>
                    @endforeach
                    <div class="my-2">
                      小計: {{ number_format($totalPrice)}}
<span class="text-sm text-gray-700">円(税込)</span>
                    </div>
                    <div>
                      {{-- <button onclick="location.href=
'{{ route('cart.checkout')}}'">購入する
                      </button> --}}
                      <button onclick="checkAddressAndProceed()">購入する
                      </button>

                    </div>
                  @else
                    カートに商品が入っていません。
                  @endif
              </div>
          </div>
      </div>
  </div>
    <script>
        function checkAddressAndProceed() {
            @php
                $user = auth()->user();
                $hasAddress = $user->addresses()->exists();
            @endphp

            @if (!$hasAddress)
                alert('送り先住所をアカウント設定画面で登録
してからご注文ください。');
                window.location.href = "{{ route('profile.edit') }}";
            @else
                window.location.href = "{{ route('cart.checkout') }}";
            @endif
        }
    </script>
</x-app-layout>
 
 

known_hostsファイル、known_hosts.oldファイル

 .sshフォルダにあるknown_hostsファイルは、SSH(Secure Shell)を使用してリモートサーバーに接続する際に使用されるファイル。具体的には、あなたがSSHで接続したことのあるサーバーの公開鍵が記録される。これにより、再度同じサーバーに接続する際に、そのサーバーが前回と同じであることを確認できる。

 known_hostsファイルは、SSHを使用してサーバーに初めて接続した際に自動的に作成される。

StripeのCheckout機能を利用する

【大まかな手順】

バックエンドでセッションを作る。

フロントエンド側に渡す。

Stripeチェックアウト


【実際の手順】
◯Stripe側

設定⇒CheckoutとPayment Links

商品の管理

商品の追加

◯Laravel側
ライブラリの登録
composer require stripe/stripe-php

◯Stripe側
開発者

APIキー
 公開可能キー
 シークレットキー

◯Laravel側
.envファイルへ登録

config/services.phpへ下記コード貼り付け
'stripe' => [
 'pb_key'=>env('STRIPE_PUBLIC'),
 'st_key'=>env('STRIPE_SECRET'),
 ],

web.php
use App\Http\Controllers\StripeController;
// 省略
// Route::get('/dashboard', function () {
// return view('dashboard');
// })->middleware(['auth', 'verified'])->name('dashboard');
Route::get('/dashboard', [StripeController::class, 'start'])->name('dashboard');
Route::get('/success/{id}', [StripeController::class, 'success'])->name('success');
Route::get('/cancel', [StripeController::class, 'cancel'])->name('cancel');

resources/views/dashboard.blade.php
{{-- {{ __("You're logged in!") }} --}}
<script src="https://js.stripe.com/v3/"></script>
<button id="checkout-button" class="text-white text-xl font-semibold bg-blue-700
hover:bg-blue-800 focus:outline-none focus:ring-4 focus:ring-blue-300 font-medium rounded-full
text-sm px-5 py-2.5 text-center mr-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700
dark:focus:ring-blue-800">購入ボタン</button>
<div id="error-message"></div>
<script>
 var stripe = Stripe("{{config('services.stripe.pb_key')}}");
 var checkoutButton = document.getElementById('checkout-button');
 var displayError = document.getElementById('error-message');
 checkoutButton.addEventListener('click', function() {
 stripe.redirectToCheckout({sessionId: "{{ $session->id }}"})
 .then(function (result) {
 if (result.error) {
 console.log(result.error);
 }
 });
 });
</script>
①パブリックキー取得
②コントローラー側からセッションIDを取得

app/Http/Controllers/StripeController.php

public function start() {
 $stripe = new \Stripe\StripeClient(config('services.stripe.st_key'));
 $url = 'http://127.0.0.1:8000';
 $id = auth()->user()->id;
 $session = $stripe->checkout->sessions->create([
 'payment_method_types' => ['card'],
 'line_items' => [[
 'price' => '商品キー情報',
 'quantity' => 1,
 ]],
 'mode' => 'payment',
 'success_url' => $url.'/success/'.$id,
 'cancel_url' => $url.'/cancel',
 ]);
 return view('dashboard', ['session' => $session]);
 }

php artisan make:migration add_role --table=users
public function up(): void
 {
 Schema::table('users', function (Blueprint $table) {
 $table->string('role')->default('user')->after('email');
 });
 }
 public function down(): void
 {
 Schema::table('users', function (Blueprint $table) {
 $table->dropColumn('role');
 });
 }

php artisan migrate

app/Http/Controllers/StripeController.php
use App\Models\User;
class StripeController extends Controller
{
// 省略

 public function success(Request $request, $id) {
 $user=User::find($id);
 $user->role = 'premium';
 $user->save();

 return redirect()->route('dashboard')->with('message', 'メッセージ');
 } 

app/Http/Controllers/StripeController.php
public function cancel() {
 return redirect()->route('dashboard')->with('message', 'お支払いがキャンセル');
 }

resources/views/dashboard.blade.php
 @if(session('message'))
 <div class="border px-4 py-3 mt-2 rounded relative bg-green-100 text-green-700">
 {{session('message')}}
 </div>
 @endif

役割によってページや動作に制限をかける方法
Gate:ユーザー一覧ページを非表示
app/Providers/AuthServiceProvider.php
use Illuminate\Support\Facades\Gate;

public function boot()
{
    Gate::define('admin', function ($user) {
        foreach ($user->roles as $role) {
            if ($role->name == 'premium') {
                return true;
            }
        }
        return false;
    });
}

resources/views/layouts/navigation.blade.php
@can('admin')
省略
@endcan


Middleware:操作不可能
web.php
Route::middleware(['can:Gateの名前, (引数)'])->group(function(){

     ルート設定;

});

例)
Route::middleware(['auth', 'can:admin'])->group(function () {
    Route::get('profile/index', [ProfileController::class, 'index'])->name('profile.index');
});

ドロップダウンが表示されない

どのタイミングからかは分からないが右上のユーザー名(ブラウザを狭めた時のハンバーガーメニュー)を押してもドロップダウンが表示されなくなり、ログアウトができなくなった。 心当たりは全くないがSwiper.jsを導入したあたりからそうなった。

チャットGPTによる返答(↓)

Swiper.jsとAlpine.jsの併用によって発生する問題は、JavaScriptのイベントハンドリングやDOMの操作において、互いに干渉することが考えられます。こうした場合、特にAlpine.jsで実装されたドロップダウンが正常に動作しなくなる原因として、以下の点をチェックすると良いでしょう。

  1. JavaScriptのエラーの確認

    • ブラウザの開発者ツールのコンソールタブを開き、エラーメッセージが出ていないか確認してください。エラーメッセージがあれば、それが何を指しているのか特定する手がかりになります。
  2. Alpine.jsの初期化タイミング

    • Swiper.jsとAlpine.jsがどの順番でロードおよび初期化されているかを確認してください。Alpine.jsがSwiper.jsより先に初期化されていると、SwiperによるDOMの改変がAlpine.jsの挙動に影響を与える可能性があります。
  3. コンポーネントの隔離

    • Swiper.jsのスライドがAlpine.jsのドロップダウンコンポーネントの中で使用されていないか、あるいはその逆のケースがないかを確認してください。互いのコンポーネントが干渉しないように、必要に応じてHTML構造を見直しましょう。
  4. js/app.jsの内容確認

    • js/app.js ファイルの中身を確認して、Alpine.jsの初期化コードや、どのようにSwiper.jsが設定されているかを確認してください。また、他のJavaScriptライブラリとのコンフリクトがないかも確認しましょう。

CSSが適用されない!

Laravel Mixのビルドプロセスの実行

npm run dev

npm run prod


Laravelのストレージリンクを確認

php artisan storage:link


webpack.mix.js ファイルを確認

npm install tailwindcss autoprefixer --save-dev


const mix = require('laravel-mix');
require('dotenv').config();

// PostCSSプラグインのインポート
const tailwindcss = require('tailwindcss');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel applications. By default, we are compiling the CSS
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/js/app.js', 'public/js')
   .postCss('resources/css/app.css', 'public/css', [
      tailwindcss, // Tailwind CSSを指定
      require('autoprefixer'), // ベンダープレフィックスの自動追加
   ]);