修改 Laravel 模型响应以使用不同的 ID

Modify Laravel model response to use different ID

我希望在将模型发送回客户端之前进行某种“拦截”并更改模型中的字段。我有一个 API 端点类似于以下内容:

Route::get('users/{user}', 'Api\UserController@user');

我的应用程序使用vinkla/laravel-hashids,所以就客户端应用程序而言,要查询的ID 应该是K6LJwKJ1M8,而不是1。目前我可以查询提供 hash-id 的用户,但响应返回 numeric/auto-incrementing ID。

例如对于 /api/users/K6LJwKJ1M8 之类的查询,我收到以下响应:

{
    "id": 1,
    "address": null,
    "telephone": null,
    "name": "TestNameHere",
    "description": null,
    ...
}

在 Laravel 中是否有一种好方法可以修改响应中返回的所有用户对象以使用 vinkla/laravel-hashids ID,而不是自动递增的 ID?

理想情况下,上述响应将变为:

{
    "id": K6LJwKJ1M8,
    "address": null,
    "telephone": null,
    "name": "TestNameHere",
    "description": null,
    ...
}

我在想使用 getRouteKey 之类的东西会起作用,但它不会更改 JSON 响应中发送的对象。

例如

public function getRouteKey() {
    return Hashids::encode($this->attributes['id']);
}

如果有一个地方可以改变这个就好了,因为我的应用程序有大约 40 条不同的路线,否则我需要“手动”改变(例如,在发送响应之前做一些像 $user->id = Hashids::encode($id))

您可以使用 API 资源 https://laravel.com/docs/7.x/eloquent-resources#introduction

API Resource acts as a transformation layer that sits between your Eloquent models and the JSON responses that are actually returned to your application's users.

您可以为用户创建一个 API 资源,并在响应中 return 用户的任何地方使用它。

Api 资源给了你更多的控制权,你可以操纵你想要的任何字段,使用几个字段的组合发送一些额外的字段,更改你想要在响应中的字段的名称(xyz => $this->name)

用户资源

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray($request)
    {
        //You can access model properties directly using $this
        return [
            'id' => Hashids::encode($this->id),
            "address": $this->address,
            "telephone": $this->telephone,
            "name": $this->name,
            "description": $this->description,
             ...
        ];
    }
}

然后在任何地方 return 一个用户实例。

控制器

// $user is a User Model Instance.

return new UserResource($user); 

如果你有 collection

// $users is a collection of User Model instances.

return UserResource::collection($users);

UserResource 将应用于您 collection 中的每个模型实例,然后 return 作为您的 JSON 响应发送给您。

要实现您想要的效果,在您的模型中,您必须使用 set getIncrementing to false 并确保 getKeyType 设置为 string

class YourModel extends Model
{
    public function getIncrementing()
    {
        return false;
    }

    public function getKeyType()
    {
        return 'string';
    }
}

如果您使用的是 uuid 并且迁移文件中包含以下内容,则以上内容有效:

$table->uuid('id')->primary();

您可能必须找到一种方法来修改包以使用此方法。

您可以实施 CastsAttributes interface:

Classes that implement this interface must define a get and set method. The get method is responsible for transforming a raw value from the database into a cast value, while the set method should transform a cast value into a raw value that can be stored in the database.

在您的 app 目录中创建一个名为 Casts 的目录并创建一个名为 UserCode:

的 class
namespace App\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use ...\Hashids;

class UserCode implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        return Hashids::encode($value);
    }

    public function set($model, $key, $value, $attributes)
    {
        return Hashids::decode($value);
    }
}

然后在您的用户模型中将 UserCode 添加到 id 值:

use App\Casts\UserCode; // <--- make sure to import the class
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected $casts = [
        'id' => UserCode::class,
    ];
}

然后,如果您执行 User::find(1)->id,您将获得散列值或访问 /user/1,它将 return 具有散列 ID 的用户。 credit.

请注意,您无法通过散列 ID 找到用户,除非您实施了某些操作,例如/user/hashed_id 将给出 404。