Add SnowflakeService and hasSnowflakePrimary

This commit is contained in:
Daniel Supernault 2024-12-19 09:29:58 -07:00
parent e193132773
commit c07eacc074
2 changed files with 74 additions and 0 deletions

View File

@ -0,0 +1,19 @@
<?php
namespace App\Concerns;
use App\Services\SnowflakeService;
trait HasSnowflakePrimary
{
public static function bootHasSnowflakePrimary()
{
static::saving(function ($model) {
if (is_null($model->getKey())) {
$keyName = $model->getKeyName();
$id = resolve(SnowflakeService::class)->next();
$model->setAttribute($keyName, $id);
}
});
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace App\Services;
use Exception;
use Illuminate\Support\Facades\Redis;
use Cache;
use Illuminate\Support\Carbon;
class SnowflakeService
{
// The snowflake epoch is 2024-03-28T11:21:53+00:00
const EPOCH_DATE = 1711624913000;
/**
* Generate the next 64-bit unique ID
* @return int
* @throws Exception
*/
public static function next(): int
{
$seq = Cache::get('snowflake:seq');
if(!$seq) {
Cache::put('snowflake:seq', 1);
$seq = 1;
} else {
Cache::increment('snowflake:seq');
}
if($seq >= 4095) {
Cache::put('snowflake:seq', 0);
$seq = 0;
}
return ((round(microtime(true) * 1000) - 1711624913000) << 22)
| (random_int(1,31) << 17)
| (random_int(1,31) << 12)
| $seq;
}
public static function byDate(Carbon $ts = null)
{
if($ts instanceOf Carbon) {
$ts = now()->parse($ts)->timestamp;
} else {
return self::next();
}
return ((round($ts * 1000) - 1711624913000) << 22)
| (random_int(1,31) << 17)
| (random_int(1,31) << 12)
| 0;
}
}