PHP项目Laravel Spark快速搭建SaaS

wen PHP项目 4

本文目录导读:

PHP项目Laravel Spark快速搭建SaaS

  1. 环境准备
  2. 安装 Laravel Spark
  3. 基础配置
  4. 创建 SaaS 核心功能
  5. 前端页面设置
  6. 中间件配置
  7. 管理后台功能
  8. Webhook 处理
  9. 部署建议
  10. 安全建议

我来为您详细介绍如何使用 Laravel Spark 快速搭建 SaaS 项目。

环境准备

系统要求

- PHP >= 8.1
- Laravel >= 10.x
- MySQL >= 5.7 或 PostgreSQL
- Composer
- Node.js & NPM

安装 Laravel

# 创建项目
composer create-project laravel/laravel my-saas
# 进入项目目录
cd my-saas
# 配置环境变量
cp .env.example .env
php artisan key:generate

安装 Laravel Spark

通过 Composer 安装

# 添加 Spark 仓库
composer require laravel/spark
# 发布配置文件
php artisan vendor:publish --tag=spark-config
php artisan vendor:publish --tag=spark-migrations
# 运行迁移
php artisan migrate
# 安装前端资源
npm install
npm run dev

配置 Stripe(支付)

# .env 文件中配置
STRIPE_KEY=your_stripe_key
STRIPE_SECRET=your_stripe_secret
STRIPE_WEBHOOK_SECRET=your_webhook_secret

基础配置

创建 Plan 配置

// config/spark.php
<?php
return [
    'bills' => [
        'stripe' => [
            'plans' => [
                [
                    'name' => 'Basic',
                    'short_reference' => 'basic',
                    'monthly_price' => 9.00,
                    'yearly_price' => 90.00,
                    'features' => [
                        '1 Project',
                        '5GB Storage',
                        'Basic Support'
                    ]
                ],
                [
                    'name' => 'Pro',
                    'short_reference' => 'pro',
                    'monthly_price' => 29.00,
                    'yearly_price' => 290.00,
                    'features' => [
                        'Unlimited Projects',
                        '100GB Storage',
                        'Priority Support',
                        'API Access'
                    ]
                ],
            ],
        ],
    ],
];

配置用户模型

// app/Models/User.php
<?php
namespace App\Models;
use Laravel\Spark\Billable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
    use Billable;
    protected $fillable = [
        'name', 
        'email', 
        'password',
        'trial_ends_at',
    ];
    protected $hidden = [
        'password', 
        'remember_token',
    ];
}

创建 SaaS 核心功能

多租户支持

// app/Traits/TenantTrait.php
<?php
namespace App\Traits;
use Illuminate\Support\Facades\Auth;
trait TenantTrait
{
    protected static function bootTenantTrait()
    {
        static::creating(function ($model) {
            if (Auth::check() && empty($model->user_id)) {
                $model->user_id = Auth::id();
            }
        });
        static::addGlobalScope('user', function ($builder) {
            if (Auth::check()) {
                $builder->where('user_id', Auth::id());
            }
        });
    }
}

订阅管理控制器

// app/Http/Controllers/SubscriptionController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Laravel\Spark\Spark;
class SubscriptionController extends Controller
{
    public function subscribe(Request $request)
    {
        $request->validate([
            'plan' => 'required|string',
            'payment_method' => 'required|string'
        ]);
        try {
            $user = $request->user();
            // 创建订阅
            $subscription = $user->newSubscription(
                $request->plan,
                $request->plan
            )->create($request->payment_method);
            return response()->json([
                'success' => true,
                'subscription' => $subscription
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => $e->getMessage()
            ], 422);
        }
    }
    public function cancel(Request $request)
    {
        $user = $request->user();
        $user->subscription()->cancel();
        return response()->json(['success' => true]);
    }
}

前端页面设置

路由配置

// routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\SubscriptionController;
Route::middleware(['auth'])->group(function () {
    // 仪表盘
    Route::get('/dashboard', function () {
        return view('dashboard');
    })->name('dashboard');
    // 订阅管理
    Route::get('/settings/subscription', function () {
        return view('subscription');
    })->name('subscription');
    Route::post('/subscribe', [SubscriptionController::class, 'subscribe'])->name('subscribe');
    Route::post('/cancel-subscription', [SubscriptionController::class, 'cancel'])->name('cancel-subscription');
});

