Download the PHP package maiscraft/graphql without Composer
On this page you can find all versions of the php package maiscraft/graphql. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download maiscraft/graphql
More information about maiscraft/graphql
Files in maiscraft/graphql
Package graphql
Short Description PHP 8 Attribute + Reflection driven GraphQL Schema auto-generation engine. Framework-agnostic, with strategy pattern type conversion and container DI.
License MIT
Homepage https://github.com/mslbit/graphql
Informations about the package graphql
Maiscraft GraphQL
基于 PHP 8 Attribute + 反射的 GraphQL Schema 自动生成引擎,框架无关。
核心理念
- 约定优于配置:getter/setter/构造函数自动推导字段,无需手动注册
- 最小注解设计:
#[Type]、#[Field]、#[Query]、#[Mutation]、#[Arg]五个核心注解 - 反射驱动:PHP 反射自动生成 Schema,减少样板代码
- 策略模式 + 容器注入:TypeResolver(唯一决策点)→ TypeConverterFactory → 各 TypeConverter,核心服务通过容器单例
- ID 自动加解密:自定义
ID标量,输出时自动 encode、输入时自动 decode,业务层无感知 - ID 自动推断:参数名/字段名恰好为
id且 PHP 类型为int时,自动推断为ID类型,无需显式注解 - EntityObject 基类:继承即自动成为 GraphQL Type,无需
#[Type]注解 - 字段级方向控制:
#[Field(readonly: true)](仅 Output)、#[Field(writeonly: true)](仅 Input)、#[Field(view: ['list'])](视图限定),引擎自动派生多类型
架构
职责边界:
- TypeResolver:唯一决策点,所有类型判断收敛到这里
- TypeRegistry:纯存储,只做 get/set/has/mapClassName
- Converter:纯转换,className → GraphQL Type,零注册逻辑
- 所有核心服务通过 ContainerInterface 注入,保证单例
安装
快速开始
1. 定义 Entity(Output Type)
方式一:继承 EntityObject(推荐)
继承
EntityObject的类自动成为 GraphQL Type,无需#[Type]注解。引擎通过父链查找识别。
方式二:使用 #[Type] 注解
字段暴露规则:
| 来源 | Output | Input |
|---|---|---|
| 构造函数参数 | ✅ 自动收集 | ✅ 自动收集 |
get* 方法 |
✅ 自动收集 | ❌ |
is* 方法 |
✅ → is_fieldname |
❌ |
set* 方法 |
❌ | ✅ 自动收集 |
| public 属性 | 仅 #[Field] 标注 |
仅 #[Field] 标注 |
#[Field(hidden: true)] |
❌ 不输出 | ❌ 不输出 |
2. 定义 Enum
支持 backed enum 和非 backed enum,运行时值转换统一通过 ReflectionEnum::getCase() 反射获取,无硬编码方法依赖。
3. 定义 DTO(Input Type)
构造函数参数自动成为 GraphQL Input 字段,运行时通过反射构造实例(snake_case → camelCase 自动映射)。
4. 定义 Resolver
非 id 的 ID 参数需显式注解:
5. 配置(Hyperf)
6. 独立使用(无框架)
无框架使用时,容器中无 IdCodecInterface 绑定,引擎自动用 NoopIdCodec 兜底(明文 ID)。
7. 查询示例
注意:
id参数传入的是加密后的字符串(如"jR"),引擎自动 decode 为 int 传给 Resolver 方法。输出时id字段自动 encode 为加密字符串。
EntityObject 基类
EntityObject 是 GraphQL 包提供的规范实体基类。继承此类的子类自动成为 GraphQL ObjectType,无需 #[Type] 注解。
工作机制
EntityObject声明#[Type]且为abstract,本身不会被扫描注册ClassScanner::isTypeClass()跳过抽象类MetadataInspector::isGraphqlType()沿父链查找#[Type]注解- 具体子类(如
Article)非抽象、无#[Type],但父链找到 → 被扫描注册
核心能力
| 能力 | 说明 |
|---|---|
$_data 数组存储 |
构造函数接收 Model::getAttributes() 数组,数据统一存入 $_data |
__call 魔术方法 |
getXxx() → $_data['xxx'](snake_case),setXxx/isXxx/hasXxx/unsXxx 同理 |
setData/getData |
显式读写 $_data,供 Model toEntity() 调用 |
setPropAttr() |
根据 public 属性声明类型自动转换(int/float/string/bool/enum) |
toArray() |
递归转为关联数组(处理嵌套 EntityObject) |
raw() |
返回原始 $_data(不做转换) |
\ArrayAccess |
支持 $entity['key'] 语法 |
| 外键加解密 | encryptForeignKey/decryptForeignKey 等辅助方法 |
使用示例
若子类需要隐藏(不暴露到 Schema),加
#[Type(hidden: true)]。
ID 标量类型
GraphQL 内置 ID 标量被替换为自定义 IDScalar,实现自动加解密。
工作机制
核心组件
| 组件 | 位置 | 职责 |
|---|---|---|
IdCodecInterface |
Contract/IdCodecInterface.php |
加解密契约(encode/decode/decodeNullable) |
NoopIdCodec |
Default/NoopIdCodec.php |
默认兜底实现(明文透传,(string) $id) |
IDScalar |
Type/IDScalar.php |
自定义标量,继承 CustomScalarType,覆盖 serialize/parseValue/parseLiteral |
TypeRegistry |
TypeRegistry.php |
resolveIDScalar() 检查容器有无 IdCodecInterface,有则用 IDScalar,无则用内置 Type::id() |
SchemaDirector |
Director/SchemaDirector.php |
构建 Schema 时注入 scalarOverrides,让 webonyx 使用自定义 IDScalar 替代内置 ID |
注册自定义 IdCodec
方式一:通过容器绑定(推荐)
方式二:实现 IdCodecInterface
容器中无
IdCodecInterface绑定时,TypeRegistry::resolveIDScalar()返回内置Type::id(),ID 明文传输,无加解密。
webonyx scalarOverrides
webonyx 的 Schema 构造需要 scalarOverrides 配置才会用自定义标量替代内置 ID。SchemaDirector::build() 中:
没有 scalarOverrides,即使 TypeRegistry 注册了 IDScalar,序列化仍走内置 Type::id()。
ID 自动推断
参数名/字段名恰好为 id 且 PHP 类型为 int 时,自动推断为 ID 类型,无需显式 #[Arg(type: 'ID!')] 或 #[Field(type: 'ID')]。
推断规则
| 场景 | 条件 | 结果 | 实现位置 |
|---|---|---|---|
| Query/Mutation 参数 | 参数名 === 'id' + PHP int |
ID 或 ID!(按 nullable) |
ArgResolver::isIdParameter() |
| Output 字段 | 字段名 === 'id' + PHP int |
ID 或 ID!(按 nullable) |
ObjectTypeConverter::isIdFieldName() |
| Input 字段 | 字段名 === 'id' + PHP int |
ID 或 ID!(按 nullable) |
InputTypeConverter::isIdFieldName() |
不自动推断的情况:
- 外键字段:
product_id、categoryId、*_id、*Id→ 保持Int,需显式#[Arg(type: 'ID!')]或#[Field(type: 'ID')] - 非
int类型的id:如string $id→ 保持String - 有显式注解的:
#[Arg(type: 'String!')] int $id→ 用注解类型
示例对比
分页
引擎提供三种分页模式,声明返回类型即自动完成类型注册、参数追加、数据规范化。
三种分页类型
| 模式 | 泛型语法 | 直接写法 | 生成的 GraphQL 类型 | 特点 |
|---|---|---|---|---|
| 完整偏移分页 | Pagination<Page> |
PagePagination |
{Node}Pagination |
含 total/last_page,触发 COUNT(*) |
| 简单偏移分页 | SimplePagination<Page> |
PageSimplePagination |
{Node}SimplePagination |
无 total,多取 1 条判断 hasMore |
| Relay 游标分页 | CursorPagination<Page> |
PageConnection |
{Node}Connection |
edges+pageInfo+totalCount |
GraphQL 类型结构
完整偏移分页({Node}Pagination):
简单偏移分页({Node}SimplePagination):
Relay 游标分页({Node}Connection):
自动追加参数
根据返回类型自动追加参数(仅当方法未显式声明时):
| 分页模式 | 自动追加参数 | 默认值 |
|---|---|---|
Pagination / SimplePagination |
page: Int, perPage: Int |
page=1, perPage=15 |
CursorPagination |
first: Int, after: String |
first=15, after=null |
Resolver 用法
PaginationHelper 便捷工具
GraphQL 查询示例
Entity 字段中使用分页
注解参考
#[Type] — 类级别,标记 GraphQL 类型
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name |
string | 类短名 | GraphQL type 名称 |
description |
string | '' |
类型描述 |
as |
string | '' |
类型用途标记(如 'input'、'output'),扩展预留 |
hidden |
bool | false |
隐藏,不生成 Schema |
继承
EntityObject的子类无需#[Type],父链查找自动识别。若需隐藏子类,加#[Type(hidden: true)]。
#[Field] — 方法/属性/参数,标记字段
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name |
string|null | null |
覆盖字段名 |
type |
string|null | 自动推导 | GraphQL 类型(支持 Article[]、ID!、JSON、ProductPagination) |
description |
string|null | null |
字段描述 |
hidden |
bool | false |
隐藏,不输出到 Schema |
readonly |
bool | false |
仅 Output(排除 Input),适用于系统生成字段 |
writeonly |
bool | false |
仅 Input(排除 Output),适用于写入字段 |
view |
array | [] |
视图限定(空=所有视图,['list'] =仅 list 视图) |
id字段(PHPint)自动推断为ID,无需#[Field(type: 'ID')]。
字段方向控制规则:
| 标记 | Output | Input | 说明 |
|---|---|---|---|
| 无标记(默认) | ✅ | ✅ | 读写都行 |
readonly: true |
✅ | ❌ | 系统生成字段(slug、created_at、variants) |
writeonly: true |
❌ | ✅ | 写入字段(password、category_ids 批量关联) |
view: ['list'] |
仅该视图 | ❌ | 视图特异性字段 |
view: ['detail'] |
仅该视图 | ❌ | 视图特异性字段 |
视图派生示例:
引擎自动派生 3 个类型:
#[Query] / #[Mutation] — 方法,定义根字段
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name |
string | 方法名 | GraphQL 字段名 |
description |
string | '' |
字段描述 |
type |
string | 返回类型推导 | 返回类型名(支持 PagePagination、Pagination<Page> 等) |
#[Arg] — 参数,定义字段参数
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name |
string | 参数名 | GraphQL 参数名 |
type |
string | 自动推导 | GraphQL 类型(支持 ID!、[FilterInput!] 等) |
description |
string | null |
参数描述 |
id参数(PHPint)自动推断为ID!,无需#[Arg(type: 'ID!')]。非id的 ID 参数需显式注解。
#[Input] — 属性/方法/参数,控制 Input 类型行为
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
exclude |
bool | false |
从 Input 类型中排除该字段 |
required |
bool|null | null |
是否必填(null=自动推断,true=必填,false=可选) |
#[Rules] — 属性/参数,验证规则
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
rules |
array|string|null | null |
验证规则(数组格式 ['required', 'max:255'] 或管道格式 'required|max:255') |
支持 Laravel 风格全部规则(
required|unique:table,col|exists:...等),通过ValidatorInterface执行。嵌套 InputType 递归验证。
#[Permission] — 类/方法,权限检查
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
args |
array|string | [] |
权限标识(如 ['content.view']) |
policy |
string|null | null |
自定义策略类名(null 时用默认 AuthorizeResourceInterface) |
授权流程:
AuthResolverInterface→FieldSecurityMiddleware→Permission::check()。#[Guard]已废弃,用#[Permission]替代。
#[Privacy] — 方法/属性/参数,字段级访问控制
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
policy |
callable|string | null |
闭包或 Privacy 子类类名 |
与
#[Permission]区别:#[Permission]拒绝时抛错,#[Privacy]拒绝时返回 null。
#[Cache] — 方法,字段级缓存
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
key |
string|null | null |
缓存键(null 时自动生成) |
prefix |
string | '' |
缓存键前缀 |
ttl |
int|null | null |
有效期(秒),null 用缓存驱动默认 |
guard |
bool | false |
按登录状态区分缓存 |
userId |
bool | false |
按用户 ID 区分缓存 |
abilities |
array | [] |
按权限标识区分缓存 |
#[QueryMiddleware] — 类,查询级中间件
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
priority |
int | 100 |
执行优先级(越小越先),同优先级按类名排序 |
#[FieldMiddleware] — 类,字段级中间件
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
priority |
int | 100 |
执行优先级(越小越先),同优先级按类名排序 |
#[GraphqlInterface] — 接口/类,标记 GraphQL InterfaceType
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name |
string|null | null |
GraphQL 接口名(null 用类短名) |
description |
string|null | null |
接口描述 |
#[Union] — 类,标记 GraphQL UnionType
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
name |
string|null | null |
GraphQL 联合类型名(null 用类短名) |
description |
string|null | null |
联合类型描述 |
#[Guard](已废弃)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
driver |
string | '' |
认证驱动名('admin'、'customer') |
AuthResolverInterface已保证认证,#[Permission]做细粒度授权。
项目结构
API 端点
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /graphql |
执行 GraphQL 查询 |
| GET | /graphql |
Introspection 查询 |
| GET | /playground |
GraphQL Playground 调试界面 |