2

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

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

我的应用程序使用vinkla/laravel-hashids,因此就客户端应用程序而言,要查询的 ID 应该类似于K6LJwKJ1M8,而不是1。目前,我可以查询提供哈希 ID 的用户,但响应返回的是数字/自动递增 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,
    ...
}

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

例如

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

如果有一个地方可以更改它会很好,因为我的应用程序有大约 40 条不同的路由,否则我需要“手动”更改(例如,在发送响应之前执行类似的操作$user->id = Hashids::encode($id)

4

3 回答 3

2

您可以实现CastsAttributes 接口

实现此接口的类必须定义 get 和 set 方法。get 方法负责将数据库中的原始值转换为转换值,而 set 方法应将转换值转换为可以存储在数据库中的原始值。

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

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);
    }
}

然后在您的用户模型中将强制转换添加UserCodeid值中:

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它将返回具有散列 ID 的用户。信用

请注意,您无法通过散列 id 找到用户,除非您实现了某些东西,例如/user/hashed_id会给出 404。

于 2020-08-01T19:28:15.660 回答
1

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

API 资源充当转换层,位于 Eloquent 模型和实际返回给应用程序用户的 JSON 响应之间。

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

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,
             ...
        ];
    }
}

然后在任何你想返回用户实例的地方。

控制器

// $user is a User Model Instance.

return new UserResource($user); 

如果你有收藏

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

return UserResource::collection($users);

UserResource 将应用于您集合中的每个模型实例,然后作为您的 JSON 响应返回给您。

于 2020-08-01T17:13:13.253 回答
1

为了实现你想要的,在你的模型中,你必须使用 set getIncrementingtofalse和 ensure getKeyTypeis set to string

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

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

如果您正在使用uuid并在迁移文件中包含以下内容,则上述内容将起作用:

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

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

于 2020-08-01T17:38:05.907 回答