Using UUIDs with Spatie Laravel Permission Package

The Laravel Permissions package developed by one of my favourite people in the World, the team at Spatie. This package easily allows you to add the functionality of an Access Control List(ACL) to your Laravel project. You can define roles for users, then define as many permissions as you wish for these roles or directly to a user.
The package ships with support for auto-incrementing primary keys as the default, just as is with the Laravel framework. You can swap this out for UUID based primary keys for your database tables.
What are UUIDs?
UUID is an abbreviation for âUniversal Unique Identifierâ. It is an alpha-numeric string that is 36 characters long(32 hexadecimal characters separated by four hyphens). Itâs a 128-bit value used for a unique identification. It is also known as the GUID (Globally Unique Identification), especially in the world of Microsoft.
Benefits of using UUIDs as PKs against auto-incrementing IDs
- Itâs easier to shard.
- Itâs easier to merge/replicate. There is no universal order, hence easy merging of records from different databases.
- You know the ID before the insert, it can simplify the logic/flow.
- They are very unique across applications - every table, every database, every server.
- You can generate IDs anywhere, instead of having to roundtrip to the database server. It also simplifies logic in the application. For example, to insert data into a parent table and child tables, you have to insert into the parent table first, get generated id and then insert data into the child tables. By using UUID, you can generate the primary key value of the parent table up front and insert rows into both parent and child tables at the same time within a transaction.
- UUID values do not expose the information about your data so they are safer to use in a URL. For example, if a customer with id 10 accesses his account via http://www.foobar.com/customers/69/ URL, it is easy to guess that there is a customer 70, 71, etc., and this could be a target for an attack.
Downsides of using UUIDs as PKs against auto-incrementing IDs
- There is a huge overhead in size. A UUID/GUID is four times larger than an INT. This is very important when it comes to indexes.
- Canât order by ID to get the insert order. This is a minor one as this can be achieved by sorting timestamps on records eg. created_at
- Debugging seems to be more difficult, imagine the expression WHERE id = â9eccf14d-2242-4018-bdc8-e648d4af7611;â instead of WHERE id = 1
Setting up Laravel Permissions
Spatie usually provides good,very detailed documentation for their packages. You can find documentation for the Laravel Permission package here.
First, we install the package using composer:
When the installation of the package is done, the service provider is registered automatically. On the other hand, we can manually register the service provider in our config/app/php
file:
Next, we publish the migration for the tables with:
After publishing the migration, letâs run:
then publish the config file with:
This command publishes a config file for the package in config/permission.php
.
Great! We are done setting up the package in project.
Now letâs setup our Eloquent models to use Uuid as the primary key of database tables.
We are going to take advantage of the events in Laravel. To be more specific, we are going to use the âcreatingâ event. This event is triggered exactly when a new record of the model is getting created.
One of the cleaner ways is to, extract it into a trait by itself and do all the logic there then you can just use that trait when you need a model to use UUIDs.
From the above snippet, we are hooking into the boot method of the model and when the creating model is called, we pass in a closure. We are setting setting autoincrementing of the off(setting to false). The method getKeyName
will get the name of the primary key, just in case you are using something other than the id
for the primary key.
Now that we have our trait, we can use it in all of our models(eg. User model) like so:
Great! So now all of our models have have uuid as the format for primary keys. Letâs set up a corresponding database migration for our User model.
As you can see, we are making use of Laravelâs uuid column type for our id field and indexing it as the primary key.
Letâs setup a User Factory.
Letâs fire up Tinker;
We create a user by running the following command;
This creates a user object like this;
Now we are sure that everything works just as we want it to. There is a problem though, the tables generated by the Laravel Permission package will have ids as the primary key. According to the documentation, we need to do the below;
âIf youâre using UUIDs or GUIDs for your User models you can update the
create_permission_tables.php
migration and replace$table->unsignedBigInteger($columnNames['model_morph_key'])
with$table->uuid($columnNames['model_morph_key'])
. For consistency, you can also update the package configuration file to use themodel_uuid
column name instead of the defaultmodel_id
column.â Following this instruction, we end up with a create permission table like this;
This solves our problem right? Now we have our roles and permissions tables having uuid primary keys. In my case not so much. I still ran into issues where Eloquent was expecting an integer as primary key even after running;
If thatâs the case with you as well, please continue reading.
To resolve this, we create two models Role.php
and Permission.php
.
and
As you can see, we are extending the models from the package(Spatie\Permission\Models\Permission and Spatie\Permission\Models\Role). We are also using our trait in these classes without modifying the original class in the package.
Run:
Try creating a role, permission, assign permission to a role and assign roles to users. You shouldnât run into any issues.
Cheers and thanks for reading!
Comments