$departaimantsCollections */ class Customer extends Authenticatable implements MustVerifyEmail { use HasFactory; use Notifiable; use Prunable; use SoftDeletes; /** * Perform any actions required after the model boots. * * @return void */ protected static function booted() { // * EVENT CLOSURES. self::creating(function (self $model) { self::assertEmailIsUnique($model->id, $model->email); }); self::updating(function (self $model) { self::assertEmailIsUnique($model->id, $model->email); }); self::deleted(function (self $model) { if ($model->forceDeleting) { $model->notify(new DestroyedCustomer()); } else { $model->notify(new DestroyCustomer()); } }); self::restored(function () { \session()->flash( 'warning', \trans('Votre compte à été réactivé.') ); }); } // * RELATIONSHIPS /** * Get all of the departaimant collections for the Customer * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function departaimantsCollections(): HasMany { return $this->hasMany(DepartaimantsCollection::class); } /** * The notifications that belong to the Customer * * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function notifications(): BelongsToMany { return $this->belongsToMany(Notifications::class); } /** * The read notifications that belong to the Customer * * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function readNotifications(): BelongsToMany { return $this->belongsToMany(Notifications::class, 'notifications_read', 'customer_id', 'notification_id'); } /** * Get all of the messages for the Customer * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function messages(): HasMany { return $this->hasMany(Message::class, 'to'); } /** * Get all of the sentMessages for the Customer * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function sentMessages(): HasMany { return $this->hasMany(Message::class, 'from'); } // * METHODS /** * Get conversations with messages sorted by time * * @return array */ public function conversations(): array { $dateSort = fn (Message $a, Message $b) => $a->created_at->timestamp > $b->created_at->timestamp; $messageFilter = fn (Collection $item) => $item->all(); $messageWith = [ 'fromCustomer' => fn (Builder $q) => $q->select(['id', 'username', 'created_at']), 'toCustomer' => fn (Builder $q) => $q->select(['id', 'username', 'created_at']) ]; /** * Hack workaround https://github.com/livewire/livewire/issues/1054 */ $sentM = $this->sentMessages() ->where('hide_from', false) ->with($messageWith)->get() ->groupBy('toCustomer.username') ->map($messageFilter)->toBase(); $receivedM = $this->messages() ->where('hide_to', false)->with($messageWith)->get() ->groupBy('fromCustomer.username')->map($messageFilter)->toBase(); $output = $receivedM->mapWithKeys(function (array $messagesArray, string $fromUsername) use (&$sentM, $dateSort) { // @phpstan-ignore-next-line $responses = collect(\array_merge($sentM->pull($fromUsername) ?? [], $messagesArray))->sort($dateSort); $last = $responses->last(); return [$fromUsername => collect([ 'to' => $fromUsername, 'to_id' => collect($messagesArray)->first()->fromCustomer->id, 'id' => $last->id, 'date' => $last->created_at, 'dateRaw' => $last->getRawOriginal('created_at'), 'preview' => str($last->message)->limit(15), 'messages' => $responses->values()->all() ])]; })->toBase(); // * Map sur les message envoyés (qui n'ont pas encore eu de réponses) $outputSentM = $sentM->mapWithKeys(function ($messagesArray) { $sent = collect($messagesArray); $last = $sent->last(); $toCustomer = $last->toCustomer; $toUserName = $toCustomer->username; return [$toUserName => collect([ 'to' => $toUserName, 'to_id' => $toCustomer->id, 'id' => $last->id, 'date' => $last->created_at, 'dateRaw' => $last->getRawOriginal('created_at'), 'preview' => str($last->message)->limit(15), 'messages' => $sent->values()->all() ])]; })->toBase(); return $output->merge($outputSentM)->sort(function ($a, $b) { return Carbon::parse( Arr::get($a, 'dateRaw') )->timestamp < Carbon::parse(Arr::get($b, 'dateRaw'))->timestamp; })->toArray(); } /** * Asserts using validation that the email is unique * * @param mixed $id * @param mixed $email * @return void * @throws \Illuminate\Validation\ValidationException If user email as already used. */ private static function assertEmailIsUnique(mixed $id, mixed $email): void { self::assertFieldIsUnique($id, 'email', $email); } /** * Asserts that the field is unique * * @param mixed $id * @param string $field * @param mixed $value * @return void * @throws \Illuminate\Validation\ValidationException If the field is not unique. */ private static function assertFieldIsUnique(mixed $id, string $field, mixed $value): void { Validator::make([$field => $value], [ $field => Rule::unique('customers', $field)->ignore($id), ], [ $field . '.unique' => trans('La valeur :value pour le champ :attribute est déjà utilisé', [ 'attribute' => $field, 'value' => $value ]) ])->validate(); } /** * Get all user Departaimant collection or create them if they dont exists * * @return \Illuminate\Support\Collection<\App\Models\DepartaimantsCollection> */ public function getOrCreateAllDepartaimentsCollections(): Collection { $collections = $this->departaimantsCollections()->get() ->keyBy(fn (DepartaimantsCollection $el) => $el->type->value()); foreach (DepartaimantCollectionType::all() as $depColectionType) { if (!$collections->has($depColectionType->value())) { $depCollection = new DepartaimantsCollection([ 'type' => $depColectionType->value ]); $depCollection->customer()->associate($this); $depCollection->save(); $collections->add($depCollection); } } return $collections; } /** * Get all notifications * * @return \Illuminate\Database\Eloquent\Collection<\App\Models\Notifications> */ public function getAllNotifications(): \Illuminate\Database\Eloquent\Collection { return Notifications::query() ->whereHas('customer', fn (Builder $q) => $q->where('id', $this->id)) ->orWhere('customer_id', null) ->with('notifiable') ->orderBy('created_at', 'DESC') ->get(); } // * --- AUTH --- /** * Send the email verification notification. * * @return void */ public function sendEmailVerificationNotification() { $this->notify(new VerifyEmail()); } /** * Send the password reset notification. * * @param mixed $token * @return void */ public function sendPasswordResetNotification(mixed $token) { /** @var string $token */ $this->notify(new ResetPassword($token)); } }