Repository: archtechx/tenancy (language: php)

Issue:
Add option to customize name of tenant_user_impersonation_tokens table
It seems that the name for the `tenant_user_impersonation_tokens` table is hard-coded with no way to change it.

Our database table naming scheme involves *singular* table names, not plural. It would be nice if we could customize the name of this table to fit our naming conventions.
Add option to customize name of tenant_user_impersonation_tokens table
It seems that the name for the `tenant_user_impersonation_tokens` table is hard-coded with no way to change it.

Our database table naming scheme involves *singular* table names, not plural. It would be nice if we could customize the name of this table to fit our naming conventions.


Discussion / hints:
Would need a suggested implementation to keep this issue open.
To match other implementations in the package, an additional setting could be added to `tenancy.php`:

```
'impersonation_token_model'         => \App\Models\ImpersonationToken::class,
```

The table name could be customized by extending the existing model using a custom class, and just overriding the `table` property to change the table name.
Would need a suggested implementation to keep this issue open.
To match other implementations in the package, an additional setting could be added to `tenancy.php`:

```
'impersonation_token_model'         => \App\Models\ImpersonationToken::class,
```

The table name could be customized by extending the existing model using a custom class, and just overriding the `table` property to change the table name.

Fix patch:
diff --git a/assets/config.php b/assets/config.php
index db3820bf3..9089974d7 100644
--- a/assets/config.php
+++ b/assets/config.php
@@ -15,6 +15,7 @@
     'models' => [
         'tenant' => Stancl\Tenancy\Database\Models\Tenant::class,
         'domain' => Stancl\Tenancy\Database\Models\Domain::class,
+        'impersonation_token' => Stancl\Tenancy\Database\Models\ImpersonationToken::class,
 
         /**
          * Name of the column used to relate models to tenants.
diff --git a/src/Database/Models/ImpersonationToken.php b/src/Database/Models/ImpersonationToken.php
index 6dabbd031..38d2463e5 100644
--- a/src/Database/Models/ImpersonationToken.php
+++ b/src/Database/Models/ImpersonationToken.php
@@ -25,6 +25,9 @@ class ImpersonationToken extends Model
 {
     use CentralConnection;
 
+    /** You can set this property to customize the table name */
+    public static string $tableName = 'tenant_user_impersonation_tokens';
+
     protected $guarded = [];
 
     public $timestamps = false;
@@ -33,11 +36,15 @@ class ImpersonationToken extends Model
 
     public $incrementing = false;
 
-    protected $table = 'tenant_user_impersonation_tokens';
     protected $casts = [
         'created_at' => 'datetime',
     ];
 
+    public function getTable()
+    {
+        return static::$tableName;
+    }
+
     public static function booted(): void
     {
         static::creating(function ($model) {
diff --git a/src/Features/UserImpersonation.php b/src/Features/UserImpersonation.php
index 2e0fedbf8..3db563a4e 100644
--- a/src/Features/UserImpersonation.php
+++ b/src/Features/UserImpersonation.php
@@ -4,6 +4,7 @@
 
 namespace Stancl\Tenancy\Features;
 
+use Illuminate\Database\Eloquent\Model;
 use Illuminate\Http\RedirectResponse;
 use Illuminate\Support\Facades\Auth;
 use Stancl\Tenancy\Contracts\Feature;
@@ -18,8 +19,8 @@ class UserImpersonation implements Feature
 
     public function bootstrap(Tenancy $tenancy): void
     {
-        $tenancy->macro('impersonate', function (Tenant $tenant, string $userId, string $redirectUrl, string|null $authGuard = null, bool $remember = false): ImpersonationToken {
-            return ImpersonationToken::create([
+        $tenancy->macro('impersonate', function (Tenant $tenant, string $userId, string $redirectUrl, string|null $authGuard = null, bool $remember = false): Model {
+            return UserImpersonation::modelClass()::create([
                 Tenancy::tenantKeyColumn() => $tenant->getTenantKey(),
                 'user_id' => $userId,
                 'redirect_url' => $redirectUrl,
@@ -30,10 +31,15 @@ public function bootstrap(Tenancy $tenancy): void
     }
 
     /** Impersonate a user and get an HTTP redirect response. */
-    public static function makeResponse(#[\SensitiveParameter] string|ImpersonationToken $token, ?int $ttl = null): RedirectResponse
+    public static function makeResponse(#[\SensitiveParameter] string|Model $token, ?int $ttl = null): RedirectResponse
     {
-        /** @var ImpersonationToken $token */
-        $token = $token instanceof ImpersonationToken ? $token : ImpersonationToken::findOrFail($token);
+        /**
+         * The model does NOT have to extend ImpersonationToken, but usually it WILL be a child
+         * of ImpersonationToken and this makes it clear to phpstan that the model has a redirect_url property.
+         *
+         * @var ImpersonationToken $token
+         */
+        $token = $token instanceof Model ? $token : static::modelClass()::findOrFail($token);
         $ttl ??= static::$ttl;
 
         $tokenExpired = $token->created_at->diffInSeconds(now()) > $ttl;
@@ -54,6 +60,12 @@ public static function makeResponse(#[\SensitiveParameter] string|ImpersonationT
         return redirect($token->redirect_url);
     }
 
+    /** @return class-string<Model> */
+    public static function modelClass(): string
+    {
+        return config('tenancy.models.impersonation_token');
+    }
+
     public static function isImpersonating(): bool
     {
         return session()->has('tenancy_impersonating');


Test patch: