前提
- Laravel 5.7
- PostgreSQL
-
laravel-permission で
User
に対するパーミッション周りの実装を実施。-
User
からRole
に対するMorphToMany
のリレーションを持たせた。 -
User
は Global Scope でroles
に対する Eager Loading を実施するようにしてある。
-
起きたこと
artisan migrate:refresh
をしたら以下のログと共に失敗して、それ以降 artisan
コマンド自体がコケるようになりました。
In Connection.php line 664:
SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "roles" does not exist
LINE 1: ...as_roles"."model_type" as "pivot_model_type" from "roles" in...
^ (SQL: select "roles".*, "model
_has_roles"."model_id" as "pivot_model_id", "model_has_roles"."role_id" as "pivot_role_id", "
model_has_roles"."model_type" as "pivot_model_type" from "roles" inner join "model_has_roles"
on "roles"."id" = "model_has_roles"."role_id" where "model_has_roles"."model_id" in (1, 2, 3
) and "model_has_roles"."model_type" = App\User and "roles"."deleted_at" is null and "deleted
_at" is null)
原因
処理は全部追えておらず推測を含むので、間違っているかもしれません。
-
User::boot()
内でroles
に対して Eager Loading をさせた事でUser
を参照する時にroles
テーブルの存在が前提になってしまっていた。 -
artisan
実行時にAuthServiceProvider
で記述しているGate::define
等によりUser
モデルが呼ばれるので、roles
テーブルも参照される。-
AuthServiceProvider
が呼ばれてるのはconfig/app.php
によるもの?
-
- しかし直前に
migrate:refresh
でroles
テーブルが既に削除されてるので無理…となっていた。
対応
該当のスコープ内で必要なテーブルの有無をチェックするようにしたら解消し、 migrate:refresh
も無限に実行できるようになりました。
app/Scopes/WithRolesScope.php
class WithRolesScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
if ($this->isExistRolesTable()) {
$builder->with('roles');
}
}
protected function isExistRolesTable()
{
$schemaName = config('database.connections.pgsql.schema');
$rolesTableName = config('permission.table_names.roles');
$rows = DB::select('SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = ? AND table_name = ?)', [$schemaName, $rolesTableName]);
return $rows[0]->exists;
}
}
これがスマートなやり方かどうかは分からない…。