Home  >  Article  >  PHP Framework  >  Teach you how Laravel automatically converts long integer snowflake ID to string

Teach you how Laravel automatically converts long integer snowflake ID to string

藏色散人
藏色散人forward
2020-11-03 15:06:072690browse

The following tutorial column will introduce you to the method of Laravel automatically converting long integer snowflake IDs into strings. I hope it will be helpful to friends in need! When designing an API, for reasons such as security, it is sometimes necessary to abandon the use of auto-incrementing IDs to make the IDs non-continuous and unguessable. This can usually be achieved using Hash id, UUID, Snowflake ID, etc. In a recent project, I tried using Snowflake ID. After a lot of fiddling around, I found that the performance is quite high and the implementation is quite simple. However, when I continued to roll up my sleeves and connect with the front-end part, the problem of JS precision loss occurred because the stored ID was an unsigned bigint value. (As for why there is a loss of accuracy, I will not explain it in detail here. If you are not sure, you can search it by yourself). This article mainly introduces solutions.

To solve this problem, the basic principle is very simple, that is, convert the ID into a string and then return it to the front end.

Bad Attempt

At first I thought of using the model accessor of the Laravel Eloquent model. Just add a getIdAttribute to the model that needs to be converted, and convert the ID into a string, right? For example: App\Models\User model writes this:

/**

 * @return string

 */public function getIdAttribute(){

    return strval($this->attributes['id']);}

But this is not the case. The attribute accessor can indeed make the ID returned by the API to the front end become a string. But it will also affect the results of inserting and modifying the associated model. For example, if user is associated with the post model, use $user->posts()->saveMany(…); to save new posts records in this way. The corresponding user_id will be empty.

This is not difficult to understand, because the model accessor needs to participate in model-related processing. The accessor converts the ID from a number to a string, which will naturally lead to data confusion.

Correct posture

Calm down and decide to think carefully before taking action. After checking the official documents, I found that Resource is exactly what I want. Resource will only affect the data returned to the front end. We can customize the Resource to implement the structure, type conversion and other functions of the API return results. It's easy to change IDs. To save trouble, I directly modify the App\Http\Resource base class. Just overload its toArray() method and use recursion to convert values ​​that may exceed the safe range of JS. You can also create a new Resource class, such as UserResource, according to your actual situation.

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class Resource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param \Illuminate\Http\Request $request
     *
     * @return array
     */
    public function toArray($request)
    {
        $parentReturn = parent::toArray($request);

        foreach (array_keys($parentReturn) as $key) {
            // 为方便演示这里把所有整型字段都转成字符串
            if (is_int($parentReturn[$key])) {
                $parentReturn[$key] = strval($parentReturn[$key]);
            }

            // 关联的字段,如 $user->post,相当于递归处理
            if (is_array($parentReturn[$key])) {
                $parentReturn[$key] = new Resource($parentReturn[$key]);
            }
        }

        return $parentReturn;
    }
}

Then, return Resource in the interface controller to return data, and the integer field value will automatically become a string.

<?php

namespace App\Http\Controllers;

use App\Http\Resources\Resource;

use App\Models\User;

use Illuminate\Http\Request;

class TestController extends Controller
{
    /**
     * @return \App\Http\Resources\Resource
     */
    public function __invoke(Request $request)
    {
        $user = User::first();
        return new Resource($user);
    }
}

The result is as shown below:


Laravel 自动转换长整型雪花 ID 为字符串Notes

Because this method uses traversal , and there is recursive processing, which may have a certain impact on performance when the data structure is complex and the amount of data is large. I think this is a lazy way of writing it. If you are pursuing performance, it would be better to customize the Resource class and then convert it based on the specific known field name

  • Because it is returned to The front-end ID is converted to a string, and the front-end needs to pay special attention when making comparison judgments, especially === judgments

The above is the detailed content of Teach you how Laravel automatically converts long integer snowflake ID to string. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:learnku.com. If there is any infringement, please contact admin@php.cn delete