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

[1.x] Allow complete control of user resolution #251

Merged
merged 6 commits into from
Dec 21, 2023
Merged

Conversation

jessarcher
Copy link
Member

@jessarcher jessarcher commented Dec 20, 2023

This PR introduces a new approach for resolving users in Pulse.

There are a few scenarios we're aiming to solve here:

1. User models that don't have a name or email field, or that want to provide an alternative avatar

The most commonly needed Pulse customization is to change what fields are used to display users in the dashboard. The current approach requires you to resolve the users yourself and be sure to include an id field so we can map them back up again:

Pulse::users(fn ($ids) => User::findMany($ids)->map(fn ($user) => [
    'id' => $user->id,
    'name' => $user->name,
    'extra' => $user->email,
    'avatar' => $user->avatar_url,
]));

The proposed Pulse::user method allows you to hook into just the field customization instead:

Pulse::user(fn (Authenticatable $user) => [
    'name' => $user->name,
    'extra' => $user->email,
    'avatar' => $user->avatar_url,
]);

We have maintained the existing API for backward compatibility but might propose removing it for the stable release.

2. Authenticatable classes other than App\Models\User or App\User

Pulse currently checks for an App\Models\User or App\User model. With this PR, Pulse will use the configured user provider (from config/auth.php) to resolve the user. This means we'll support whichever model has been configured and will also support other user providers, such as the DatabaseUserProvider.

3. Complex authentication where the authenticable ID alone is not unique or enough to resolve the user (e.g. multi-tenancy)

Pulse currently only captures the authenticated user ID when attributing records to a user. For some applications this is not enough to uniquely resolve back to a user record for display in the dashboard.

This PR introduces a new ResolvesUsers contract which you can implement and bind in the service container to completely control what user identifier is captured, and how that identifier is resolved back to a user for the dashboard.

The contract defines three methods required to capture and resolve users:

use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
use Laravel\Pulse\Contracts\ResolvesUsers;

class CustomResolver implements ResolvesUsers
{
    public function key(Authenticatable $user): int|string|null
    {
        return json_encode([$user->tenantId, $user->id]);
    }

    public function load(Collection $keys): self
    {
        // Optionally eager load the given keys...

        return $this;
    }

    public function fields(int|string|null $key): array
    {
        // Locate the user and return the required fields...

        return [
            'name' => '...',
            'extra' => '...',
            'avatar' => '...',
        ];
    }
});

Fixes #121

@@ -40,6 +41,7 @@ public function register(): void

$this->app->singleton(Pulse::class);
$this->app->bind(Storage::class, DatabaseStorage::class);
$this->app->singletonIf(ResolvesUsers::class, Users::class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Far out, Laravel. Love this.

Co-authored-by: Tim MacDonald <hello@timacdonald.me>
@jessarcher jessarcher marked this pull request as ready for review December 21, 2023 01:21
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 this pull request may close these issues.

Having multiple Authenticatable models is incorrectly tracked
3 participants