<?php declare(strict_types=1); namespace Kreait\Firebase\Auth; use Beste\Json; use DateTimeImmutable; use Kreait\Firebase\Util\DT; use function array_key_exists; use function array_map; /** * @phpstan-import-type ProviderUserInfoResponseShape from UserInfo * @phpstan-import-type UserMetadataResponseShape from UserMetaData * @phpstan-import-type MfaInfoResponseShape from MfaInfo * * @phpstan-type UserRecordResponseShape array{ * localId: non-empty-string, * email?: non-empty-string, * emailVerified?: bool, * displayName?: non-empty-string, * photoUrl?: non-empty-string, * phoneNumber?: non-empty-string, * disabled?: bool, * passwordHash?: non-empty-string, * salt?: non-empty-string, * customAttributes?: non-empty-string, * tenantId?: non-empty-string, * providerUserInfo?: list<ProviderUserInfoResponseShape>, * mfaInfo?: list<MfaInfoResponseShape>, * createdAt: non-empty-string, * lastLoginAt?: non-empty-string, * passwordUpdatedAt?: non-empty-string, * lastRefreshAt?: non-empty-string, * validSince?: non-empty-string * } */ final class UserRecord { /** * @param non-empty-string $uid * @param non-empty-string|null $email * @param non-empty-string|null $displayName * @param non-empty-string|null $phoneNumber * @param non-empty-string|null $photoUrl * @param list<UserInfo> $providerData * @param non-empty-string|null $passwordHash * @param non-empty-string|null $passwordSalt * @param array<non-empty-string, mixed> $customClaims * @param non-empty-string|null $tenantId */ public function __construct( public readonly string $uid, public readonly ?string $email, public readonly bool $emailVerified, public readonly ?string $displayName, public readonly ?string $phoneNumber, public readonly ?string $photoUrl, public readonly bool $disabled, public readonly UserMetaData $metadata, public readonly array $providerData, public readonly ?MfaInfo $mfaInfo, public readonly ?string $passwordHash, public readonly ?string $passwordSalt, public readonly array $customClaims, public readonly ?string $tenantId, public readonly ?DateTimeImmutable $tokensValidAfterTime, ) { } /** * @internal * * @param UserRecordResponseShape $data */ public static function fromResponseData(array $data): self { $validSince = array_key_exists('validSince', $data) ? DT::toUTCDateTimeImmutable($data['validSince']) : null; $customClaims = array_key_exists('customAttributes', $data) ? Json::decode($data['customAttributes'], true) : []; $providerUserInfo = array_key_exists('providerUserInfo', $data) ? self::userInfoFromResponseData($data) : []; return new self( $data['localId'], $data['email'] ?? null, $data['emailVerified'] ?? false, $data['displayName'] ?? null, $data['phoneNumber'] ?? null, $data['photoUrl'] ?? null, $data['disabled'] ?? false, self::userMetaDataFromResponseData($data), $providerUserInfo, self::mfaInfoFromResponseData($data), $data['passwordHash'] ?? null, $data['salt'] ?? null, $customClaims, $data['tenantId'] ?? null, $validSince, ); } /** * @param UserMetadataResponseShape $data */ private static function userMetaDataFromResponseData(array $data): UserMetaData { return UserMetaData::fromResponseData($data); } /** * @param array{ * mfaInfo?: list<MfaInfoResponseShape> * } $data */ private static function mfaInfoFromResponseData(array $data): ?MfaInfo { if (!array_key_exists('mfaInfo', $data)) { return null; } $mfaInfo = array_shift($data['mfaInfo']); if ($mfaInfo === null) { return null; } return MfaInfo::fromResponseData($mfaInfo); } /** * @param array{providerUserInfo: list<ProviderUserInfoResponseShape>} $data * * @return list<UserInfo> */ private static function userInfoFromResponseData(array $data): array { return array_map( static fn (array $userInfoData) => UserInfo::fromResponseData($userInfoData), $data['providerUserInfo'], ); } }