You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Fractal中按关联原始资源对资源集合排序?

实现按最近X天评论数排序并返回统计数的Laravel Fractal方案

我刚好做过类似的需求,给你一步步拆解实现:

1. 先在Post模型里添加动态统计评论数的逻辑

我们需要能够根据传入的天数,计算每个帖子在该时间段内的评论数。可以在Post模型里定义一个作用域,直接在查询时拼接统计字段:

// app/Models/Post.php
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    public function comments()
    {
        return $this->hasMany(Comment::class);
    }

    // 定义作用域,添加最近X天评论数的统计字段
    public function scopeWithRecentCommentCount($query, $days)
    {
        return $query->addSelect([
            'recent_comment_count' => Comment::selectRaw('count(*)')
                ->whereColumn('post_id', 'posts.id')
                ->where('created_at', '>=', now()->subDays($days))
        ]);
    }
}

2. 处理PostTransformer中的include解析

接下来在你的PostTransformer里,解析comment_count:since_days(7)这种带参数的include请求,提取天数后把统计数加入响应:

// app/Transformers/PostTransformer.php
use League\Fractal\TransformerAbstract;

class PostTransformer extends TransformerAbstract
{
    protected $availableIncludes = ['recent_comment_count'];
    protected $days = 7; // 默认天数

    public function transform(Post $post)
    {
        return [
            'id' => $post->id,
            'title' => $post->title,
            'content' => $post->content,
            // 其他基础字段...
        ];
    }

    // 返回最近评论数的原始值
    public function includeRecentCommentCount(Post $post)
    {
        return $this->primitive($post->recent_comment_count);
    }

    // 重写include解析逻辑,提取since_days参数
    public function parseIncludes($includes)
    {
        $parsed = [];
        foreach ($includes as $include) {
            if (strpos($include, ':') !== false) {
                list($name, $params) = explode(':', $include, 2);
                // 匹配since_days(数字)格式的参数
                if (preg_match('/since_days\((\d+)\)/', $params, $matches)) {
                    $this->days = (int)$matches[1];
                    $parsed[] = 'recent_comment_count';
                }
            } else {
                $parsed[] = $include;
            }
        }
        return parent::parseIncludes($parsed);
    }
}

3. 控制器中处理请求参数(include和sort)

在PostsController里,需要解析请求的include和sort参数,构建带统计和排序的查询:

// app/Http/Controllers/Api/PostsController.php
use App\Models\Post;
use App\Transformers\PostTransformer;
use League\Fractal\Manager;
use League\Fractal\Resource\Collection;

class PostsController extends Controller
{
    public function index()
    {
        $fractal = new Manager();
        $request = request();
        $days = 7; // 默认天数
        $sortField = 'id';
        $sortDirection = 'asc';

        // 处理include参数,同时提取天数
        if ($request->has('include')) {
            $fractal->parseIncludes($request->get('include'));
            // 从include参数里提取天数
            if (preg_match('/comment_count:since_days\((\d+)\)/', $request->get('include'), $matches)) {
                $days = (int)$matches[1];
            }
        }

        // 处理sort参数,切换为统计字段排序
        if ($request->has('sort')) {
            list($field, $direction) = explode(':', $request->get('sort'), 2);
            if ($field === 'comment_count') {
                $sortField = 'recent_comment_count';
                $sortDirection = strtolower($direction) === 'desc' ? 'desc' : 'asc';
            }
        }

        // 构建查询:添加统计字段 + 排序
        $posts = Post::withRecentCommentCount($days)
            ->orderBy($sortField, $sortDirection)
            ->get();

        // 转换为Fractal资源并返回
        $resource = new Collection($posts, new PostTransformer());
        $resource->setMeta([
            'stats_period_days' => $days,
            'sort_field' => $sortField,
            'sort_direction' => $sortDirection
        ]);

        return response()->json($fractal->createData($resource)->toArray());
    }
}

4. 测试API请求

现在你可以直接测试目标API了:

GET /api/posts?include=comment_count:since_days(7)&sort=comment_count:desc

响应会包含每个帖子的recent_comment_count字段,并且帖子按最近7天的评论数降序排列。

优化小提示

  • 给comments表的post_id和created_at字段添加联合索引,能大幅提升统计查询的性能;
  • 可以把参数解析逻辑封装成自定义Request类,让控制器代码更简洁;
  • 如果用了Laravel的Fractal集成包,可通过依赖注入直接在Transformer里获取请求实例,简化参数传递。

内容的提问来源于stack exchange,提问作者Horrorente

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:36:42