slime-systems/eloquent-object-id
Composer 安装命令:
composer require slime-systems/eloquent-object-id
包简介
MongoDB-style BSON's ObjectId for Eloquent and Laravel. Provides unique, chronologically ordered IDs.
关键字:
README 文档
README
MongoDB-style BSON's ObjectId for Eloquent and Laravel.
✨ Features
- Decentralized Generation: Create IDs on the fly without hitting the database.
- No Collisions: Statistically unique IDs for distributed systems.
- Chronological Sorting: IDs are naturally ordered.
- High Performance: Storage-efficient binary-packed format results in better indexing and faster queries.
- Batteries Included: Integrated with Laravel’s Eloquent ORM.
📦 Installation
Install the package via Composer:
composer require slime-systems/eloquent-object-id
🤔 Why ObjectIDs?
Before diving into how to use ObjectIDs, it's important to understand why they are so useful. The ObjectID is a remarkable invention, offering significant benefits beyond a simple unique identifier.
The Basic
An ObjectID is a type of identifier, similar to Eloquent’s default incremental ID, used to reference a specific entity in the system.
ObjectIDs are powerful because they can be generated independently and in a decentralized manner by any trusted party. This eliminates the need to rely on a database or a centrally managed registry during ID creation. The generated IDs are designed to be sufficiently unique for most use cases, making collisions highly unlikely.
ObjectID is More Than a Generic ID
ObjectIDs inherently contain a timestamp. This property is extremely useful, for example, when performing time-based queries:
Suppose we want to count the cats registered in the past week:
$end = Carbon::now('Asia/Tokyo')->startOfWeek(); $start = ObjectId::fromTime($end->subWeek(), unique: false); $end = ObjectId::fromTime($end, unique: false); $lastWeekCatCount = Cat::where('id', '>=', OI::val($start)) ->where('id', '<', OI::val($end)) ->count(); // Don't worry about the utility functions just yet; we'll cover them shortly.
If the ObjectID is set as the primary key, there is no need for a separate index to perform these time-based lookups. This query will be as optimized as one using an indexed created_at field, entirely avoiding a full table scan.
Essentially, ObjectIDs offer the querying power of timestamps directly within the identifier.
ObjectID is Also More Than Just a Timestamp
The ability to use the ID for chronological and offset-based queries is crucial for efficient pagination (known as keyset or cursor pagination).
A common, but highly unoptimized, way to paginate with an offset in Eloquent is:
Cat::orderBy('created_at', 'asc') ->skip(20000 * $perPage) // Fetch page 20,000 of the registry ->limit($perPage) ->get();
The skip (or OFFSET) clause prevents database indexes from being fully utilized, leading to very slow queries on large datasets.
A better approach is to use the last known ID to fetch the next page, which works great with unique, chronologically ordered incremental IDs:
Cat::where('id', '>', $lastKnownCat->id) ->orderBy('id') ->limit($perPage) ->get();
This query is fast because the where('id', '>', ...) condition can efficiently leverage the primary key index for lookup.
Attempting the same with only a timestamp field has a critical flaw:
Cat::where('created_at', '>', $lastKnownCat->created_at) ->orderBy('created_at') ->limit($perPage) ->get();
While this could be fast if created_at is indexed, the logic is broken because the created_at timestamp is not guaranteed to be unique. If two entities are created in the same second, this query might incorrectly skip or miss records.
Guess what else is chronologically ordered and guaranteed to be unique?
Cat::where('id', '>', OI::val($lastKnownCat->id)) ->orderBy('id') ->limit($perPage) ->get();
That's right: ObjectID!
ObjectID is Also More Than an Incremental ID
A major limitation of traditional keyset (or cursor) pagination, when relying only on a sequential incremental ID, is the inability to jump to an arbitrary point in the dataset; users must navigate linearly from the start or from a known cursor.
This is where the ObjectID's embedded timestamp provides a unique advantage, transforming the approach to pagination by enabling chronological chunking and navigation.
The embedded time component allows developers to define predictable boundaries in the collection—like the start of a month or year—and generate an optimized cursor for that boundary without needing to query for a specific ID first.
This capability unlocks powerful UX patterns:
- Archival Navigation: Users can view a collection organized into monthly or yearly "archive boxes" (e.g., "See all posts from December 2024"), making large datasets feel organized and intuitive.
- Time-Based Jumping: Users can instantly jump to a specific time in a feed (e.g., a social media feed or log history) instead of scrolling endlessly.
- Keyset Efficiency Retained: Regardless of the time-based jump, the subsequent fetching of records remains fast because it leverages the index.
In essence, ObjectID provides the efficient scanning of incremental IDs while adding the random-access power of an embedded timestamp, making complex archival navigation simple and performant.
Various Ways to Utilize This Invention
As demonstrated, the ObjectID gives you the best of what both a timestamp and a unique, incremental ID have to offer. There is more than one way to utilize this powerful identifier. Have fun explore its full potential!
Note on Usage
In the following section, I will use ObjectID as a drop-in replacement for Eloquent's incremental ID.
While I do provide the helper function OI::setDefault, I personally do not believe this is the most effective or interesting way to utilize ObjectIDs.
If you bring forth the ObjectID's full potential, you'll likely find yourself not needing to use OI::setDefault at all.
🚀 Usage
Database Migration
Use the objectId column type in your migrations. This creates a binary column suitable for storing the ObjectId.
use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; Schema::create('cats', function (Blueprint $table) { $table->objectId('id')->primary(); // <- here $table->string('name'); });
Model Setup
In your Eloquent model, cast the field using SlimeSystems\EloquentObjectId\ObjectIdCast.
use Illuminate\Database\Eloquent\Model; use SlimeSystems\EloquentObjectId\ObjectIdCast; class Cat extends Model { public $timestamps = false; protected $guarded = []; // for demonstration purposes protected $casts = [ 'id' => ObjectIdCast::class, ]; }
Auto-generating IDs
Models can be configured to autogenerate an ObjectId. An example using the OI::setDefault helper in the booted method is provided below.
use Illuminate\Database\Eloquent\Model; use SlimeSystems\EloquentObjectId\ObjectIdCast; use SlimeSystems\EloquentObjectId\OI; class Cat extends Model { protected $casts = [ 'id' => ObjectIdCast::class, ]; protected static function booted() { static::creating(OI::setDefault('id')); // <- here } }
Accessing the ID from models
The ID will be automatically cast to SlimeSystems\ObjectId when retrieved from the database.
use SlimeSystems\ObjectId; // Create with auto-generated ID $cat = Cat::create(['name' => 'Luna']); // Create with explicit ID $id = new ObjectId; Cat::create(['id' => $id, 'name' => 'Peanut']); // Examples $cat = Cat::latest()->first(); $cat->id->toString(); // a hex string $id->equals($cat->id); // true
You can access all SlimeSystems\ObjectId methods documented at https://github.com/slime-systems/php-object-id.
Querying
OI::val() can be used to ensure that ObjectId is correctly formatted for compatibility with Eloquent queries.
use SlimeSystems\EloquentObjectId\OI; use SlimeSystems\ObjectId; $someId = new ObjectId; // Find by ID $cat = Cat::find(OI::val($someId)); // Comparison queries $cats = Cat::where('id', '>', OI::val($someId))->get(); // `::val` also ensures compatibility with hexadecimal and binary formats of ObjectId $cat = Cat::find(OI::val('0123456789abcdef1011121')); // <- this works, but probably doesn't make sense in terms of value // Please note that the ID object itself is not compatible with Eloquent $cat = Cat::find($someId); // <- this doesn't work; Eloquent won't understand what to do with the object.
✅ Tests
composer run test
or if you have containerd:
make test
📄 License
This library is open-sourced software licensed under the BSD-2-Clause license.
slime-systems/eloquent-object-id 适用场景与选型建议
slime-systems/eloquent-object-id 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 0 次下载、GitHub Stars 达 1, 最近一次更新时间为 2025 年 11 月 21 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「mongodb」 「pagination」 「id」 「uuid」 「laravel」 「identifier」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 slime-systems/eloquent-object-id 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 slime-systems/eloquent-object-id 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 slime-systems/eloquent-object-id 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Generates Symfony2 documents, forms and CRUD
DrUUID RFC 4122 library for PHP
Trait to generate uuid when creating models
A package to allow laravel/passport use with mongodb/laravel-mongodb
MongoDB Adapter to be used with Laminas Paginator
Mapper for accessing resources in KWCMS
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 33
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: BSD-2-Clause
- 更新时间: 2025-11-21
