【问题标题】:Modify Laravel model response to use different ID修改 Laravel 模型响应以使用不同的 ID
【发布时间】:2020-08-01 17:08:40
【问题描述】:

我正在寻找某种“拦截”并在模型中的字段发送回客户端之前对其进行更改。我有一个 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,
    ...
}

我在想像使用 getRouteKey 这样的东西会起作用,但它不会改变 JSON 响应中发送的对象。

例如

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

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

【问题讨论】:

  • 例如,您为什么不在 db hashid 中再添加一列,并通过 getRouteKey 方法开箱即用地使用它。对于您关于响应的问题,最好使用 Resource 类,您可以在其中根据需要设置结构。另一种选择是模型中的 toArray() 方法。

标签: php laravel laravel-7 hashids


【解决方案1】:

你可以实现CastsAttributes interface:

实现此接口的类必须定义 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);
    }
}

然后在您的用户模型中将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)-&gt;id,您将获得散列值或访问/user/1,它将返回具有散列ID 的用户。 credit.

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

【讨论】:

    【解决方案2】:

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

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

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

    Api 资源为您提供了更多的控制权,您可以操作您想要的任何字段,使用几个字段的组合发送一些额外的字段,更改您在响应中想要的字段的名称 (xyz =&gt; $this-&gt;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 响应返回给您。

    【讨论】:

      【解决方案3】:

      要实现您想要的,在您的模型中,您必须使用 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();
      

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

      【讨论】:

        猜你喜欢
        • 2016-01-07
        • 2017-08-11
        • 2015-11-05
        • 1970-01-01
        • 2017-05-03
        • 2015-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多