订阅页面视图

{{-- resources/views/subscription.blade.php --}}
@extends('layouts.app')
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">订阅管理</div>
                <div class="card-body">
                    @if(auth()->user()->subscribed())
                        <div class="alert alert-success">
                            当前订阅: {{ auth()->user()->subscription()->stripe_plan }}
                        </div>
                        <button class="btn btn-danger" onclick="handleCancel()">
                            取消订阅
                        </button>
                    @else
                        <form method="POST" action="{{ route('subscribe') }}" id="subscription-form">
                            @csrf
                            <div class="form-group">
                                <label>选择套餐</label>
                                <select name="plan" class="form-control" required>
                                    <option value="basic">基础版 - $9/月</option>
                                    <option value="pro">专业版 - $29/月</option>
                                </select>
                            </div>
                            <div class="form-group mt-3">
                                <label>支付方式</label>
                                <div id="card-element"></div>
                            </div>
                            <button type="submit" class="btn btn-primary mt-3">
                                立即订阅
                            </button>
                        </form>
                    @endif
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
@push('scripts')
<script>
    const stripe = Stripe('{{ config('services.stripe.key') }}');
    const elements = stripe.elements();
    const card = elements.create('card');
    card.mount('#card-element');
    const form = document.getElementById('subscription-form');
    form.addEventListener('submit', async (event) => {
        event.preventDefault();
        const {token} = await stripe.createToken(card);
        // 添加 token 到表单
        const hiddenInput = document.createElement('input');
        hiddenInput.type = 'hidden';
        hiddenInput.name = 'payment_method';
        hiddenInput.value = token.id;
        form.appendChild(hiddenInput);
        // 提交表单
        form.submit();
    });
</script>
@endpush

中间件配置

订阅检查中间件

// app/Http/Middleware/CheckSubscription.php
<?php
namespace App\Http\Middleware;
use Closure;
class CheckSubscription
{
    public function handle($request, Closure $next)
    {
        if (!$request->user()->subscribed()) {
            return redirect()->route('subscription')
                ->with('error', '请先订阅才能访问此功能');
        }
        return $next($request);
    }
}

管理后台功能

管理员面板

// app/Http/Controllers/Admin/DashboardController.php
<?php
namespace App\Http\Controllers\Admin;
use App\Models\User;
use App\Models\Subscription;
use Illuminate\Http\Request;
class DashboardController extends Controller
{
    public function index()
    {
        $stats = [
            'total_users' => User::count(),
            'active_subscriptions' => Subscription::where('status', 'active')->count(),
            'monthly_revenue' => Subscription::where('status', 'active')->sum('amount'),
        ];
        return view('admin.dashboard', compact('stats'));
    }
}

Webhook 处理

// app/Http/Controllers/WebhookController.php
<?php
namespace App\Http\Controllers;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
class WebhookController extends Controller
{
    public function handleStripeWebhook(Request $request)
    {
        $payload = json_decode($request->getContent(), true);
        // 处理不同事件
        switch ($payload['type']) {
            case 'invoice.payment_succeeded':
                // 更新订阅状态
                break;
            case 'customer.subscription.deleted':
                // 处理订阅取消
                break;
        }
        return response()->json(['received' => true]);
    }
}

部署建议

生产环境优化

# 优化配置
php artisan config:cache
php artisan route:cache
php artisan view:cache
# 使用队列
php artisan queue:work redis
# 定时任务 (crontab)
* * * * * cd /path-to-project && php artisan schedule:run >> /dev/null 2>&1

数据库优化

-- 添加索引
ALTER TABLE subscriptions ADD INDEX idx_user_id (user_id);
ALTER TABLE subscriptions ADD INDEX idx_status (status);

安全建议

  1. API 限流

    // app/Http/Kernel.php
    'api' => [
     'throttle:60,1',
     'bindings',
    ],
  2. 数据加密

    // 加密敏感数据
    $encrypted = encrypt($sensitiveData);
  3. 审计日志

  4. 定期备份

Laravel Spark 提供了完整的 SaaS 解决方案,包括:

  • ✅ 订阅计费系统
  • ✅ 多租户支持
  • ✅ 发票管理
  • ✅ 客户门户
  • ✅ 管理后台

建议根据实际需求调整配置,确保系统安全和性能,如果需要更详细的功能实现,请告诉我具体需求!

抱歉,评论功能暂时关闭!