Skip to content

Commit

Permalink
Update uuid.md (#2438)
Browse files Browse the repository at this point in the history
* Update uuid.md

Resolve problems with Laravel 10. Ex version of uuid.md doesn`t correct working. In this manual -- all good
---------

Co-authored-by: Chris Brown <[email protected]>
  • Loading branch information
ChillMouse and drbyte authored Aug 19, 2023
1 parent feb3014 commit 7920916
Showing 1 changed file with 125 additions and 42 deletions.
167 changes: 125 additions & 42 deletions docs/advanced-usage/uuid.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,88 +3,171 @@ title: UUID
weight: 7
---

If you're using UUIDs or GUIDs for your User models there are a few considerations to note.
If you're using UUIDs for your User models there are a few considerations to note.

> THIS IS NOT A FULL LESSON ON HOW TO IMPLEMENT UUIDs IN YOUR APP.
Since each UUID implementation approach is different, some of these may or may not benefit you. As always, your implementation may vary.


## Migrations
You will probably want to update the `create_permission_tables.php` migration:
You will need to update the `create_permission_tables.php` migration:

If your User models are using `uuid` instead of `unsignedBigInteger` then you'll need to reflect the change in the migration provided by this package. Something like this would be typical, for both `model_has_permissions` and `model_has_roles` tables:
**User Models using UUIDs**
If your User models are using `uuid` instead of `unsignedBigInteger` then you'll need to reflect the change in the migration provided by this package. Something like the following would be typical, for **both** `model_has_permissions` and `model_has_roles` tables:

```diff
// note: this is done in two places in the default migration file, so edit both places:
- $table->unsignedBigInteger($columnNames['model_morph_key'])
+ $table->uuid($columnNames['model_morph_key'])
```

OPTIONAL: If you also want the roles and permissions to use a UUID for their `id` value, then you'll need to also change the id fields accordingly, and manually set the primary key. LEAVE THE FIELD NAME AS `id` unless you also change it in dozens of other places.
**Roles and Permissions using UUIDS**
If you also want the roles and permissions to use a UUID for their `id` value, then you'll need to change the id fields accordingly, and manually set the primary key.

```diff
Schema::create($tableNames['permissions'], function (Blueprint $table) {
- $table->bigIncrements('id');
+ $table->uuid('id');
$table->string('name');
$table->string('guard_name');
$table->timestamps();

+ $table->primary('id');
- $table->bigIncrements('id'); // permission id
+ $table->uuid('id')->primary()->unique(); // permission id
//...
});

Schema::create($tableNames['roles'], function (Blueprint $table) {
- $table->bigIncrements('id');
+ $table->uuid('id');
$table->string('name');
$table->string('guard_name');
$table->timestamps();

+ $table->primary('id');
- $table->bigIncrements('id'); // role id
+ $table->uuid('id')->primary()->unique(); // role id
//...
});

Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames) {
- $table->bigIncrements('permission_id');
+ $table->uuid('permission_id');
...
- $table->unsignedBigInteger(PermissionRegistrar::$pivotPermission);
+ $table->uuid(PermissionRegistrar::$pivotPermission);
$table->string('model_type');
//...
$table->foreign(PermissionRegistrar::$pivotPermission)
- ->references('id') // permission id
+ ->references('uuid') // permission id
->on($tableNames['permissions'])
->onDelete('cascade');
//...

Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames) {
- $table->bigIncrements('role_id');
+ $table->uuid('role_id');
...
- $table->unsignedBigInteger(PermissionRegistrar::$pivotRole);
+ $table->uuid(PermissionRegistrar::$pivotRole);
//...
$table->foreign(PermissionRegistrar::$pivotRole)
- ->references('id') // role id
+ ->references('uuid') // role id
->on($tableNames['roles'])
->onDelete('cascade');//...

Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames) {
- $table->bigIncrements('permission_id');
- $table->bigIncrements('role_id');
+ $table->uuid('permission_id');
+ $table->uuid('role_id');
- $table->unsignedBigInteger(PermissionRegistrar::$pivotPermission);
- $table->unsignedBigInteger(PermissionRegistrar::$pivotRole);
+ $table->uuid(PermissionRegistrar::$pivotPermission);
+ $table->uuid(PermissionRegistrar::$pivotRole);
```


## Configuration (OPTIONAL)
You might want to change the pivot table field name from `model_id` to `model_uuid`, just for semantic purposes.
For this, in the configuration file edit `column_names.model_morph_key`:

- OPTIONAL: Change to `model_uuid` instead of the default `model_id`. (The default of `model_id` is shown in this snippet below. Change it to match your needs.)

- OPTIONAL: Change to `model_uuid` instead of the default `model_id`.
```diff
'column_names' => [
/*
* Change this if you want to name the related model primary key other than
* `model_id`.
*
* For example, this would be nice if your primary keys are all UUIDs. In
* that case, name this `model_uuid`.
*/
'model_morph_key' => 'model_id',
/*
* Change this if you want to name the related pivots other than defaults
*/
'role_pivot_key' => null, //default 'role_id',
'permission_pivot_key' => null, //default 'permission_id',

/*
* Change this if you want to name the related model primary key other than
* `model_id`.
*
* For example, this would be nice if your primary keys are all UUIDs. In
* that case, name this `model_uuid`.
*/
- 'model_morph_key' => 'model_id',
+ 'model_morph_key' => 'model_uuid',
],
```
- If you extend the models into your app, be sure to list those models in your configuration file. See the Extending section of the documentation and the Models section below.

## Models
If you want all the role/permission objects to have a UUID instead of an integer, you will need to Extend the default Role and Permission models into your own namespace in order to set some specific properties. (See the Extending section of the docs, where it explains requirements of Extending, as well as the configuration settings you need to update.)

- You likely want to set `protected $keyType = 'string';` so Laravel handles joins as strings and doesn't cast to integer.
- OPTIONAL: If you changed the field name in your migrations, you must set `protected $primaryKey = 'uuid';` to match.
- Usually for UUID you will also set `public $incrementing = false;`. Remove it if it causes problems for you.
Examples:

Create new models, which extend the Role and Permission models of this package, and add the HasUuids trait (available since Laravel 9):
```bash
php artisan make:model Role
php artisan make:model Permission
```

`App\Model\Role.php`
```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Spatie\Permission\Models\Role as SpatieRole;

class Role extends SpatieRole
{
use HasFactory, HasUuids;
protected $primaryKey = 'uuid';
}
```

`App\Model\Permission.php`
```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Spatie\Permission\Models\Permission as SpatiePermission;

class Permission extends SpatiePermission
{
use HasFactory, HasUuids;
protected $primaryKey = 'uuid';
}
```
And edit `config/permission.php`
```diff
'models' => [

/*
* When using the "HasPermissions" trait from this package, we need to know which
* Eloquent model should be used to retrieve your permissions. Of course, it
* is often just the "Permission" model but you may use whatever you like.
*
* The model you want to use as a Permission model needs to implement the
* `Spatie\Permission\Contracts\Permission` contract.
*/

- 'permission' => Spatie\Permission\Models\Permission::class
+ 'permission' => App\Models\Permission::class,

/*
* When using the "HasRoles" trait from this package, we need to know which
* Eloquent model should be used to retrieve your roles. Of course, it
* is often just the "Role" model but you may use whatever you like.
*
* The model you want to use as a Role model needs to implement the
* `Spatie\Permission\Contracts\Role` contract.
*/

- 'role' => Spatie\Permission\Models\Role::class,
+ 'role' => App\Models\Role::class,

],
```


It is common to use a trait to handle the $keyType and $incrementing settings, as well as add a boot event trigger to ensure new records are assigned a uuid. You would `use` this trait in your User and extended Role/Permission models. An example `UuidTrait` is shown here for inspiration. Adjust to suit your needs.

Expand Down

0 comments on commit 7920916

Please sign in to comment.