maiscraft/graphql
Composer 安装命令:
composer require maiscraft/graphql
包简介
PHP 8 Attribute + Reflection driven GraphQL Schema auto-generation engine. Framework-agnostic, with strategy pattern type conversion and container DI.
README 文档
README
基于 PHP 8 Attribute + 反射的 GraphQL Schema 自动生成引擎,框架无关。
核心理念
- 约定优于配置:getter/setter/构造函数自动推导字段,无需手动注册
- 最小注解设计:
#[Type]、#[Field]、#[Query]、#[Mutation]、#[Arg]五个注解 - 反射驱动:PHP 反射自动生成 Schema,减少样板代码
- 策略模式 + 容器注入:TypeResolver(唯一决策点)→ TypeConverterFactory → 各 TypeConverter,核心服务通过容器单例
架构
Driver(组装容器,注册核心服务)
└─ TypeResolver(唯一决策点 + 唯一注册入口)
├─ enum_exists / class_exists 判断收敛于此
├─ TypeKind 分类(SCALAR / ENUM / OBJECT / INPUT_OBJECT)
└─ TypeConverterFactory → EnumTypeConverter / ObjectTypeConverter / InputTypeConverter
└─ TypeRegistry(纯存储,零判断)
└─ PhpTypeMapper(PHP → GraphQL 类型映射)
└─ RootFieldConverter(Query/Mutation 根字段 + 运行时值转换)
职责边界:
- TypeResolver:唯一决策点,所有类型判断收敛到这里
- TypeRegistry:纯存储,只做 get/set/has/mapClassName
- Converter:纯转换,className → GraphQL Type,零注册逻辑
- 所有核心服务通过 ContainerInterface 注入,保证单例
安装
composer require maiscraft/graphql
composer require maiscraft/graphql-hyperf # Hyperf 框架适配
快速开始
1. 定义 Entity(Output Type)
namespace App\Domain\Entity; use Maiscraft\GraphQL\Annotation\Type; use Maiscraft\GraphQL\Annotation\Field; #[Type(description: '文章')] class Article { public function __construct( private readonly ?int $id = null, private readonly string $title = '', private readonly string $slug = '', private readonly string $status = 'draft', ) {} #[Field(type: 'ID')] public function getId(): ?int { return $this->id; } public function getTitle(): string { return $this->title; } public function getSlug(): string { return $this->slug; } // is* 方法 → is_fieldname 布尔字段 public function isPublished(): bool { return $this->status === 'published'; } }
字段暴露规则:
| 来源 | Output | Input |
|---|---|---|
| 构造函数参数 | ✅ 自动收集 | ✅ 自动收集 |
get* 方法 |
✅ 自动收集 | ❌ |
is* 方法 |
✅ → is_fieldname |
❌ |
set* 方法 |
❌ | ✅ 自动收集 |
| public 属性 | 仅 #[Field] 标注 |
仅 #[Field] 标注 |
#[Field(hidden: true)] |
❌ 不输出 | ❌ 不输出 |
2. 定义 Enum
namespace App\Domain\ValueObject; use Maiscraft\GraphQL\Annotation\Type; #[Type(description: '发布状态')] enum PublishStatus { case DRAFT; case PUBLISHED; case ARCHIVED; }
支持 backed enum 和非 backed enum,运行时值转换统一通过 ReflectionEnum::getCase() 反射获取,无硬编码方法依赖。
3. 定义 DTO(Input Type)
namespace App\DTO; class CreateArticleDTO { public function __construct( public readonly string $title, public readonly string $slug, public readonly ?string $description = null, ) {} }
构造函数参数自动成为 GraphQL Input 字段,运行时通过反射构造实例(snake_case → camelCase 自动映射)。
4. 定义 Resolver
namespace App\GraphQL; use App\Domain\Entity\Article; use App\DTO\CreateArticleDTO; use Maiscraft\GraphQL\Annotation\Query; use Maiscraft\GraphQL\Annotation\Mutation; use Maiscraft\GraphQL\Annotation\Arg; use Maiscraft\GraphQL\Contract\ResolverInterface; class ArticleResolver implements ResolverInterface { public function __construct( private ArticleRepositoryInterface $repository ) {} #[Query(description: 'Get an article by ID')] public function article(#[Arg(type: 'ID!')] string $id): ?Article { return $this->repository->findById((int) $id); } #[Query(description: 'Get paginated articles')] public function articles(?int $page = null, ?int $pageSize = null): ArticlePaginator { return $this->repository->paginate($page ?? 1, $pageSize ?? 10); } #[Mutation(description: 'Create a new article')] public function createArticle(CreateArticleDTO $input): Article { return $this->repository->save(new Article( title: $input->title, slug: $input->slug, description: $input->description, )); } #[Mutation(description: 'Delete an article')] public function deleteArticle(#[Arg(type: 'ID!')] string $id): bool { return $this->repository->delete((int) $id); } }
5. 配置(Hyperf)
// config/autoload/graphql.php return [ 'debug' => true, // 目录路径扫描(从文件内容解析 namespace 获取类名) 'scan_paths' => [ BASE_PATH . '/app', ], 'security' => [ 'max_query_depth' => 15, 'max_query_complexity' => 1000, ], ];
6. 独立使用(无框架)
use Maiscraft\GraphQL\Default\SimpleContainer; use Maiscraft\GraphQL\Driver\Driver; $container = new SimpleContainer(); $driver = new Driver($container); $schema = $driver->buildSchema( resolvers: [ArticleResolver::class], types: [Article::class, PublishStatus::class], ); $result = \GraphQL\GraphQL::executeQuery( schema: $schema, source: '{ articles { items { id title } total } }', );
7. 查询示例
query { article(id: "1") { id title slug is_published } articles(page: 1, pageSize: 10) { items { id title } total } }
mutation { createArticle(input: { title: "新文章" slug: "new-article" description: "描述" }) { id title } }
注解参考
#[Type] — 类级别,标记 GraphQL 类型
#[Type(name: 'CustomName', description: '描述', hidden: false)]
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name |
string | 类名 | GraphQL type 名称 |
description |
string | '' |
类型描述 |
hidden |
bool | false |
隐藏,不生成 Schema |
#[Field] — 方法/属性/参数,标记字段
#[Field(type: 'ID', description: '描述', hidden: false)]
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
type |
string | 自动推导 | GraphQL 类型(支持 Article[]、ID!、JSON) |
description |
string | null |
字段描述 |
hidden |
bool | false |
隐藏,不输出到 Schema |
#[Query] / #[Mutation] — 方法,定义根字段
#[Query(description: '描述', type: 'ArticlePaginator')]
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name |
string | 方法名 | 字段名 |
description |
string | '' |
字段描述 |
type |
string | 返回类型推导 | 返回类型名 |
#[Arg] — 参数,定义字段参数
#[Arg(type: 'ID!')]
项目结构
graphql/src/
├── Annotation/ # 注解定义
│ ├── Arg.php
│ ├── Field.php
│ ├── Mutation.php
│ ├── Query.php
│ └── Type.php
├── Contract/ # 接口契约
│ ├── ContainerInterface.php
│ ├── ResolverInterface.php
│ └── ...
├── Converter/ # 类型转换器(策略模式)
│ ├── TypeConverterInterface.php
│ ├── TypeConverterFactory.php
│ ├── EnumTypeConverter.php
│ ├── ObjectTypeConverter.php
│ ├── InputTypeConverter.php
│ └── RootFieldConverter.php
├── Default/ # 默认实现
│ ├── SimpleContainer.php
│ └── ...
├── Driver/ # 驱动层
│ ├── ClassScanner.php
│ └── Driver.php
├── Engine/ # 引擎
│ ├── EngineConfig.php
│ └── GraphQLEngine.php
├── Mapper/ # 类型映射
│ └── PhpTypeMapper.php
├── Metadata/ # 元数据检查
│ └── MetadataInspector.php
├── Type/
│ └── JsonType.php # JSON 标量类型
├── ReflectionHelper.php # 共享工具 trait
├── TypeKind.php # 类型分类枚举
├── TypeRegistry.php # 纯存储
└── TypeResolver.php # 唯一决策点 + 唯一注册入口
API 端点
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /graphql |
执行 GraphQL 查询 |
| GET | /graphql |
Introspection 查询 |
| GET | /playground |
GraphQL Playground 调试界面 |
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 2
- 依赖项目数: 1
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-21