lighthouse-php中如何使用@method指令正确实现带复杂逻辑的按需自定义查询
正确实现Lighthouse统计字段按需查询的方案
现有实现的核心问题
你目前手动在服务提供者中注册ObjectType的方式存在本质偏差:
- 手动注册的类型没有绑定到Schema的根查询入口,哪怕注册成功,Schema中也不存在
statsReport这个可查询的字段路径,自然无法发起请求 - 这种绕开Lighthouse Schema优先机制的写法,无法利用@method等内置指令的解析能力,也没法实现字段级的按需执行
实现步骤
1. 移除冗余的手动类型注册代码
可以直接删掉GraphQLServiceProvider中手动实例化ObjectType、调用TypeRegistry->register()的逻辑,Lighthouse的Schema驱动机制完全可以自动完成类型注册和解析,不需要手动介入。
2. 在schema.graphql中声明需要的类型结构
按照你期望的查询结构,在Schema文件中做如下声明:
# 定义统计指标对应的自定义返回类型 type Stats { dailyTotalSales: Float! @method dailyAverageSales: Float! @method dailyTotalItemsSold: Int! @method newDailyCustomersCount: Int! @method } # 在根Query类型中新增statsReport查询入口 type Query { # 可根据业务需要补充查询入参,比如统计日期范围 statsReport( startDate: Date @eq, endDate: Date @eq ): Stats! @method(class: "App\\GraphQL\\Queries\\StatsReport") }
这里给Stats类型下每个字段加
@method指令的作用,就是告诉Lighthouse:当前字段的解析逻辑,直接调用父返回对象(也就是statsReport查询返回的实例)上与字段名同名的驼峰方法,不需要额外编写resolve逻辑。
3. 编写对应业务解析类
你不需要写一个统一的__invoke方法把所有统计逻辑一次性计算完,只需要把每个字段对应的统计逻辑,拆成StatsReport类的独立方法即可:
<?php namespace App\GraphQL\Queries; class StatsReport { // 对应Stats类型下的dailyTotalSales字段,只有用户请求该字段时才会执行 public function dailyTotalSales(): float { return Sale::whereDate('created_at', today())->sum('total_amount'); } // 对应Stats类型下的newDailyCustomersCount字段,只有用户请求该字段时才会执行 public function newDailyCustomersCount(): int { return Customer::whereDate('created_at', today())->count(); } // 对应其他字段,未被用户请求时完全不会触发执行 public function dailyAverageSales(): float { return Sale::whereDate('created_at', today())->avg('total_amount'); } public function dailyTotalItemsSold(): int { return OrderItem::whereDate('created_at', today())->sum('quantity'); } }
按需加载的核心运行逻辑
这种实现方式天然满足你提出的按需执行需求:
- Lighthouse在执行查询时,会严格按照用户实际请求的字段树逐个触发解析逻辑
- 当用户只请求
dailyTotalSales和newDailyCustomersCount两个字段时,框架只会调用这两个字段对应的类方法,剩下的字段逻辑完全不会执行,不存在一次性计算所有指标的问题 - 根查询
statsReport接收到的入参(比如筛选日期)会自动注入到StatsReport类的构造函数中,每个字段方法都可以直接复用这些公共参数,不需要在每个统计逻辑里重复处理入参
内容的提问来源于stack exchange,提问作者Andrius Solopovas
相关产品推荐
相关产品推荐

