source-toad/enhanced-resources

增强 Laravel 的 API 资源。

v7.0.0 2024-03-13 12:39 UTC

README

Laravel API 资源的增强。

安装

$ composer require sourcetoad/enhanced-resources

基本用法

要创建一个增强资源,只需扩展 Sourcetoad\EnhancedResources\Resource 而不是 Illuminate\Http\Resources\Json\JsonResource,并提供一个格式方法。

<?php

use Sourcetoad\EnhancedResources\Formatting\Attributes\Format;
use Sourcetoad\EnhancedResources\Resource;

class ExampleResource extends Resource
{
    #[Format]
    public function foo(): array
    {
        return [];
    }
}

格式化

使用 EnhancedResources,您可以为单个资源添加多个格式,只需添加格式方法。格式方法使用 #[Format] 属性定义。

如果只定义了一个格式方法,如上面基本用法部分中的示例,那么该格式将作为默认格式使用,在解析资源时使用。然而,您可以定义任意多个格式。

<?php

use Sourcetoad\EnhancedResources\Formatting\Attributes\Format;
use Sourcetoad\EnhancedResources\Resource;

class ExampleResource extends Resource
{
    #[Format]
    public function bar(): array
    {
        return [];
    }

    #[Format]
    public function foo(): array
    {
        return [];
    }

    #[Format]
    public function foobar(): array
    {
        return [];
    }
}

在上述情况下,您需要通过向 format() 方法提供其名称来指定要使用的格式。默认情况下,格式使用与方法相同的名称,因此在此示例中,我们具有格式名称 barfoofoobar

ExampleResource::make($object)->format('foo');

在未指定默认格式的情况下,将抛出 NoFormatSelectedException

指定默认格式

如果您不想始终显式指定具有多个格式的资源要使用的格式,可以使用 #[IsDefault] 属性指定一个格式作为默认格式。

<?php

use Sourcetoad\EnhancedResources\Formatting\Attributes\Format;
use Sourcetoad\EnhancedResources\Formatting\Attributes\IsDefault;
use Sourcetoad\EnhancedResources\Resource;

class ExampleResource extends Resource
{
    #[Format]
    public function bar(): array
    {
        return [];
    }

    #[IsDefault, Format]
    public function foo(): array
    {
        return [];
    }

    #[Format]
    public function foobar(): array
    {
        return [];
    }
}

添加 #[IsDefault] 属性到您的一个格式方法后,除非通过 format() 方法显式指定格式,否则将使用它。

通过 #[IsDefault] 属性指定多个默认方法将抛出 MultipleDefaultFormatsException

#[IsDefault] 属性在继承链的每个类上都会被检测,因此您可以在父资源上定义一个 #[IsDefault] 格式,并在子资源上使用另一个 #[IsDefault] 格式来覆盖它,而不会触发 MultipleDefaultFormatsException。但是,如果子资源上未定义 #[IsDefault] 格式,则仍将使用父资源上的格式。

命名格式

您还可以覆盖格式的名称,甚至为单个格式提供多个名称。让我们看看以下示例

<?php

use Sourcetoad\EnhancedResources\Formatting\Attributes\Format;
use Sourcetoad\EnhancedResources\Formatting\Attributes\IsDefault;
use Sourcetoad\EnhancedResources\Resource;

class ExampleResource extends Resource
{
    #[Format, Format('a')]
    public function bar(): array
    {
        return [];
    }

    #[Format, Format('b'), Format('something-else')]
    public function foo(): array
    {
        return [];
    }

    #[Format('c')]
    public function foobar(): array
    {
        return [];
    }
}

在此示例中,我们有三个格式,但有六个名称

  • bar 方法可以用 bara 的名称使用。
  • foo 方法可以用 foobsomething-else 的名称使用。
  • foobar 方法可以用 c 的名称使用。

每个格式的首选名称是 #[Format] 属性的第一个实例,其余的是别名。这意味着在上面的示例中,首选名称将是 barfooc。在大多数情况下,这种区别不应发挥作用。

集合

匿名集合和定义的资源集合都利用底层资源对象的格式,并遵循所有相同的规则。

修改

修改允许您动态调整资源的输出。它们的应用方式类似于 Eloquent 工厂中应用 state 的方式。修改的最基本形式是通过向资源的 modify 方法提供一个数组来执行简单的数组合并修改。

ExampleResource::make($object)->modify(['some_key' => 'some_value']);

