$model */ public function __construct( Hasher $hasher, string $model, private readonly CrmService $crmService ) { parent::__construct($hasher, $model); } /** * The model to use, specified in auth config guard. * * @var class-string<\App\Models\Customer> */ private $usedModel = Customer::class; /** * Retrieve a user by the given credentials. * * @param array $credentials * * @throws \RuntimeException If connection to server fails. * @throws \LDC\LDCCRM\Exceptions\CrmException On CRM call error. * @throws \Exception On CRM call error. */ #[\Override] public function retrieveByCredentials(array $credentials): ?Authenticatable { $model = parent::retrieveByCredentials($credentials); $result = $this->crmService->getCustomerFromEmail(Arr::string($credentials, 'email')); if ($result instanceof CrmServiceException) { report($result); throw ValidationException::withMessages([ \trans('An error has occurred. Please try again later'), ]); } $this->crmCustomer = $result; if ($this->crmCustomer instanceof CrmCustomer && $model === null) { $model = $this->createLocalCustomer($this->crmCustomer); } return $this->crmCustomer !== null ? $model : null; } /** * Validate a user against the given credentials. * * @param array $credentials * * @throws \RuntimeException If model provided is not a Customer or connection to server fails. * @throws \LDC\LDCCRM\Exceptions\CrmException On CRM call error. * @throws \Exception On CRM call error. */ #[\Override] public function validateCredentials(Authenticatable $model, array $credentials): bool { if ($model::class !== $this->usedModel) { throw new UnexpectedValueException("Cannot authenticate any thing else than '{$this->usedModel}'"); } if (! in_array(MustVerifyEmail::class, \class_implements($model))) { throw new UnexpectedValueException("Model '{$this->usedModel}' should implement 'MustVerifyEmail'"); } /** @var \Illuminate\Contracts\Auth\Authenticatable&\Illuminate\Contracts\Auth\MustVerifyEmail $model */ $requestEmail = Arr::string($credentials, 'email'); $requestPassword = Arr::string($credentials, 'password'); try { $this->crmService->login( $requestEmail, $requestPassword ); return true; } catch (CrmCustomerNotActivatedException) { $model->sendEmailVerificationNotification(); return true; } catch (CrmAuthenticationFailedException) { return false; } catch (CrmServiceException $e) { report($e); throw ValidationException::withMessages([ trans('An error has occurred. Please try again later'), ]); } } /** @param array $credentials */ #[\Override] public function rehashPasswordIfRequired(Authenticatable $user, #[\SensitiveParameter] array $credentials, bool $force = false): void { // No hashing. } private function createLocalCustomer(CrmCustomer $crmCustomer): Model & Authenticatable { $email = $crmCustomer->email ? new Email($crmCustomer->email) : throw new UnexpectedValueException('Email is required ti create a customer'); $hashcode = $crmCustomer->hashcode ? $crmCustomer->hashcode : throw new UnexpectedValueException('Hashcode is required to create a customer'); /** @var \App\Models\Customer&\Illuminate\Contracts\Auth\Authenticatable $model */ $model = $this->usedModel::query() ->where('email', $crmCustomer->email) ->firstOrNew(); $model->email = $email; $model->hashcode = CrmHashcode::fromString($hashcode); $model->saveOrFail(); return $model; } }