Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SQLSTATE[42883]: Undefined function: 7 ERROR: operator does not exist: uuid = integer #1434

Closed
JhonatanGarcia92 opened this issue Apr 8, 2020 · 6 comments · Fixed by #2089

Comments

@JhonatanGarcia92
Copy link

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

@JhonatanGarcia92 JhonatanGarcia92 changed the title Help Please. Error to sync Permissions to Role Error synchronizing permissions for the role Apr 8, 2020
@drbyte drbyte changed the title Error synchronizing permissions for the role SQLSTATE[42883]: Undefined function: 7 ERROR: operator does not exist: uuid = integer Apr 8, 2020
@drbyte
Copy link
Collaborator

drbyte commented Apr 8, 2020

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!

@JhonatanGarcia92
Copy link
Author

JhonatanGarcia92 commented Apr 9, 2020

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.

@drbyte
Copy link
Collaborator

drbyte commented Apr 9, 2020

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.

@JhonatanGarcia92
Copy link
Author

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 :/

@drbyte
Copy link
Collaborator

drbyte commented Apr 11, 2020

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']);
    }
}

@JhonatanGarcia92
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants