CursorPaginator测试异常求助:仅测试环境报错,浏览器特定条目数失效
解决CursorPaginator测试报错:
Only arrays and objects are supported when cursor paginating items. 结合你的场景,我分享下排查思路和可能的解决方案,我之前也遇到过类似的诡异问题:
1. 先确认排序字段的数据库存储精度
你提到已经确认创建时间的毫秒数不同,但要注意:如果你的entries表中created_at字段不是datetime(6)(支持毫秒存储)类型,数据库会自动截断毫秒部分,导致实际存储的时间仍可能重复。
CursorPaginator完全依赖排序字段的唯一性来生成游标,如果排序值重复,在分页到非满页(比如6条数据分两页,第二页仅1条)时,内部可能出现数据结构异常,触发这个类型错误。
检查与修复:
- 查看
entries表的迁移文件,确认时间字段定义:$table->datetime('created_at')->useCurrent()->precision(6); $table->datetime('updated_at')->useCurrent()->useCurrentOnUpdate()->precision(6); - 如果之前没有设置
precision(6),修改迁移并重新执行(记得备份数据)。
2. 排查through方法的潜在影响
你在控制器中用through给模型添加额外属性,虽然看起来返回的是模型实例,但CursorPaginator在处理分页数据时,对through后的集合有特殊的内部逻辑,尤其是在处理单条数据的非满页场景下,可能触发类型识别异常。
替代方案:
把额外属性的逻辑移到模型层面,避免在分页器中修改实例:
// Entry模型中添加 protected $appends = ['can_edit', 'can_delete']; public function getCanEditAttribute() { return auth()->user()?->can('update', $this->content); } public function getCanDeleteAttribute() { return auth()->user()?->can('delete', $this->content); }
然后简化控制器代码:
return $item->entries() ->latest() ->with(['content','user']) ->cursorPaginate(5) ->withPath("/items/$item->id/notes/more");
3. 测试中打印请求详情定位问题
在测试代码中添加日志,确认第二页的请求参数和返回数据结构:
public function testMoreNotesAreReturnedIfRequested() { $item = Item::factory()->has(Entry::factory()->for($this->user)->count(6))->create(); $response = $this->actingAs($this->user)->json('get',"/items/{$item->id}/notes/more"); $nextUrl = $response->decodeResponseJson()['next_page_url']; // 打印URL检查游标参数是否正常 dump($nextUrl); $next = $this->actingAs($this->user)->json('get',$nextUrl); // 打印返回内容,确认data字段的结构 dump($next->decodeResponseJson()); $next->assertJson(fn (AssertableJson $json) => $json ->has('data') ->has('paginator')); }
如果data字段是空或非集合类型,那大概率是游标查询的逻辑出了问题。
4. 查看测试环境的实际查询语句
开启Laravel查询日志,看看第二页的游标查询是否符合预期:
// 在测试中添加 DB::enableQueryLog(); $next = $this->actingAs($this->user)->json('get',$nextUrl); dump(DB::getQueryLog());
通过日志可以确认CursorPaginator生成的查询是否正确过滤了数据,有没有出现不符合预期的结果。
为什么浏览器只在特定条目数失效?
这是因为6、7、16、17这类条目数会生成非满页的第二页(比如6条数据分两页,第二页仅1条),此时CursorPaginator的内部处理逻辑更容易触发隐藏bug;而满页场景(比如10条数据分两页,每页5条)不会触发这个问题。
内容的提问来源于stack exchange,提问作者Rory
相关产品推荐
相关产品推荐

