定制 jcfrane/laravel-resource-scope 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

jcfrane/laravel-resource-scope

Composer 安装命令:

composer require jcfrane/laravel-resource-scope

包简介

Symfony-like serialization scoping for Laravel API Resources. Define scopes to control which fields are returned per context.

README 文档

README

Tests Latest Stable Version License

Control which fields your Laravel API Resources return based on context. Define scopes like listing, detail, or summary and let the frontend request only the data it needs.

Inspired by Symfony's serialization groups.

Requirements

  • PHP 8.2+
  • Laravel 11, 12, or 13

Installation

composer require jcfrane/laravel-resource-scope

The package auto-discovers its service provider. No manual registration needed.

Publish Config (Optional)

php artisan vendor:publish --tag=resource-scope-config

Quick Start

1. Add the trait to your resource

use JCFrane\ResourceScope\Concerns\HasResourceScope;

class UserResource extends JsonResource
{
    use HasResourceScope;

    protected function scopeDefinitions(): array
    {
        return [
            'listing' => ['id', 'name', 'email', 'avatar'],
            'detail'  => ['id', 'name', 'email', 'avatar', 'bio', 'created_at', 'settings'],
        ];
    }

    public function toArray(Request $request): array
    {
        return $this->scoped([
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'avatar' => $this->avatar_url,
            'bio' => $this->bio,
            'created_at' => $this->created_at,
            'settings' => $this->whenLoaded('settings'),
        ]);
    }
}

2. Register the middleware

In bootstrap/app.php:

->withMiddleware(function (Middleware $middleware) {
    $middleware->api(append: [
        \JCFrane\ResourceScope\Middleware\SetResourceScope::class,
    ]);
})

Or apply it to specific route groups:

Route::middleware('resource.scope')->group(function () {
    Route::apiResource('users', UserController::class);
});

3. Request scoped data

# Listing — returns only id, name, email, avatar
GET /api/users?scope=listing

# Detail — returns all detail fields
GET /api/users/1?scope=detail

# No scope — returns everything (backwards compatible)
GET /api/users

You can also pass the scope via header:

X-Resource-Scope: listing

Defining Scopes

Method-based (recommended)

Define a scopeDefinitions() method that returns scope name => allowed field keys:

protected function scopeDefinitions(): array
{
    return [
        'listing' => ['id', 'name', 'email'],
        'detail'  => ['id', 'name', 'email', 'bio', 'skills', 'documents'],
    ];
}

Attribute-based

Use PHP 8 attributes on the resource class:

use JCFrane\ResourceScope\Attributes\ResourceScope;

#[ResourceScope('listing', fields: ['id', 'name', 'email'])]
#[ResourceScope('detail', fields: ['id', 'name', 'email', 'bio', 'skills', 'documents'])]
class UserResource extends JsonResource
{
    use HasResourceScope;

    public function toArray(Request $request): array
    {
        return $this->scoped([
            // ...
        ]);
    }
}

If both are present, scopeDefinitions() takes priority.

Scope Cascading

When a resource contains nested resources, you can control how scopes propagate. There are two ways to define mappings:

Method-based mappings

class PostResource extends JsonResource
{
    use HasResourceScope;

    protected function scopeDefinitions(): array
    {
        return [
            'listing' => ['id', 'title', 'author', 'created_at'],
        ];
    }

    protected function scopeMappings(): array
    {
        return [
            'listing' => [
                UserResource::class => 'summary',
            ],
        ];
    }

    public function toArray(Request $request): array
    {
        return $this->scoped([
            'id' => $this->id,
            'title' => $this->title,
            'body' => $this->body,
            'author' => new UserResource($this->whenLoaded('author')),
            'created_at' => $this->created_at,
        ]);
    }
}

Attribute-based mappings

You can also define mappings directly in the #[ResourceScope] attribute using the mappings parameter:

use JCFrane\ResourceScope\Attributes\ResourceScope;

#[ResourceScope('listing', fields: ['id', 'title', 'author', 'created_at'], mappings: [
    UserResource::class => 'summary',
])]
#[ResourceScope('detail', fields: ['id', 'title', 'body', 'author', 'created_at'])]
class PostResource extends JsonResource
{
    use HasResourceScope;

    public function toArray(Request $request): array
    {
        return $this->scoped([
            'id' => $this->id,
            'title' => $this->title,
            'body' => $this->body,
            'author' => new UserResource($this->whenLoaded('author')),
            'created_at' => $this->created_at,
        ]);
    }
}

When the listing scope is active on PostResource, the nested UserResource will automatically use the summary scope.

If both scopeMappings() method and attribute mappings are present, the method takes priority. If no mapping is defined, the parent's scope name passes through to nested resources. If the nested resource doesn't define that scope, it returns all fields.

Works with Laravel's Conditional Fields

Scoping works alongside whenLoaded(), whenHas(), and when(). Both conditions apply — Laravel's conditional checks run first, then scoping filters the keys:

return $this->scoped([
    'id' => $this->id,
    'name' => $this->name,
    'documents' => DocumentResource::collection($this->whenLoaded('documents')),
    'is_admin' => $this->when($user->isAdmin(), true),
]);

Backwards Compatible

  • No scope parameter = all fields returned (existing behavior)
  • Scope not defined on a resource = all fields returned
  • Unknown scope name = all fields returned

No breaking changes to existing API responses.

Configuration

Published config file (config/resource-scope.php):

return [
    // Query parameter name (default: 'scope')
    'query_param' => 'scope',

    // HTTP header name (default: 'X-Resource-Scope')
    'header' => 'X-Resource-Scope',

    // Query param takes priority over header (default: true)
    'query_param_priority' => true,
];

Testing

composer test

License

MIT

统计信息

  • 总下载量: 598
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 8
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 8
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-02-18

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固