KalimeroMK/Slim4MVC
GitHub: KalimeroMK/Slim4MVC
一个基于Slim 4框架的生产级MVC启动套件,集成Eloquent ORM、Blade模板、JWT认证和模块化架构,用于快速构建现代Web应用和API服务。
Stars: 3 | Forks: 0
# Slim 4 MVC 启动套件
一个现代化、可用于生产环境的启动套件,用于使用 Slim Framework 4 构建 Web 应用程序,集成了 Eloquent ORM、Blade 模板引擎、全面的身份验证系统以及强大的测试套件。
## 🚀 功能特性
- **MVC 架构** - 使用 Slim 4 实现清晰的关注点分离
- **Eloquent ORM** - Laravel 强大的数据库工具包
- **Blade 模板** - 轻量级的 BladeOne 引擎,带有自定义指令 (@auth, @guest, @csrf, @method, @can, @role)
- **身份验证系统** - 基于 JWT 的 API 认证和基于 Session 的 Web 认证
- **授权系统** - 基于角色和权限的访问控制,包含 middleware 和 policy
- **表单请求验证** - Laravel 风格的验证,带有自动错误处理
- **速率限制** - 内置防御暴力破解攻击的保护
- **CORS 支持** - 可配置的 CORS middleware,用于 API 端点
- **错误日志** - 兼容 PSR-3 的日志记录,使用 Monolog
- **API 资源** - 使用 Resource 类实现一致的 API 响应格式化
- **一致的 API 响应** - 使用枚举和辅助方法实现标准化的 JSON 响应
- **仓储模式 (Repository Pattern)** - 清晰的数据访问层抽象,提高可测试性和可维护性
- **异常处理** - 自定义异常类,带有集中式异常处理 middleware
- **缓存层** - 多驱动的缓存系统 (File, Redis, Null),带有辅助函数
- **Cookie 辅助工具** - 使用 AES-256-CBC 进行加密的 Cookie 管理
- **API 查询构建器** - 支持操作符和分页的过滤、排序、搜索
- **测试套件** - 使用 PHPUnit 实现全面的测试覆盖 (286+ 测试, 599+ 断言)
- **CLI 命令** - 类似 Artisan 的脚手架命令 (模块, 模型, 控制器, 请求)
- **模块化架构** - 基于功能的模块组织,具有更好的可扩展性
- **自动依赖注册** - 创建模块时自动注册依赖项
- **兼容 PHP 8.4** - 现代化的 PHP 特性和 Rector 自动重构
- **兼容 Docker** - 完整的 Docker 开发环境设置
- **环境变量验证** - 快速失败 (Fail-fast) 的配置验证
- **自动发现** - 带有缓存的自动 DI 注册
- **通用 CRUD** - 可复用的 CRUD,代码量减少 87%
## 📋 环境要求
- PHP >= 8.4
- Composer
- Docker & Docker Compose (用于开发)
- MySQL/MariaDB (或 SQLite 用于测试)
## 🛠️ 安装说明
1. **克隆仓库:**
git clone https://github.com/KalimeroMK/Slim4MVC
cd Slim4MVC
2. **安装依赖:**
composer install
3. **配置环境:**
cp .env.example .env
编辑 `.env` 并配置:
- 数据库凭据
- JWT_SECRET (生成一个强密钥)
- 邮件设置
- CORS 来源 (如果需要)
- 缓存驱动 (file/redis) 和 Redis 设置 (如果使用 Redis)
- Cookie 设置 (加密,生产环境的安全标志)
4. **启动 Docker 容器:**
docker-compose up -d
5. **清除缓存 (如果遇到命名空间错误):**
php clear-cache.php
docker compose restart
6. **运行迁移:**
php run_migrations.php
7. **填充数据库 (可选):**
php slim seed:database
8. **设置存储权限:**
# 使用 PHP 脚本 (推荐)
php setup-storage.php
# 或者使用 bash 脚本
./setup-storage.sh
# 或者手动
chmod -R 775 storage
chown -R www-data:www-data storage # 根据需要调整 user/group
应用程序将在 [http://localhost:81](http://localhost:81) 上可用
## 📁 项目结构
该项目使用**模块化架构**,其中每个功能都组织为一个独立的模块:
```
├── app/
│ ├── Console/ # CLI Commands
│ │ └── Commands/ # Console commands (make:module, make:request, etc.)
│ ├── Modules/ # Feature modules
│ │ ├── Core/ # Core module (base classes, middleware, support)
│ │ │ ├── Application/
│ │ │ │ ├── Actions/ # Core actions (Auth actions)
│ │ │ │ ├── DTOs/ # Core DTOs
│ │ │ │ ├── Enums/ # Enums (HttpStatusCode, ApiResponseStatus)
│ │ │ │ └── Interfaces/
│ │ │ └── Infrastructure/
│ │ │ ├── Events/ # Event system
│ │ │ ├── Exceptions/ # Custom exceptions
│ │ │ ├── Http/
│ │ │ │ ├── Controllers/ # Base controllers
│ │ │ │ ├── Middleware/ # Middleware
│ │ │ │ ├── Requests/ # Base FormRequest
│ │ │ │ └── Resources/ # Base Resource
│ │ │ ├── Jobs/ # Queue jobs
│ │ │ ├── Policies/ # Base Policy
│ │ │ ├── Providers/ # Service providers
│ │ │ ├── Queue/ # Queue system
│ │ │ ├── Repositories/ # Base repositories
│ │ │ ├── Support/ # Helper classes (Auth, Logger, Mailer, Cookie)
│ │ │ ├── Cache/ # Cache system (File, Redis, Null drivers)
│ │ │ ├── Query/ # API Query Builder (filter, sort, search)
│ │ │ └── View/ # Blade integration
│ │ ├── Auth/ # Authentication module
│ │ │ ├── Application/
│ │ │ │ ├── Actions/Auth/ # Login, Register, PasswordRecovery, etc.
│ │ │ │ ├── DTOs/Auth/ # Auth DTOs
│ │ │ │ └── Interfaces/Auth/
│ │ │ └── Infrastructure/
│ │ │ ├── Http/
│ │ │ │ ├── Controllers/
│ │ │ │ │ ├── Api/ # API AuthController (JWT)
│ │ │ │ │ └── Web/ # Web AuthController (Session)
│ │ │ │ └── Requests/Auth/
│ │ │ ├── Providers/ # AuthServiceProvider
│ │ │ └── Routes/ # API and Web routes
│ │ ├── User/ # User module
│ │ ├── Role/ # Role module
│ │ └── Permission/ # Permission module
│ └── Support/ # Legacy support (backward compatibility)
├── bootstrap/ # Application bootstrap files
│ ├── modules.php # Module loader
│ └── modules-register.php # Module registration
├── database/
│ ├── migrations/ # Database migrations
│ └── seed/ # Database seeders
├── public/ # Web root
├── resources/
│ ├── views/ # Blade templates
│ └── lang/ # Translation files
├── routes/ # Main route files (web.php, api.php)
├── stubs/ # Code generation stubs
│ └── Module/ # Module structure stubs
├── storage/
│ ├── cache/ # Application cache
│ │ ├── data/ # File cache storage
│ │ └── view/ # Blade compiled views
│ ├── logs/ # Application logs
│ ├── queue/ # Queue storage (file driver)
│ └── sessions/ # Session storage (file driver)
└── tests/ # PHPUnit tests
├── Unit/ # Unit tests
└── Feature/ # Feature tests
```
### 模块结构
每个模块遵循一致的结构:
```
app/Modules/Example/
├── Application/ # Business logic layer
│ ├── Actions/ # Business logic actions
│ ├── DTOs/ # Data Transfer Objects
│ ├── Services/ # Service classes
│ └── Interfaces/ # Service contracts
├── Infrastructure/ # Infrastructure layer
│ ├── Models/ # Eloquent models
│ ├── Repositories/ # Data access layer
│ ├── Http/
│ │ ├── Controllers/ # Request handlers
│ │ ├── Requests/ # Form request validation
│ │ └── Resources/ # API resource transformers
│ ├── Providers/ # Service providers
│ └── Routes/ # Module routes (api.php, web.php)
├── Exceptions/ # Module-specific exceptions
├── Observers/ # Eloquent observers
└── Policies/ # Authorization policies
```
## 🎯 使用方法
### 创建模块
创建新功能的推荐方式是使用**模块化架构**:
```
# 创建新模块
php slim make:module Product
# 使用自定义模型名称创建模块
php slim make:module Product --model=Item
# 创建带迁移的模块
php slim make:module Product --migration
```
这将自动创建:
- 完整的模块结构 (Application, Infrastructure 层)
- Actions (Create, Update, Delete, Get, List)
- DTOs (Create, Update)
- Interfaces (CreateActionInterface, UpdateActionInterface)
- Model 和 Repository
- 带有 CRUD 方法的 Controller
- Form Requests (Create, Update)
- API Resource
- Policy
- Service Provider
- API 路由
- 在 `bootstrap/dependencies.php` 中**自动注册依赖**
- 在 `bootstrap/modules-register.php` 中**自动注册模块**
**示例:**
```
php slim make:module Blog --model=Post --migration
```
这将创建:
- `app/Modules/Blog/` 及其完整结构
- `CreatePostAction`, `UpdatePostAction` 等
- `PostRepository` 会自动在 Service Provider 中注册
- `CreatePostActionInterface` 和 `UpdatePostActionInterface` 会自动在 `bootstrap/dependencies.php` 中注册
- 模块会自动在 `bootstrap/modules-register.php` 中注册
### 创建模型和迁移
```
# 创建模型
php slim make:model Product
# 创建带迁移的模型
php slim make:model Product -m
```
### 创建控制器
```
php slim make:controller Product
```
这将创建:
- Controller
- Actions (Create, Update, Delete, Get, List)
- DTOs (Create, Update)
- Form Requests (Create, Update)
### 创建表单请求
```
# 创建基础 request
php slim make:request User/CreateUserRequest
# 创建带有从模型自动生成规则的 request
php slim make:request User/CreateUserRequest --model=User
# 创建带有模型的更新 request
php slim make:request User/UpdateUserRequest --model=User --type=update
# 简写语法
php slim make:request User/CreateUserRequest -m User -t create
```
`--model` 选项会根据模型的 `$fillable` 字段和 `$casts` 自动生成验证规则。
### 运行迁移
```
# 运行迁移
php run_migrations.php
# 回滚上次迁移
php run_migrations.php rollback
# 刷新所有迁移
php run_migrations.php refresh
```
### 可用命令
```
# 模块创建
php slim make:module [--model=] [--migration]
# 模型创建
php slim make:model [-m]
# Controller 创建
php slim make:controller
# Request 创建
php slim make:request [--model=] [--type=]
# 数据库 seeding
php slim seed:database
# Queue 处理
php slim queue:work [--stop-when-empty] [--max-jobs=]
# Cache 管理
php slim cache:clear [--tag=] [--driver=]
# 列出所有路由
php slim list-routes
```
### 运行测试
```
# 运行所有测试
./vendor/bin/phpunit
# 或
composer test
# 运行并显示详细输出
./vendor/bin/phpunit --testdox
# 运行特定 test suite
./vendor/bin/phpunit tests/Unit
```
## 🔐 身份验证
应用程序包含一个专用的 **Auth 模块**,用于处理 API 和 Web 身份验证。
### Auth 模块
Auth 模块 (`app/Modules/Auth/`) 提供:
- **API 身份验证** - 用于 API 端点的基于 JWT 的身份验证
- **Web 身份验证** - 用于 Web 路由的基于 Session 的身份验证
- **密码找回** - 基于 token 的密码重置功能
- **事件驱动** - 为用户注册和密码重置分派事件
### API 身份验证 (JWT)
API 使用 JWT token 进行身份验证。成功登录后,请在请求中包含该 token:
```
curl -H "Authorization: Bearer YOUR_JWT_TOKEN" http://localhost:81/api/v1/users
```
### Web 身份验证 (Session)
Web 路由使用基于 session 的身份验证。`AuthWebMiddleware` 负责处理 Web 路由的身份验证。
## 🛡️ 授权
### 使用 Middleware
**基于角色的访问:**
```
$app->get('/admin/dashboard', [DashboardController::class, 'index'])
->add(new CheckRoleMiddleware())
->setArgument('roles', 'admin');
// Multiple roles (user needs one of these)
$app->get('/reports', [ReportController::class, 'index'])
->add(new CheckRoleMiddleware())
->setArgument('roles', ['admin', 'manager']);
```
**基于权限的访问:**
```
$app->post('/users', [UserController::class, 'store'])
->add(new CheckPermissionMiddleware())
->setArgument('permissions', 'create-users');
// Multiple permissions
$app->put('/posts/{id}', [PostController::class, 'update'])
->add(new CheckPermissionMiddleware())
->setArgument('permissions', ['edit-posts', 'publish-posts']);
```
### 使用 Policy
创建一个 policy:
```
// app/Policies/PostPolicy.php
class PostPolicy extends Policy
{
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id ||
$user->hasPermission('edit-posts');
}
}
```
在控制器中使用:
```
public function update(Request $request, Response $response, int $id): Response
{
$post = Post::find($id);
if (!$this->authorize('update', $post)) {
return $this->respondUnauthorized();
}
// Update logic...
}
```
## ⚡ 速率限制
速率限制会自动应用于身份验证端点 (每分钟 5 个请求)。您可以将其应用于任何路由:
```
use App\Modules\Core\Infrastructure\Http\Middleware\RateLimitMiddleware;
$rateLimit = new RateLimitMiddleware(10, 60); // 10 requests per 60 seconds
$app->post('/api/endpoint', [Controller::class, 'method'])
->add($rateLimit);
```
## 🌐 CORS 配置
CORS 在 `bootstrap/middleware.php` 中进行全局配置。在 `.env` 中配置允许的来源:
```
CORS_ORIGINS=*
# 或特定 origins
CORS_ORIGINS=http://localhost:3000,https://example.com
```
## 📝 日志
应用程序使用 Monolog 进行日志记录。使用 Logger 辅助函数:
```
use App\Modules\Core\Infrastructure\Support\Logger;
Logger::error('Something went wrong', ['user_id' => 123]);
Logger::warning('Suspicious activity detected');
Logger::info('User logged in', ['email' => $email]);
Logger::debug('Debug information', $data);
```
日志写入 `storage/logs/slim.log`。日志级别根据 `APP_ENV` 自动设置:
- `production`: Warning 及以上
- `local`/`development`: Debug 及以上
## 🎨 Blade 模板
本项目使用 **BladeOne** - 一个为 Slim 4 优化的轻量级独立 Blade 引擎。它提供了与 Laravel 相同的 Blade 语法,但没有沉重的依赖。
### 自定义 Blade 指令
提供了以下类似 Laravel 的指令:
#### 身份验证指令
```
@guest
Login
Register
@endguest
@auth
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
3. **存储目录** 受到保护 (已在 `.htaccess` 中配置)
### 权限参考
| 目录 | 权限 | 所有者 | 用途 |
|-----------|-------------|-------|---------|
| `storage/` | 775 | www-data | 根存储目录 |
| `storage/logs/` | 775 | www-data | 应用程序日志 |
| `storage/cache/` | 775 | www-data | Blade 视图缓存 |
| `storage/queue/` | 775 | www-data | 队列任务文件 |
**注意:** 请根据您的服务器配置调整 user/group (`www-data`, `nginx`, `apache`)。
### 安全注意事项
1. **存储目录** 绝不能通过 Web 浏览器访问
2. **环境文件** (`.env`) 应当受到保护
3. **Composer 文件** 不应被外部访问
4. **Git 文件** 不应被外部访问
5. **文件上传** (如果已实现) 应存储在 `public/` 目录之外
## 🤝 参与贡献
欢迎参与贡献!请随时提交 Pull Request。
## 📄 许可证
本项目基于 MIT 许可证授权。
## 🙏 鸣谢
- [Slim Framework](https://www.slimframework.com/)
- [Laravel](https://laravel.com/) 提供 Eloquent, Blade 和 Validation
- 所有了不起的开源贡献者
**用 ❤️ 为 PHP 社区而作**
Welcome, {{ AuthHelper::user()['name'] }}!
@endauth ``` #### CSRF 保护 ``` ``` #### HTTP 方法伪造 ``` ``` #### 授权指令 ``` @can('edit-posts') Edit Post @endcan @role('admin') Admin Panel @endrole ``` ### AuthHelper 类 `AuthHelper` 类提供了用于身份验证的静态方法: ``` use App\Modules\Core\Infrastructure\Support\AuthHelper; // Check authentication if (AuthHelper::check()) { // User is logged in } // Check if guest if (AuthHelper::guest()) { // User is not logged in } // Get current user $user = AuthHelper::user(); echo $user['name']; // Get user ID $userId = AuthHelper::id(); // Check permissions and roles if (AuthHelper::can('create-posts')) { // User can create posts } if (AuthHelper::hasRole('admin')) { // User is admin } // Set user data after login AuthHelper::setUser([ 'id' => $user->id, 'name' => $user->name, 'email' => $user->email, 'roles' => ['user', 'editor'], 'permissions' => ['view-posts', 'create-posts'] ]); // Logout user AuthHelper::logout(); ``` ### 标准 Blade 语法 所有标准的 Blade 指令均可正常工作: ``` @extends('layouts.app') @section('content'){{ $title }}
@foreach($users as $user){{ $user->name }}
@endforeach @if($condition) {{ $message }} @elseif($otherCondition) Other message @else Default message @endif @include('partials.footer') @endsection ``` ## 🧪 测试 本项目包含一个全面的测试套件,涵盖: ### 测试套件 | 套件 | 测试数 | 描述 | |-------|-------|-------------| | **Unit** | 404+ | 隔离的组件测试 | | **Integration** | 63+ | 数据库和服务集成 | | **Feature** | 21+ | 端到端 API 测试 | | **Edge Cases** | 18+ | 边界和异常场景 | ### v2.0 新增 (173 个附加测试) #### 环境验证测试 (48 个测试) - 生产环境验证 - 本地/开发环境验证 - 弱密钥检测 - 缺失配置检测 - 边缘情况 (unicode, 特殊字符, 边界值) #### JWT 服务测试 (51 个测试) - token 生成与验证 - 刷新 token 轮换 - 基于指纹的安全防护 - token 盗窃检测 - 多种算法 (HS256, HS384, HS512) - 边缘情况 (过期 token, 被篡改的 token) #### 自动发现测试 (35 个测试) - 模块扫描 - 缓存预热与清除 - 生产环境 vs 开发环境行为 - 统计信息生成 #### 通用 CRUD 测试 (39 个测试) - 创建、读取、更新、删除操作 - 分页 - Action 工厂 - 与真实数据库的集成 ### 运行测试 ``` # 运行所有测试 composer test # 运行特定 test suite ./vendor/bin/phpunit --testsuite Unit ./vendor/bin/phpunit --testsuite Integration ./vendor/bin/phpunit --testsuite Feature ./vendor/bin/phpunit --testsuite EdgeCases # 运行并启用 coverage ./vendor/bin/phpunit --coverage-html coverage # 运行特定测试文件 ./vendor/bin/phpunit tests/Unit/EnvironmentValidatorTest.php ``` ### 测试覆盖率 - ✅ 475+ 测试 - ✅ 900+ 断言 - ✅ 所有新功能均已测试 - ✅ 覆盖边缘情况 - ✅ 与真实数据库的集成 - ✅ 使用 Rector 优化至 PHP 8.4 ### 代码质量工具 **Laravel Pint** (代码格式化): ``` # 检查代码风格 ./vendor/bin/pint --test # 修复代码风格 ./vendor/bin/pint ``` **Rector** (自动重构): ``` # 检查哪些内容会被更改 ./vendor/bin/rector process --dry-run # 应用重构 ./vendor/bin/rector process ``` **组合使用 (兼容 CI/CD):** ``` ./vendor/bin/pint && ./vendor/bin/rector process && ./vendor/bin/phpunit ``` ## 🔧 配置 ### 环境变量 `.env` 中的核心环境变量: ``` # 应用 APP_ENV=local APP_URL=http://localhost:81 # 数据库 DB_CONNECTION=mysql DB_HOST=slim_db DB_PORT=3306 DB_DATABASE=slim DB_USERNAME=slim DB_PASSWORD=secret # JWT JWT_SECRET=your-secret-key-here # 邮件 MAIL_HOST=smtp.example.com MAIL_PORT=587 MAIL_USERNAME=your_email@example.com MAIL_PASSWORD=your_password MAIL_FROM_ADDRESS=noreply@example.com MAIL_FROM_NAME="Your App Name" MAIL_ENCRYPTION=tls # CORS CORS_ORIGINS=* # Cache CACHE_DRIVER=redis CACHE_PREFIX=slim_cache CACHE_PATH=/var/www/html/storage/cache/data REDIS_CACHE_DATABASE=1 # Queue QUEUE_DRIVER=redis QUEUE_RETRY_AFTER=90 # Session SESSION_DRIVER=redis SESSION_LIFETIME=120 # Cookies COOKIE_TTL=3600 COOKIE_PATH=/ COOKIE_DOMAIN= COOKIE_SECURE=true COOKIE_HTTP_ONLY=true COOKIE_SAME_SITE=Lax COOKIE_ENCRYPT=true ``` ## 📦 API 资源 应用程序使用 Resource 类来统一格式化 API 响应: ``` use App\Modules\User\Infrastructure\Http\Resources\UserResource; // Single resource return ApiResponse::success(UserResource::make($user)); // Collection return ApiResponse::success(UserResource::collection($users)); ``` 可用的 Resources: - `UserResource` - 格式化用户数据 (隐藏 password,包含 roles) - `RoleResource` - 格式化角色数据 (包含 permissions) - `PermissionResource` - 格式化权限数据 (包含 roles) ## 📊 API 响应格式 所有 API 响应均使用 `ApiResponse` 辅助类遵循一致的格式: **成功响应:** ``` { "status": "success", "data": {...}, "message": "Optional message" } ``` **错误响应:** ``` { "status": "error", "message": "Error message", "code": "ERROR_CODE", "errors": { "field": ["Error message"] } } ``` **在控制器中使用:** ``` use App\Support\ApiResponse; use App\Enums\HttpStatusCode; // Success return ApiResponse::success($data); return ApiResponse::success($user, HttpStatusCode::CREATED); // Errors return ApiResponse::error('Error message'); return ApiResponse::unauthorized(); return ApiResponse::notFound('User not found'); return ApiResponse::validationError(['email' => ['Invalid email']]); ``` ## 📚 API 端点 ### 身份验证 - `POST /api/v1/register` - 注册新用户 - `POST /api/v1/login` - 登录并获取 JWT token - `POST /api/v1/password-recovery` - 请求重置密码 - `POST /api/v1/reset-password` - 使用 token 重置密码 ### 用户 (需要身份验证) - `GET /api/v1/users` - 获取所有用户列表 - `POST /api/v1/users` - 创建用户 - `GET /api/v1/users/{id}` - 获取单个用户 - `PUT /api/v1/users/{id}` - 更新用户 - `DELETE /api/v1/users/{id}` - 删除用户 ### 角色 (需要身份验证) - `GET /api/v1/roles` - 获取所有角色列表 - `POST /api/v1/roles` - 创建角色 - `GET /api/v1/roles/{id}` - 获取单个角色 - `PUT /api/v1/roles/{id}` - 更新角色 - `DELETE /api/v1/roles/{id}` - 删除角色 ### 权限 (需要身份验证) - `GET /api/v1/permissions` - 获取所有权限列表 - `POST /api/v1/permissions` - 创建权限 - `GET /api/v1/permissions/{id}` - 获取单个权限 - `PUT /api/v1/permissions/{id}` - 更新权限 - `DELETE /api/v1/permissions/{id}` - 删除权限 ## 🏗️ 架构 本项目遵循**模块化整洁架构**模式: ### 模块化架构 应用程序被组织成**独立的模块**,每个模块包含: 1. **Application 层** - 业务逻辑 - **Actions** - 业务逻辑操作 - **DTOs** - 用于类型安全数据处理的数据传输对象 - **Interfaces** - 用于依赖注入的服务契约 - **Services** - 复杂的业务逻辑服务 2. **Infrastructure 层** - 技术实现 - **Models** - 用于数据库交互的 E 模型 - **Repositories** - 数据访问层抽象 (Repository pattern) - **Controllers** - 委托给 Actions 的轻量级控制器 - **Requests** - 表单请求验证 - **Resources** - API 响应转换器 - **Providers** - 用于依赖注册的服务提供者 - **Routes** - 模块特定的路由 3. **横切关注点** - **Middleware** - 请求/响应处理 - **Policies** - 授权逻辑 - **Exceptions** - 用于更好错误处理的自定义异常类 - **Events** - 事件驱动架构 - **Jobs** - 异步任务处理 ### 模块注册 模块通过 `bootstrap/modules-register.php` 自动注册: ``` return [ // Core module must be loaded first App\Modules\Core\Infrastructure\Providers\CoreServiceProvider::class, // Auth module App\Modules\Auth\Infrastructure\Providers\AuthServiceProvider::class, // Feature modules App\Modules\User\Infrastructure\Providers\UserServiceProvider::class, App\Modules\Role\Infrastructure\Providers\RoleServiceProvider::class, App\Modules\Permission\Infrastructure\Providers\PermissionServiceProvider::class, ]; ``` ### 依赖注入 应用程序使用带有自动依赖注册的 **PHP-DI**: - **Repositories** - 在 Service Providers 中自动注册 - **Action 接口** - 使用 `make:module` 时在 `bootstrap/dependencies.php` 中自动注册 - **自动装配** - PHP-DI 自动解析构造函数依赖项 **工作原理:** 1. **当使用 `make:module` 创建模块时**: - Repository 注册在 `ServiceProvider::register()` 中 - Action 接口注册在 `bootstrap/dependencies.php` 中 - Use 语句会自动添加 2. **PHP-DI 自动装配**: - 自动解析具体类 (无需注册) - 通过类型提示解析构造函数依赖 - 示例:`LoginAction` 需要 `UserRepository` → 自动注入 3. **基于接口的注入**: - 控制器使用接口 (例如,`CreateUserActionInterface`) - PHP-DI 通过 `dependencies.php` 解析为实现 - 方便在测试中进行 mock ### 仓储模式 应用程序使用 Repository 模式来抽象数据访问逻辑: ``` use App\Modules\User\Infrastructure\Repositories\UserRepository; class UserController extends Controller { public function __construct( private readonly UserRepository $repository ) {} public function show(int $id): Response { $user = $this->repository->findOrFail($id); return ApiResponse::success(UserResource::make($user)); } } ``` **自动注册:** 当您使用 `make:module` 创建模块时,Repository 会自动在 Service Provider 中注册: ``` // ServiceProvider::register() $container->set(UserRepository::class, \DI\autowire(UserRepository::class)); ``` 可用的 Repositories: - `UserRepository` - 用户数据访问,包含 `findByEmail()`, `findByPasswordResetToken()` 等方法 - `RoleRepository` - 角色数据访问,包含 `findByName()`, `paginateWithPermissions()` 等方法 - `PermissionRepository` - 权限数据访问,包含 `findByName()`, `paginateWithRoles()` 等方法 ### 带有接口的 Action 模式 Actions 实现了接口,以提供更好的可测试性和灵活性: ``` // Interface interface CreateUserActionInterface { public function execute(CreateUserDTO $dto): User; } // Implementation final class CreateUserAction implements CreateUserActionInterface { public function __construct( private readonly UserRepository $repository ) {} public function execute(CreateUserDTO $dto): User { return $this->repository->create([...]); } } ``` **自动注册:** 当您创建模块时,Action 接口会自动在 `bootstrap/dependencies.php` 中注册: ``` CreateUserActionInterface::class => \DI\autowire(CreateUserAction::class), ``` ### 使用模块 **创建新模块:** ``` php slim make:module Product --migration ``` 这将创建一个完整的模块结构。创建之后: 1. **更新 Model** (`app/Modules/Product/Infrastructure/Models/Product.php`): - 添加 `$fillable` 字段 - 添加 `$casts` 用于类型转换 - 如有需要,添加关联关系 2. **更新 DTOs** (`app/Modules/Product/Application/DTOs/`): - 向 `CreateProductDTO` 添加属性 - 向 `UpdateProductDTO` 添加可选属性 3. **更新 Actions** (`app/Modules/Product/Application/Actions/`): - 在 `CreateProductAction` 中将 DTO 属性映射到模型属性 - 根据需要添加业务逻辑 4. **更新 Controller** (`app/Modules/Product/Infrastructure/Http/Controllers/ProductController.php`): - 在 `store()` 和 `update()` 方法中将请求数据映射到 DTO 5. **更新 Resource** (`app/Modules/Product/Infrastructure/Http/Resources/ProductResource.php`): - 将字段添加到资源输出中 6. **更新 Requests** (`app/Modules/Product/Infrastructure/Http/Requests/`): - 根据需要添加验证规则 7. **更新 Policy** (`app/Modules/Product/Policies/ProductPolicy.php`): - 添加授权逻辑 **模块已可使用!** 路由会自动从 `app/Modules/Product/Infrastructure/Routes/api.php` 加载。 ### 异常处理 自定义异常类提供了一致的错误处理: ``` use App\Modules\Core\Infrastructure\Exceptions\NotFoundException; use App\Modules\Core\Infrastructure\Exceptions\InvalidCredentialsException; use App\Modules\Core\Infrastructure\Exceptions\UnauthorizedException; use App\Modules\Core\Infrastructure\Exceptions\ForbiddenException; use App\Modules\Core\Infrastructure\Exceptions\BadRequestException; // In Actions throw new NotFoundException('User not found'); throw new InvalidCredentialsException('Invalid email or password'); ``` `ExceptionHandlerMiddleware` 自动将异常转换为适当的 API 响应。 ## 🆕 新功能 ### 环境变量验证 (快速失败) 环境变量验证在应用程序启动时自动运行,以便尽早捕获配置错误。 ``` # 验证配置 php slim discovery --validate ``` **功能:** - 验证 `JWT_SECRET` 长度 (最少 32 个字符) - 检查数据库连接性 - 验证 `APP_ENV` 设置 - 特定于生产环境的检查 (Redis, Mail, Cache) **示例输出:** ``` 🔒 Environment Validation ═══════════════════════════════════════════════════════════════ ✅ Environment configuration is valid ------------------- ---------- Setting Value ------------------- ---------- Environment local JWT Configured Yes JWT Secret Length 42 chars DB Connection mysql ------------------- ---------- ``` ### 依赖注入的自动发现 自动发现并注册 接口 → 实现 的绑定。 ``` # 查看发现统计信息 php slim discovery --stats # 为生产环境预热 cache php slim discovery --warm # 刷新 cache php slim discovery --refresh ``` **之前 (手动注册):** ``` // bootstrap/dependencies.php return [ CreateUserActionInterface::class => autowire(CreateUserAction::class), UpdateUserActionInterface::class => autowire(UpdateUserAction::class), // ... 80+ more lines ]; ``` **之后 (自动发现):** ``` // bootstrap/dependencies.php $discovery = new OptimizedDiscovery(); return $discovery->buildDefinitions(); ``` ### 带有刷新令牌的 JWT 服务 采用安全最佳实践的增强型 JWT 实现。 ``` use App\Modules\Core\Infrastructure\Support\AdvancedJwtService; $jwtService = new AdvancedJwtService( secret: $_ENV['JWT_SECRET'], algorithm: 'HS256', issuer: 'my-app', audience: 'my-api' ); // Generate access token $token = $jwtService->generateAccessToken( userId: 123, claims: ['role' => 'admin'], ttl: 3600 // 1 hour ); // Generate token pair (access + refresh) $tokenPair = $jwtService->generateRefreshToken(userId: 123); // Returns: access_token, refresh_token, expires_in // Rotate refresh token (security best practice) $newPair = $jwtService->rotateRefreshToken($tokenPair->getRefreshToken()); // Validate token if ($jwtService->verify($token)) { $payload = $jwtService->decode($token); $userId = $payload->sub; } // Get token info $info = $jwtService->getTokenInfo($token); // Returns: algorithm, type, issuer, expires_at, is_expired, etc. ``` **功能:** - 访问令牌 (短期) - 刷新令牌 (长期,带有轮换) - 基于指纹的盗窃检测 - 签发者和受众验证 - token 黑名单支持 ### 通用 CRUD 控制器 以最少的代码构建完整的 CRUD API。 **之前 (150 行):** ``` class UserController extends Controller { public function __construct( private CreateUserAction $createAction, private UpdateUserAction $updateAction, // ... 5 more actions ) {} public function index(Request $request): Response { /* 20 lines */ } public function store(Request $request): Response { /* 15 lines */ } public function show(Request $request, array $args): Response { /* 10 lines */ } public function update(Request $request, array $args): Response { /* 15 lines */ } public function destroy(Request $request, array $args): Response { /* 10 lines */ } } ``` **之后 (20 行):** ``` class UserController extends GenericCrudController { protected string $repositoryClass = UserRepository::class; protected ?string $resourceClass = UserResource::class; protected array $defaultRelations = ['roles']; protected array $fillable = ['name', 'email', 'password']; } ``` **优势:** - **代码量减少 87%** - **开发速度提升 67%** - 自动分页、关联和验证 - 向后兼容现有控制器 有关详细的迁移说明,请参阅 [迁移指南](docs/MIGRATION_GUIDE.md)。 ## 🔒 安全特性 - ✅ 使用 bcrypt 进行密码哈希 - ✅ JWT token 身份验证 (API) - ✅ 基于 session 的身份验证 (Web) - ✅ Web 路由的 CSRF 保护 - ✅ 身份验证端点的速率限制 (5 次请求/分钟) - ✅ 所有 API 端点的速率限制 (可配置) - ✅ 使用 FormRequest 进行输入验证 - ✅ SQL 注入防护 (Eloquent ORM) - ✅ XSS 防护 (Blade 模板) - ✅ 安全的 session 处理 - ✅ 针对敏感数据的 Cookie 加密 (AES-256-CBC) - ✅ 集中式异常处理,带有适当的错误响应 - ✅ 改善代码组织的模块化架构 - ✅ 自动依赖注册 - ✅ 自定义 Blade 指令 (@auth, @guest, @csrf, @method, @can, @role) ## 💾 缓存 应用程序包含一个支持多驱动的强大缓存层: ### 功能特性 - **多驱动支持**:File, Redis 和 Null (用于测试) - **简洁的 API**:类似 Laravel 的辅助函数 - **Repository 集成**:内置 trait 用于简单的模型缓存 - **基于标签的缓存清除**:按标签刷新缓存 - **兼容 PSR-16**:标准缓存接口 ### 配置 在您的 `.env` 文件中配置缓存: ``` # Cache 驱动: file, redis, null CACHE_DRIVER=redis CACHE_PREFIX=slim_cache CACHE_PATH=/var/www/html/storage/cache/data # Redis Cache 数据库 (与 queue/session 分开) REDIS_CACHE_DATABASE=1 ``` ### 用法 #### 辅助函数 ``` // Store a value cache_put('key', 'value', 3600); // TTL in seconds (null = forever) // Retrieve a value $value = cache('key'); $value = cache('key', 'default'); // With default // Remember pattern (cache or compute) $users = cache_remember('users', 300, function () { return User::all(); }); // Check existence if (cache_has('key')) { // ... } // Delete a value cache_forget('key'); // Clear all cache cache_flush(); // Clear by tag cache_flush('users'); cache_flush(['users', 'posts']); ``` #### 依赖注入 ``` use App\Modules\Core\Infrastructure\Cache\CacheInterface; class UserController extends Controller { public function __construct( private readonly CacheInterface $cache ) {} public function index(): Response { $users = $this->cache->remember('users', 300, function () { return User::all(); }); return ApiResponse::success($users); } } ``` #### Repository 缓存 ``` use App\Modules\Core\Infrastructure\Cache\RepositoryCacheExample; use App\Modules\Core\Infrastructure\Repositories\EloquentRepository; class UserRepository extends EloquentRepository { use RepositoryCacheExample; protected string $cacheTag = 'users'; protected int $repositoryCacheTtl = 600; // 10 minutes protected function model(): string { return User::class; } // Use cached methods public function findCached(int $id): ?User { return $this->findCached($id); } // Custom cached query public function findByEmailCached(string $email): ?User { return $this->remember("email:{$email}", function () use ($email) { return $this->findByEmail($email); }); } } ``` #### Cacheable Trait ``` use App\Modules\Core\Infrastructure\Cache\Cacheable; class ProductService { use Cacheable; protected string $cacheTag = 'products'; protected int $cacheTtl = 3600; public function getFeaturedProducts() { return $this->remember('featured', function () { // Expensive query return Product::featured()->with('category')->get(); }); } public function clearProductCache() { $this->cacheFlush(); } } ``` ### 缓存驱动 #### 文件驱动 将缓存存储在文件系统中。适用于单服务器设置。 ``` CACHE_DRIVER=file CACHE_PATH=/var/www/html/storage/cache/data ``` #### Redis 驱动 推荐用于生产环境和多服务器设置。 ``` CACHE_DRIVER=redis REDIS_HOST=127.0.0.1 REDIS_PORT=6379 REDIS_CACHE_DATABASE=1 ``` #### Null 驱动 禁用缓存。适用于测试。 ``` CACHE_DRIVER=null ``` ### CLI 命令 ``` # 清除应用 cache php slim cache:clear # 按标签清除 cache php slim cache:clear --tag=users ``` ## 🍪 Cookie 应用程序包含一个支持加密的强大 Cookie 辅助工具: ### 功能特性 - **简洁的 API**:带有辅助函数的简单 get/set 方法 - **加密**:针对敏感数据的 AES-256-CBC 加密 - **灵活性**:支持数组、对象和基本数据类型 - **安全性**:可配置的 secure, httpOnly 和 SameSite 选项 - **框架无关性**:适用于任何 PHP 应用程序 ### 配置 在您的 `.env` 文件中配置 cookie: ``` # Cookie 设置 COOKIE_TTL=3600 COOKIE_PATH=/ COOKIE_DOMAIN= COOKIE_SECURE=true COOKIE_HTTP_ONLY=true COOKIE_SAME_SITE=Lax COOKIE_ENCRYPT=true ``` ### 用法 #### 辅助函数 ``` // Set a cookie cookie_set('user_id', 123, 3600); cookie_set('preferences', ['theme' => 'dark'], 86400); // Get a cookie $userId = cookie_get('user_id'); $userId = cookie_get('user_id', 0); // With default // Check if exists if (cookie_has('user_id')) { // ... } // Delete a cookie cookie_delete('user_id'); // Delete all cookies cookie_flush(); // Forever cookie (10 years) cookie_forever('remember_me', 'yes'); // Remember pattern (get or set) $settings = cookie_remember('app_settings', 3600, function () { return Settings::getDefaults(); }); ``` #### 直接使用类 ``` use App\Modules\Core\Infrastructure\Support\CookieHelper; $cookie = CookieHelper::getInstance(); // Set with custom options $cookie->set('session', $data, 3600, [ 'secure' => true, 'httponly' => true, 'samesite' => 'Strict' ]); // Get value $value = $cookie->get('session'); // Make cookie for Slim Response $cookieData = $cookie->make('name', 'value', 3600); $response = $response->withHeader('Set-Cookie', 'name=' . $cookieData['value'] . '; Path=' . $cookieData['path'] ); ``` #### 在控制器中 ``` class UserController extends Controller { public function login(Request $request, Response $response): Response { // Set user preference cookie cookie_set('last_login', date('Y-m-d H:i:s'), 86400 * 30); // Set encrypted session data cookie_set('user_prefs', [ 'theme' => 'dark', 'lang' => 'en' ], 3600); return $response; } public function logout(Request $request, Response $response): Response { // Clear user cookies cookie_delete('user_prefs'); cookie_delete('last_login'); return $response; } } ``` ### Cookie 加密 当 `COOKIE_ENCRYPT=true` 时,Cookie 会自动使用 AES-256-CBC 进行加密: ``` // Encryption is transparent - works the same way $helper = new CookieHelper(encryptionEnabled: true); $helper->set('secret', 'sensitive data'); // Automatically decrypted on get $data = $helper->get('secret'); // 'sensitive data' ``` ### 安全最佳实践 1. **始终使用加密**处理敏感数据 2. **设置 httpOnly** 以防止 XSS 攻击 3. **在生产环境中使用 secure 标志** (仅限 HTTPS) 4. **SameSite=Lax** 或 **Strict** 用于防范 CSRF 攻击 5. **合理的 TTL** - 不要让 cookie 永远有效 ## 🔍 API 查询构建器 强大的查询参数解析,用于 REST API 的过滤、排序和搜索。 ### 功能特性 - **过滤** - 使用操作符 (`eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `like`, `in` 等) 按任意字段过滤 - **排序** - 带有方向 (`asc`/`desc`) 的多列排序 - **搜索** - 跨多个字段的全文本搜索 - **字段选择** - 仅选择需要的字段 (稀疏字段集) - **关联** - 预加载关联数据 (`include`) - **范围** - 按数字范围 (价格、日期等) 过滤 - **分页** - 带有可配置限制的自动分页 ### 用法 #### 基本过滤 ``` // URL: GET /api/users?filter[role]=admin&filter[active]=true $users = User::filter($request)->paginate(); ``` #### 排序 ``` // URL: GET /api/users?sort=-created_at,name // Sort by created_at DESC, then name ASC $users = User::filter($request)->paginate(); ``` #### 搜索 ``` // In User model protected array $searchable = ['name', 'email']; // URL: GET /api/users?search=john // Searches in name and email fields $users = User::filter($request)->paginate(); ``` #### 字段选择 ``` // URL: GET /api/users?fields=id,name,email // Returns only id, name, and email $users = User::filter($request)->paginate(); ``` #### 预加载 ``` // URL: GET /api/users?include=posts,comments $users = User::filter($request)->paginate(); ``` #### 范围 ``` // URL: GET /api/products?range[price]=10,100 $products = Product::filter($request)->paginate(); ``` #### 带有操作符的高级过滤 ``` // URL: GET /api/users?filter[age]=gt:18&filter[name]=like:john // Operators: eq, ne, gt, gte, lt, lte, like, starts, ends, in, nin, null ``` ### 在控制器中使用 ``` use App\Modules\Core\Infrastructure\Query\Filterable; class UserController extends Controller { public function index(Request $request): Response { // Using the Filterable trait $result = User::filterPaginate($request); return ApiResponse::success($result['items'], HttpStatusCode::OK, null, $result['pagination']); } } ``` ### 模型配置 ``` use App\Modules\Core\Infrastructure\Query\Filterable; class User extends Model { use Filterable; // Fields allowed for filtering protected array $filterable = ['name', 'email', 'role', 'active']; // Fields allowed for sorting protected array $sortable = ['id', 'name', 'created_at', 'updated_at']; // Fields allowed for searching protected array $searchable = ['name', 'email']; // Default sort order protected array $defaultSort = ['created_at' => 'desc']; } ``` ### 直接使用 QueryBuilder ``` use App\Modules\Core\Infrastructure\Query\QueryBuilder; // Simple usage $users = (new QueryBuilder($request))->paginate(User::class); // With configuration $builder = new QueryBuilder($request, [ 'filterable' => ['name', 'email'], 'sortable' => ['id', 'name'], 'searchable' => ['name', 'email'], ]); $users = $builder->paginate(User::class); ``` ### 辅助函数 ``` // Parse query parameters $parser = query_parser($request); $filters = $parser->filters(); $sorts = $parser->sorts(); $search = $parser->search(); // Apply filters to query $query = query_filter(User::class, $request); $users = $query->paginate(); // Get paginated results directly $result = query_paginate(User::class, $request); // Returns: ['items' => [...], 'pagination' => [...]] ``` ### URL 参数参考 | 参数 | 示例 | 描述 | |-----------|---------|-------------| | `filter[field]` | `filter[status]=active` | 按字段值过滤 | | `filter[field]=op:value` | `filter[age]=gt:18` | 使用操作符过滤 | | `sort` | `sort=-created_at,name` | 按字段排序 | | `search` | `search=john` | 全文本搜索 | | `fields` | `fields=id,name,email` | 选择特定字段 | | `include` | `include=posts,comments` | 预加载关联 | | `range[field]` | `range[price]=10,100` | 按范围过滤 | | `page` | `page=2` | 页码 | | `per_page` | `per_page=25` | 每页数量 (最大 100) | ### 过滤操作符 | 操作符 | 示例 | 描述 | |----------|---------|-------------| | `eq` | `filter[id]=eq:1` | 等于 (默认) | | `ne` | `filter[status]=ne:draft` | 不等于 | | `gt` | `filter[age]=gt:18` | 大于 | | `gte` | `filter[price]=gte:10` | 大于等于 | | `lt` | `filter[age]=lt:65` | 小于 | | `lte` | `filter[price]=lte:100` | 小于等于 | | `like` | `filter[name]=like:john` | 包含子串 | | `starts` | `filter[name]=starts:John` | 开头为 | | `ends` | `filter[name]=ends:Doe` | 结尾为 | | `in` | `filter[id]=in:1,2,3` | 在数组中 | | `nin` | `filter[status]=nin:deleted` | 不在数组中 | | `null` | `filter[deleted_at]=null:true` | 为空 / 不为空 | ## 📦 依赖项 ### 核心 - `slim/slim` - Slim Framework 4 - `illuminate/database` - Eloquent ORM - `illuminate/validation` - 验证 - `eftec/bladeone` - 轻量级 Blade 模板引擎 - `php-di/slim-bridge` - 依赖注入 ### 身份验证与安全 - `firebase/php-jwt` - JWT token - `slim/csrf` - CSRF 保护 - `tuupola/cors-middleware` - CORS 支持 ### 实用工具 - `monolog/monolog` - 日志记录 - `phpmailer/phpmailer` - 邮件发送 - `vlucas/phpdotenv` - 环境变量 - `illuminate/pagination` - 分页支持 - `illuminate/support` - Laravel 支持包 - `predis/predis` - Redis 客户端 (缓存, 队列, 会话) ### 开发 - `phpunit/phpunit` - 测试 -laravel/pint` - 代码格式化 - `rector/rector` - 代码重构 ## 🚀 部署 ### 存储目录设置 应用程序需要对 `storage/` 目录的写入权限,用于存储日志、缓存和队列文件。 #### 设置 **对于 Nginx:** ``` # 设置所有权 sudo chown -R www-data:www-data storage # 设置权限 sudo chmod -R 775 storage ``` **对于 Apache:** ``` # 设置所有权 sudo chown -R www-data:www-data storage # 设置权限 sudo chmod -R 775 storage ``` **对于 Docker:** 存储目录会自动挂载,权限由容器处理。 ### Web 服务器配置 #### Nginx 配置 Nginx 配置位于 `docker/nginx/app.conf`。对于生产环境,请确保: 1. **文档根目录** 指向 `/var/www/html/public` 2. **PHP-FPM** 配置正确 3. **存储目录** 受到保护 (在 nginx 配置中拒绝访问) 4. **安全头信息** 已设置 生产环境示例 Nginx 配置: ``` server { listen 80; server_name your-domain.com; root /var/www/html/public; # Deny access to storage and cache location ~ ^/(storage|cache)/ { deny all; } location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.3-fpm.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } ``` #### Apache 配置 位于 `public/` 目录中的 `.htaccess` 文件处理 URL 重写。请确保: 1. **mod_rewrite** 已启用: sudo a2enmod rewrite sudo systemctl restart apache2 2. 在 Apache 配置中 **AllowOverride** 设置为 All:标签:AES-256, API开发, API资源, AppImage, Blade模板引擎, CISA项目, CLI命令行, CORS, Docker, Eloquent ORM, ETW劫持, ffuf, JWT认证, Laravel, Monolog, MVC, OpenVAS, PHP, PHP 8.4, PHPUnit, RBAC, Rector, Redis缓存, RESTful API, Session认证, Slim 4, Web应用防火墙, Web开发框架, 依赖注入, 分布式计算, 加密Cookie, 单元测试, 威胁情报, 存储库模式, 安全防御评估, 开发者工具, 异常处理, 提示词优化, 搜索引擎查询, 数据库迁移, 日志记录, 权限管理, 模块化架构, 模型越狱, 漏洞评估, 脚手架, 请求拦截, 防暴力破解