Skip to content
This repository was archived by the owner on Dec 10, 2018. It is now read-only.

Commit b4e6802

Browse files
authored
Merge pull request #49 from isocroft/dynamic_accessors_mutators
Adding dynamic accessors and mutators from $uuidAttributes and customising uuid text attribute suffix
2 parents 2bdada2 + 772d9ac commit b4e6802

File tree

4 files changed

+169
-17
lines changed

4 files changed

+169
-17
lines changed

README.md

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,21 @@ Schema::create('table_name', function (Blueprint $table) {
3636
});
3737
```
3838

39-
To get your model to work with the encoded UUID, use the `Spatie\BinaryUuid\HasBinaryUuid` trait in your model.
39+
To get your model to work with the encoded UUID (i.e. to use uuid as a primary key), you must let your model use the `Spatie\BinaryUuid\HasBinaryUuid` and the `Spatie\BinaryUuid\HasUuidPrimaryKey` traits.
4040

4141
```php
4242
use Illuminate\Database\Eloquent\Model;
4343
use Spatie\BinaryUuid\HasBinaryUuid;
44+
use Spatie\BinaryUuid\HasUuidPrimaryKey;
4445

4546
class TestModel extends Model
4647
{
47-
use HasBinaryUuid;
48+
use HasBinaryUuid,
49+
HasUuidPrimaryKey;
4850
}
4951
```
5052

51-
If don't like the primary key named `uuid` you can overwrite the `getKeyName` method to manually specify the primary key name.
53+
If don't like the primary key named `uuid` you can leave off the `HasUuidPrimaryKey` trait and manually specify `$primaryKey`. Don't forget set `$incrementing` to false.
5254

5355
```php
5456
use Illuminate\Database\Eloquent\Model;
@@ -58,13 +60,43 @@ class TestModel extends Model
5860
{
5961
use HasBinaryUuid;
6062

61-
public function getKeyName()
62-
{
63-
return 'uuid';
64-
}
63+
public $incrementing = false;
64+
65+
public $primaryKey = 'uuid';
6566
}
6667
```
6768

69+
If you try converting your model to JSON with binary attributes, you will see errors. By declaring your binary attributes in `$uuidAttributes` on your model, you will tell the package to cast those UUID's to text whenever they are converted to array. Also, this adds a dynamic accessor for each of the uuid attributes.
70+
71+
```php
72+
use Illuminate\Database\Eloquent\Model;
73+
use Spatie\BinaryUuid\HasBinaryUuid;
74+
75+
class TestModel extends Model
76+
{
77+
use HasBinaryUuid;
78+
79+
/**
80+
* The suffix for the uuid text attribute
81+
* by default this is '_text'
82+
*
83+
* @var
84+
*/
85+
protected $uuidSuffix = '_str';
86+
87+
/**
88+
* The binary UUID attributes that should be converted to text.
89+
*
90+
* @var array
91+
*/
92+
protected $uuids = [
93+
'country_uuid' // foreign or related key
94+
];
95+
}
96+
```
97+
98+
In your JSON you will see `uuid` and `country_uuid` in their textual representation. If you're also making use of composite primary keys, the above works well enough too. Just include your keys in the `$uuids` array or override the `getKeyName()` method on your model and return your composite primary keys as an array of keys. You can also customize the UUID text attribute suffix name. In the code above, instead of '\_text' it's '\_str'.
99+
68100
#### A note on the `uuid` blueprint method
69101

70102
Laravel currently doesn't allow adding new blueprint methods which can be used out of the box.

src/HasBinaryUuid.php

Lines changed: 87 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,31 +73,106 @@ public static function decodeUuid(string $binaryUuid): string
7373

7474
public function toArray()
7575
{
76-
if (! $this->exists) {
77-
return parent::toArray();
76+
$uuidAttributes = $this->getUuidAttributes();
77+
78+
$array = parent::toArray();
79+
80+
if (! $this->exists || ! is_array($uuidAttributes)) {
81+
return $array;
82+
}
83+
84+
foreach ($uuidAttributes as $attributeKey) {
85+
if (! array_key_exists($attributeKey, $array)) {
86+
continue;
87+
}
88+
$uuidKey = $this->getRelatedBinaryKeyName($attributeKey);
89+
$array[$attributeKey] = $this->{$uuidKey};
90+
}
91+
92+
return $array;
93+
}
94+
95+
public function getRelatedBinaryKeyName($attribute)
96+
{
97+
$suffix = $this->getUuidSuffix();
98+
99+
return preg_match('/(?:uu)?id/i', $attribute) ? "{$attribute}{$suffix}" : $attribute;
100+
}
101+
102+
public function getAttribute($key)
103+
{
104+
$uuidKey = $this->uuidTextAttribute($key);
105+
106+
if ($uuidKey && $this->{$uuidKey} !== null) {
107+
return static::decodeUuid($this->{$uuidKey});
108+
}
109+
110+
return parent::getAttribute($key);
111+
}
112+
113+
public function setAttribute($key, $value)
114+
{
115+
if ($this->uuidTextAttribute($key)) {
116+
$value = static::encodeUuid($value);
78117
}
79118

80-
$data = parent::toArray();
119+
return parent::setAttribute($key, $value);
120+
}
121+
122+
protected function getUuidSuffix()
123+
{
124+
return (property_exists($this, 'uuidSuffix')) ? $this->uuidSuffix : '_text';
125+
}
126+
127+
protected function uuidTextAttribute($key)
128+
{
129+
$uuidAttributes = $this->getUuidAttributes();
130+
$suffix = $this->getUuidSuffix();
131+
$offset = -(strlen($suffix));
132+
133+
if (substr($key, $offset) == $suffix && in_array(($uuidKey = substr($key, 0, $offset)), $uuidAttributes)) {
134+
return $uuidKey;
135+
}
136+
137+
return false;
138+
}
139+
140+
public function getUuidAttributes()
141+
{
142+
$uuidAttributes = [];
81143

82-
if (isset($data[$this->getKeyName()])) {
83-
$data[$this->getKeyName()] = $this->uuid_text;
144+
if (property_exists($this, 'uuids') && is_array($this->uuids)) {
145+
$uuidAttributes = array_merge($uuidAttributes, $this->uuids);
84146
}
85147

86-
return $data;
148+
// non composite primary keys will return a string so casting required
149+
$key = (array) $this->getKeyName();
150+
151+
$uuidAttributes = array_unique(array_merge($uuidAttributes, $key));
152+
153+
return $uuidAttributes;
87154
}
88155

89156
public function getUuidTextAttribute(): ?string
90157
{
91-
if (! $this->exists) {
158+
$key = $this->getKeyName();
159+
160+
if (! $this->exists || is_array($key)) {
92161
return null;
93162
}
94163

95-
return static::decodeUuid($this->{$this->getKeyName()});
164+
return static::decodeUuid($this->{$key});
96165
}
97166

98167
public function setUuidTextAttribute(string $uuid)
99168
{
100-
$this->{$this->getKeyName()} = static::encodeUuid($uuid);
169+
$key = $this->getKeyName();
170+
171+
if (is_array($key)) {
172+
return;
173+
}
174+
175+
$this->{$key} = static::encodeUuid($uuid);
101176
}
102177

103178
public function getQueueableId()
@@ -112,7 +187,9 @@ public function newQueryForRestoration($id)
112187

113188
public function getRouteKeyName()
114189
{
115-
return 'uuid_text';
190+
$suffix = $this->getUuidSuffix();
191+
192+
return "uuid{$suffix}";
116193
}
117194

118195
public function getKeyName()

tests/Feature/HasBinaryUuidTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,38 @@ public function it_can_query_a_relation_with_scope()
8080
$this->assertNotNull($model);
8181
}
8282

83+
/** @test */
84+
public function it_decodes_columns_besides_primary_uuid_when_turned_to_an_array()
85+
{
86+
$uuid = Uuid::uuid1();
87+
$relationUuid = Uuid::uuid1();
88+
89+
$model = $this->createModel($uuid, $relationUuid);
90+
91+
$modelArray = $model->toArray();
92+
93+
$this->assertNotNull($model);
94+
$this->assertCount(4, $modelArray);
95+
$this->assertTrue(array_key_exists('relation_uuid', $modelArray));
96+
$this->assertEquals($modelArray['relation_uuid'], $model->relation_uuid_text);
97+
}
98+
99+
/** @test */
100+
public function it_should_use_custom_suffix_when_specified()
101+
{
102+
$uuid = Uuid::uuid1();
103+
104+
$model = $this->createModel($uuid);
105+
106+
$model->setUuidSuffix('_str');
107+
108+
$modelArray = $model->toArray();
109+
110+
$this->assertNotNull($model);
111+
$this->assertTrue(array_key_exists('uuid', $modelArray));
112+
$this->assertEquals($modelArray['uuid'], $model->uuid_str);
113+
}
114+
83115
/** @test */
84116
public function it_can_query_multiple_relations_with_scope()
85117
{

tests/TestModel.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,16 @@ class TestModel extends Model
99
{
1010
use HasBinaryUuid;
1111

12+
protected $uuids = [
13+
'relation_uuid',
14+
];
15+
16+
protected $uuidSuffix = '_text';
17+
1218
protected $table = 'test';
19+
20+
public function setUuidSuffix($suffix = '_text')
21+
{
22+
$this->uuidSuffix = $suffix;
23+
}
1324
}

0 commit comments

Comments
 (0)