为了实现更复杂的修改,您还可以传递任何接受(array $data, Resource $resource)的可调用对象。在使用这些类型的修改时,返回数据非常重要,否则资源的数据将被替换为null

ExampleResource::make($object)->modify(function (array $data) {
    $data['some_key'] = 'some_value';
    
    return $data;
})

您还可以在资源类本身上定义方法,通过调用modify方法来进行修改。

<?php

use Sourcetoad\EnhancedResources\Formatting\Attributes\Format;
use Sourcetoad\EnhancedResources\Formatting\Attributes\IsDefault;
use Sourcetoad\EnhancedResources\Resource;

class ExampleResource extends Resource
{
    #[Format]
    public function foo(): array
    {
        return [
            'value' => $this->resource['value'],
        ];
    }
    
    public function double(): static
    {
        return $this->modify(function (array $data) {
            $data['value'] *= 2;
            
            return $data;        
        });
    }
}

ExampleResource::make(['value' => 1])->double()->toArray(); // ['value' => 2]

除了...

异常增强是一个修改类和特性的组合,允许轻松地从资源中排除某些字段。

<?php

use Sourcetoad\EnhancedResources\Enhancements\Except;
use Sourcetoad\EnhancedResources\Enhancements\Traits\HasExceptEnhancement;
use Sourcetoad\EnhancedResources\Formatting\Attributes\Format;
use Sourcetoad\EnhancedResources\Formatting\Attributes\IsDefault;
use Sourcetoad\EnhancedResources\Resource;

class ExampleResource extends Resource
{
    use HasExceptEnhancement;

    #[Format]
    public function foo(): array
    {
        return [
            'first_name' => $this->resource->firstName,
            'id' => $this->resource->id,
            'last_name' => $this->resource->lastName,
        ];
    }
}

ExampleResource::make(new class {
    public string $firstName = 'John';
    public int $id = 1;
    public string $lastName = 'Doe';
})->except('id'); // ['first_name' => 'John', 'last_name' => 'Doe']

// Without the trait you can still use the Except enhancement.
ExampleResource::make(new class {
    public string $firstName = 'John';
    public int $id = 1;
    public string $lastName = 'Doe';
})->modify(new Except(['id'])); // ['first_name' => 'John', 'last_name' => 'Doe']

仅...

仅增强是一个修改类和特性的组合,允许轻松地从资源中排除某些字段。

<?php

use Sourcetoad\EnhancedResources\Enhancements\Only;
use Sourcetoad\EnhancedResources\Enhancements\Traits\HasOnlyEnhancement;
use Sourcetoad\EnhancedResources\Formatting\Attributes\Format;
use Sourcetoad\EnhancedResources\Formatting\Attributes\IsDefault;
use Sourcetoad\EnhancedResources\Resource;

class ExampleResource extends Resource
{
    use HasOnlyEnhancement;

    #[Format]
    public function foo(): array
    {
        return [
            'first_name' => $this->resource->firstName,
            'id' => $this->resource->id,
            'last_name' => $this->resource->lastName,
        ];
    }
}

ExampleResource::make(new class {
    public string $firstName = 'John';
    public int $id = 1;
    public string $lastName = 'Doe';
})->only('id'); // ['id' => 1]

// Without the trait you can still use the Only enhancement.
ExampleResource::make(new class {
    public string $firstName = 'John';
    public int $id = 1;
    public string $lastName = 'Doe';
})->modify(new Only(['id'])); // ['id' => 1]

其他增强

EnhancedResources还包括一些其他有用的增强。

状态码

现在,您可以通过调用setResponseStatus()方法简单地调整资源响应的状态码。

use Symfony\Component\HttpFoundation\Response;

ExampleResource::make($object)->setResponseStatus(Response::HTTP_I_AM_A_TEAPOT);

ConvertsToResource

您可以通过简单的特性和属性组合为任何具有toResource方法的对象提供。

use Illuminate\Database\Eloquent\Model;
use Sourcetoad\EnhancedResources\Resourceable\AsResource;
use Sourcetoad\EnhancedResources\Resourceable\ConvertsToResource;

/**
 * @method ExampleResource toResource()
 */
#[AsResource(ExampleResource::class)]
class Example extends Model
{
    use ConvertsToResource;
}

(new Example)->toResource();

测试

建议使用Laravel现有的响应断言来测试返回增强资源的端点。一种创建资源断言对象的方法,该方法利用了增强资源提供的功能,可以在以下链接中找到:这里