Last active
December 6, 2023 07:55
-
-
Save dereckmartin/06eaf720c50bb5ba1c81d83106cb7bc8 to your computer and use it in GitHub Desktop.
Laravel Trait to support TSID (string) primary key support that generates IDs automatically on insert.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Thank you to https://github.com/odan/tsid for this package. | |
* | |
* This isn't perfect, and I don't know any further method to test for | |
* for the validity of the TSID, but this is a start. | |
* | |
* I couldn't get Laravel 10 to play nice with bigIntegers as primary key. | |
* Laravel kept trying to add auto_increment on table create during migration. | |
* I had to follow the docs to use the following: | |
* | |
* Migration: | |
* $table->string('id', 13) | |
* ->nullable(false) | |
* ->unique(); | |
* | |
* $table->primary('id') | |
* | |
* In your Models where this will be implemented: | |
* | |
* use App\Traits\Database\HasTsids; | |
* | |
* class PromptStyle extends Model | |
* { | |
* ... | |
* use HasTsids; | |
* public $incrementing = false; | |
* protected $keyType = 'string'; | |
* ... | |
* } | |
* | |
* POST Request Response: | |
* | |
* * Connection #0 to host xxxxx left intact | |
* {"prompt":"test","id":"0EDZ6E1648XS6"} | |
* | |
* Database: | |
* | |
* MariaDB [xxxxxxx]> select * from prompt_styles; | |
* +---------------+--------+------------+ | |
* | id | prompt | created | | |
* +---------------+--------+------------+ | |
* | 0EDZ6E1648XS6 | test | 1701847279 | | |
* +---------------+--------+------------+ | |
* 1 row in set (0.000 sec) | |
* | |
* | |
* Update the namespace to where you plan on installing this... | |
*/ | |
namespace App\Traits\Database; | |
use Illuminate\Database\Eloquent\ModelNotFoundException; | |
use Odan\Tsid\TsidFactory; | |
trait HasTsids | |
{ | |
/** | |
* Initialize the trait. | |
* | |
* @return void | |
*/ | |
public function initializeHasTsids() | |
{ | |
$this->usesUniqueIds = true; | |
} | |
/** | |
* Get the columns that should receive a unique identifier. | |
* | |
* @return array | |
*/ | |
public function uniqueIds() | |
{ | |
return [$this->getKeyName()]; | |
} | |
/** | |
* Generate a new UUID for the model. | |
* | |
* @return string | |
*/ | |
public function newUniqueId() | |
{ | |
$tsid = new TsidFactory(); | |
return (string) $tsid->generate()->toString(); | |
} | |
/** | |
* Retrieve the model for a bound value. | |
* | |
* @param \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Relations\Relation $query | |
* @param mixed $value | |
* @param string|null $field | |
* @return \Illuminate\Database\Eloquent\Relations\Relation | |
* | |
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException | |
*/ | |
public function resolveRouteBindingQuery($query, $value, $field = null) | |
{ | |
if ($field && in_array($field, $this->uniqueIds()) && ! $this->isValidTsidStr($value)) { | |
throw (new ModelNotFoundException)->setModel(get_class($this), $value); | |
} | |
if (! $field && in_array($this->getRouteKeyName(), $this->uniqueIds()) && ! $this->isValidTsidStr($value)) { | |
throw (new ModelNotFoundException)->setModel(get_class($this), $value); | |
} | |
return parent::resolveRouteBindingQuery($query, $value, $field); | |
} | |
/** | |
* Get the auto-incrementing key type. | |
* | |
* @return string | |
*/ | |
public function getKeyType() | |
{ | |
if (in_array($this->getKeyName(), $this->uniqueIds())) { | |
return 'string'; | |
} | |
return $this->keyType; | |
} | |
/** | |
* Get the value indicating whether the IDs are incrementing. | |
* | |
* @return bool | |
*/ | |
public function getIncrementing() | |
{ | |
if (in_array($this->getKeyName(), $this->uniqueIds())) { | |
return false; | |
} | |
return $this->incrementing; | |
} | |
public function isValidTsidStr(string $tsid_str): bool | |
{ | |
if (13 !== \strlen($tsid_str)) { | |
return false; | |
} | |
if (13 !== strspn($tsid_str, '0123456789ABCDEFGHJKMNPQRSTVWXYZ')) { | |
return false; | |
} | |
return true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment