Skip to content

Commit 7e08010

Browse files
committed
docs: update README.md
1 parent 60323ec commit 7e08010

File tree

1 file changed

+120
-79
lines changed

1 file changed

+120
-79
lines changed

README.md

+120-79
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,106 @@
1-
# Laraflake
2-
31
<p align="center">
4-
<img src="/art/laraflake.webp" alt="Laraflake" style="width:40%;">
2+
<img src="/art/laraflake.webp" alt="Laraflake" style="width:35%;">
53
</p>
4+
<p align="center">Generate X/Twitter <a href="https://en.wikipedia.org/wiki/Snowflake_ID">Snowflake identifiers</a> in Laravel.</p>
65

7-
This package enables a Laravel application to create [Snowflake IDs](https://en.wikipedia.org/wiki/Snowflake_ID).
8-
It is a very thin wrapper around the excellent [godruoyi/php-snowflake](https://github.com/godruoyi/php-snowflake) library.
96

107
## What are Snowflakes?
118

129
Snowflakes are a form of unique identifier devised by X/Twitter and are used by many companies, including Instagram and Discord, to generate unique IDs for their entities.
1310

1411
Some of the benefits of using Snowflakes (over alternatives such as UUID/ULID) include:
1512

16-
- They consist entirely of integers.
17-
- They use less space (16 characters, so it fits in a `BIGINT`).
18-
- Indexing of integers is much faster than indexing a string.
19-
- Keys begin with a timestamp, so are sortable.
20-
- Keys end with a random number, so guessing table size is not possible.
21-
- Databases handle integers more efficiently than strings.
22-
- Generation of new keys is faster (less than 1 ms).
13+
- **Timestamp Component:** Extract creation time directly from the ID.
14+
- **Uniqueness Across Distributed Systems:** Ensures unique IDs without coordination.
15+
- **Orderability:** Roughly ordered by creation time for easy sorting.
16+
- **Compactness:** 64-bit size, more compact than 128-bit UUIDs.
17+
- **Performance:** Faster and less resource-intensive generation.
18+
- **Configurability:** Flexible bit allocation for specific needs.
19+
- **Storage Efficiency:** More efficient storage compared to larger identifiers.
20+
- **Database Indexing:** Faster indexing and query performance.
21+
- **Human Readability:** More compact and readable than longer identifiers.
2322

2423
## Installation
2524

26-
Pull in the package using Composer:
25+
First pull in the package using Composer:
2726

2827
```bash
2928
composer require calebdw/laraflake
3029
```
3130

32-
## Configuration
33-
34-
Snowflake includes a configuration file with several settings that you can use to initialize the Snowflake service.
35-
You should begin by publishing this configuration file:
31+
And then publish the package's configuration file:
3632

3733
```bash
38-
php artisan vendor:publish
34+
php artisan vendor:publish --provider="CalebDW\Laraflake\ServiceProvider"
3935
```
4036

37+
## Configuration
38+
4139
### Snowflake Epoch
4240

4341
The 41-bit timestamp encoded in the Snowflake is the difference between the time of creation and a given starting epoch/timestamp.
4442
Snowflakes can be generated for up to 69 years past the given epoch.
45-
46-
The default epoch is `2024-01-01`, but in most cases you should set this value to the current date using a format of `YYYY-MM-DD`.
43+
In most cases you should set this value to the current date using a format of `YYYY-MM-DD`.
4744

4845
> **Note**:
49-
> Do not set the timestamp to a date in the future, as that won't achieve anything.
50-
> You should also avoid using a date far in the past (such as the Unix epoch `1970-01-01`), as that may reduce the number of years for which you can generate timestamps.
46+
> Future dates will throw an error and you should avoid using a date far in the past (such as the Unix epoch `1970-01-01`)
47+
as that may reduce the number of years for which you can generate timestamps.
5148

5249
### Data Center & Worker IDs
5350

54-
If using a distributed architectural setup, you'll need to set the data center and worker IDs that the application should use when generating Snowflakes.
55-
These are both set to `0` by default, as that is a good starting point, but you are free to increase these numbers as you add more workers and data centers.
56-
57-
The maximums for each of these configuration values is `31`. This gives you up to 32 workers per data center, and 32 data centers in total.
58-
Therefore, you can have up `1024` workers each generating unique Snowflakes.
59-
60-
### Sequence resolver
61-
62-
In order to handle the generation of unique keys within the same millisecond, the service uses a sequence resolver.
63-
There are several to choose from, however they each have dependencies, such as Redis.
64-
You are free to use any of them, however the default option is a good choice, as it **doesn't** have any dependencies.
51+
If using distributed systems, you'll need to set the data center and worker IDs that the application should use when generating Snowflakes.
52+
These are used to ensure that each worker generates unique Snowflakes and can range from `0` to `31` (up to `1024` unique workers).
6553

6654
## Usage
6755

68-
> **WARNING**: Do not create new instances of the Snowflake service, as doing so risks generating matching keys / introducing collisions.
69-
> Instead, always resolve the Snowflake singleton out of the container. You can also use the global helper method (see below).
56+
> **WARNING**: Do not create new instances of the Snowflake generator (as this could cause collisions), always use the Snowflake singleton from the container.
7057
71-
72-
You can generate a Snowflake by resolving the service out of the container and calling its `id` method:
73-
Since this is a little cumbersome, the package also registers a global `snowflake()` helper method that you can use anywhere.
58+
You can generate a Snowflake by resolving the singleton from the container and calling its `id` method:
7459

7560
```php
76-
<?php
61+
use Godruoyi\Snowflake\Snowflake;
62+
63+
resolve('snowflake')->id(); // (string) "5585066784854016"
64+
resolve(Snowflake::class)->id(); // (string) "5585066784854016"
65+
```
66+
This package also provides a `snowflake` helper function, a `Snowflake` facade, and a `Str` macro for convenience:
7767

78-
declare(strict_types=1);
68+
```php
7969
use CalebDW\Laraflake\Facades\Snowflake;
8070
use Illuminate\Support\Str;
8171

82-
resolve('snowflake')->id(); // (string) "5585066784854016"
83-
snowflake()->id(); // (string) "5585066784854016"
84-
Snowflake::id(); // (string) "5585066784854016"
72+
snowflake()->id(); // (string) "5585066784854016"
73+
Snowflake::id(); // (string) "5585066784854016"
8574
Str::snowflakeId(); // (string) "5585066784854016"
8675
```
8776

88-
## Databases
89-
90-
If you want to use Snowflakes in your database e.g. for primary and foreign keys, then you'll need to perform a couple of steps.
91-
92-
First, modify your migrations so that they use the Snowflake migration methods e.g.
93-
94-
```php
95-
<?php
77+
### Eloquent Integration
9678

97-
declare(strict_types=1);
79+
#### Migrations
9880

99-
// Before
100-
$table->id();
101-
$table->foreignId('user_id');
102-
$table->foreignIdFor(User::class);
103-
104-
// After
105-
$table->snowflake()->primary();
106-
$table->foreignSnowflake('user_id');
107-
$table->foreignSnowflakeFor(User::class);
108-
```
81+
This package provides a set of migration macros to make it easier to work with Snowflakes in your database schema.
10982

11083
Here's an example:
11184

11285
```php
113-
<?php
114-
11586
return new class extends Migration
11687
{
117-
public function up()
88+
public function up(): void
11889
{
119-
Schema::create('posts', function(Blueprint $table) {
90+
Schema::create('comments', function(Blueprint $table) {
12091
$table->snowflake()->primary();
12192
$table->foreignSnowflake('user_id')->constrained()->cascadeOnDelete();
122-
$table->string('title', 100);
123-
$table->timestamps();
93+
$table->foreignSnowflakeFor(Post::class)->constrained();
12494
});
12595
}
12696
}
12797
```
12898

129-
Next, if you're using Eloquent, add the package's `HasSnowflakes` trait to your Eloquent models:
130-
131-
```php
132-
<?php
99+
#### Models
133100

134-
declare(strict_types=1);
101+
Next, add the package's `HasSnowflakes` trait to your Eloquent models:
135102

103+
```php
136104
namespace App\Models;
137105

138106
use CalebDW\Laraflake\Concerns\HasSnowflakes;
@@ -143,15 +111,35 @@ class Post extends Model
143111
}
144112
```
145113

146-
Finally, configure the model's `$casts` array to use the package's `AsSnowflake` for all Snowflake attributes.
147-
This cast automatically handles conversion from the database integer to a string representation in the application.
148-
It also ensures that languages which do not support 64-bit integers (such as JavaScript), will not truncate the Snowflake.
114+
The trait provides several features for the model's Snowflake columns:
115+
- the generation of Snowflakes for new records
116+
- route model binding
117+
- automatic casting from database integers to strings which prevents truncation in languages that do not support 64-bit integers (such as JavaScript).
118+
119+
By default, the trait assumes that the model's primary key is a Snowflake.
120+
If you have other unique columns that should be treated as Snowflakes, you can override the `uniqueIds` method to specify them:
149121

150122
```php
151-
<?php
152123

153-
declare(strict_types=1);
124+
namespace App\Models;
125+
126+
use CalebDW\Laraflake\Concerns\HasSnowflakes;
127+
128+
class Post extends Model
129+
{
130+
use HasSnowflakes;
131+
132+
/** @inheritDoc */
133+
public function uniqueIds(): array
134+
{
135+
return [$this->getKeyName(), 'slug'];
136+
}
137+
}
138+
```
139+
140+
If necessary, you can explicitly cast the model's Snowflake columns using the `AsSnowflake` cast:
154141

142+
```php
155143
namespace App\Models;
156144

157145
use CalebDW\Laraflake\Casts\AsSnowflake;
@@ -164,11 +152,63 @@ class Post extends Model
164152
protected $casts = [
165153
'id' => AsSnowflake::class,
166154
'user_id' => AsSnowflake::class,
167-
'title' => 'string',
168155
];
169156
}
170157
```
171158

159+
160+
### Validation
161+
162+
If you need to validate Snowflakes in your application, you can use the `Snowflake` rule or the `Rule` macro provided by this package:
163+
164+
```php
165+
use CalebDW\Laraflake\Rules\Snowflake;
166+
use Illuminate\Validation\Rule;
167+
168+
$request->validate([
169+
'id' => ['required', new Snowflake()],
170+
'user_id' => ['required', Rule::snowflake()],
171+
]);
172+
```
173+
174+
You can also just use the `Str` macro to check if a value is a valid Snowflake:
175+
176+
```php
177+
use Illuminate\Support\Str;
178+
179+
Str::isSnowflake('5585066784854016'); // (bool) true
180+
```
181+
182+
### Sequence Resolver
183+
184+
The sequence resolver is responsible for generating the sequence component of the Snowflake
185+
to ensure that numbers generated on the same machine within the same millisecond are unique.
186+
187+
By default, if the application has a cache, then it uses the `LaravelSequenceResolver`
188+
which uses the Laravel cache to store the last sequence number.
189+
190+
If the application does not have a cache, then it uses the `RandomSequenceResolver` which
191+
has no dependencies **but is not concurrency-safe**.
192+
193+
You can override the sequence resolver by binding your own implementation in a service provider:
194+
195+
```php
196+
use Godruoyi\Snowflake\SequenceResolver;
197+
use Illuminate\Support\ServiceProvider;
198+
199+
class AppServiceProvider extends ServiceProvider
200+
{
201+
public function register(): void
202+
{
203+
$this->app->bind(SequenceResolver::class, function() {
204+
return new MySequenceResolver();
205+
});
206+
}
207+
}
208+
```
209+
210+
Please see [godruoyi/php-snowflake](https://github.com/godruoyi/php-snowflake) for more information on the available sequence resolvers and their dependencies.
211+
172212
## Contributing
173213

174214
Thank you for considering contributing! You can read the contribution guide [here](CONTRIBUTING.md).
@@ -180,3 +220,4 @@ Laraflake is open-sourced software licensed under the [MIT license](LICENSE).
180220
## Acknowledgements
181221

182222
Derived from [caneara/snowflake](https://github.com/caneara/snowflake) which is no longer maintained.
223+
The actual Snowflake generation is handled by the excellent [godruoyi/php-snowflake](https://github.com/godruoyi/php-snowflake) library.

0 commit comments

Comments
 (0)