Laravel-permission: SQLSTATE[42883]: Undefined function: 7 ERROR: operator does not exist: uuid = integer

Created on 8 Apr 2020  路  6Comments  路  Source: spatie/laravel-permission

When I try create a Role:
image

In the Roles and Permissions models, I put to force these attributes but still returns the error mentioned above.
image

image

When creating, failed when looking for role relationship with permission model
image

Most helpful comment

I created a new project just like you did and compared the changes in the projects. Then, I identified that I had not changed in my config/Permissions.php and set to my Models and not Spatie. Anyway, problem solved.

'models' => [ 'permission' => App\Permission::class, 'role' => App\Role::class, ],

Thank you very much for your support

All 6 comments

It would seem that your alterations for UUID are not consistently matching up across tables: perhaps you didn't alter the schema completely in all affected tables?

Specifically the error is a complaint by Postgres when trying to do the whereIn matching on int vs uuid/string. The protected $keyType='string' should handle this.

Also, unrelated: you should never set id as a $fillable property!!!! (especially if it's your primary key)! Read the Laravel docs around security reasons why the $fillable property exists!

I found the problem, I extends the Spatie\Permission\Models\Permission in my Permission.php,
and I set the $keyType='string' to override, but, for some reason, the Spatie\Permission\Models\Permission, don't override the Illuminate\Database\Eloquent\Model.

image

If I override this $keyType='string' in Spatie\Permission\Models\Permission, it's work.

image

Some ideia for resolve this situation, please?

about the id in fillable, thanks for alert, I will improve and studied this.

I would have expected that extending the Spatie Permission model would also allow you to override $keyType as you've done.

Is it possible that your code is (somewhere) using the Spatie model directly and not using your overridden model?

Nevertheless, it is okay to implement the Contract instead of merely extending the Spatie model.

I believe not, I reviewed all the code, however, the only place where I use Spatie model, is in Permission and Role. I changed all my models to override $ keyType = 'string', but it still didn't work :/

I believe there's something wrong in your app.

I've set up a very simple app which extends the Spatie models, and it works fine with assignRole(), syncRoles(), givePermissionTo(), syncPermissions(), with uuid implemented simply.

.env file, specifying Postgres

DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_DATABASE=uuidtest

UuidTrait.php

<?php
namespace App;

use Facades\Str;

trait UuidTrait
{
    public $incrementing = false;
    protected $keyType = 'string';

    protected static function boot()
    {
        parent::boot();

        static::creating(function ($model) {
            $model->{$model->getKeyName()} = (string) Str::uuid();
        });
    }
}

User.php

<?php
namespace App;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use Notifiable;
    use HasRoles;
    use UuidTrait;
}

Role.php

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;
use Spatie\Permission\Models\Role as SpatieRole;

class Role extends SpatieRole
{
    use UuidTrait;
}

Permission.php

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;
use Spatie\Permission\Models\Permission as SpatiePermission;

class Permission extends SpatiePermission
{
    use UuidTrait;
}

config/permissions.php

<?php

return [
    'models' => [
        'permission' => App\Permission::class,
        'role' => App\Role::class,
    ],
/// the rest of this file is just defaults:
    'table_names' => [
        'roles' => 'roles',
        'permissions' => 'permissions',
        'model_has_permissions' => 'model_has_permissions',
        'model_has_roles' => 'model_has_roles',
        'role_has_permissions' => 'role_has_permissions',
    ],

    'column_names' => [
        'model_morph_key' => 'model_id',
    ],
    'display_permission_in_exception' => false,
    'enable_wildcard_permission' => false,

    'cache' => [
        'expiration_time' => \DateInterval::createFromDateString('24 hours'),
        'key' => 'spatie.permission.cache',
        'model_key' => 'name',
        'store' => 'default',
    ],
];

migration (sets uuid() columns, and sets primary key on role/permission tables):

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePermissionTables extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        $tableNames = config('permission.table_names');
        $columnNames = config('permission.column_names');

        if (empty($tableNames)) {
            throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding.');
        }

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

            $table->primary('id');
        });

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

            $table->primary('id');
        });

        Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames) {
            $table->uuid('permission_id');

            $table->string('model_type');
            $table->uuid($columnNames['model_morph_key']);
            $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');

            $table->foreign('permission_id')
                ->references('id')
                ->on($tableNames['permissions'])
                ->onDelete('cascade');

            $table->primary(['permission_id', $columnNames['model_morph_key'], 'model_type'],
                    'model_has_permissions_permission_model_type_primary');
        });

        Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames) {
            $table->uuid('role_id');

            $table->string('model_type');
            $table->uuid($columnNames['model_morph_key']);
            $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');

            $table->foreign('role_id')
                ->references('id')
                ->on($tableNames['roles'])
                ->onDelete('cascade');

            $table->primary(['role_id', $columnNames['model_morph_key'], 'model_type'],
                    'model_has_roles_role_model_type_primary');
        });

        Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames) {
            $table->uuid('permission_id');
            $table->uuid('role_id');

            $table->foreign('permission_id')
                ->references('id')
                ->on($tableNames['permissions'])
                ->onDelete('cascade');

            $table->foreign('role_id')
                ->references('id')
                ->on($tableNames['roles'])
                ->onDelete('cascade');

            $table->primary(['permission_id', 'role_id'], 'role_has_permissions_permission_id_role_id_primary');
        });

        app('cache')
            ->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
            ->forget(config('permission.cache.key'));
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        $tableNames = config('permission.table_names');

        if (empty($tableNames)) {
            throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
        }

        Schema::drop($tableNames['role_has_permissions']);
        Schema::drop($tableNames['model_has_roles']);
        Schema::drop($tableNames['model_has_permissions']);
        Schema::drop($tableNames['roles']);
        Schema::drop($tableNames['permissions']);
    }
}

I created a new project just like you did and compared the changes in the projects. Then, I identified that I had not changed in my config/Permissions.php and set to my Models and not Spatie. Anyway, problem solved.

'models' => [ 'permission' => App\Permission::class, 'role' => App\Role::class, ],

Thank you very much for your support

Was this page helpful?
0 / 5 - 0 ratings

Related issues

neoreids picture neoreids  路  3Comments

ghost picture ghost  路  3Comments

notflip picture notflip  路  3Comments

vpratfr picture vpratfr  路  4Comments

devingray picture devingray  路  3Comments