ldc-legaulois/app/Models/Customer.php
2024-07-17 12:45:43 +02:00

276 lines
9.1 KiB
PHP

<?php
namespace App\Models;
use App\Enums\Departaimants\DepartaimantCollectionType;
use App\Notifications\Customer\DestroyCustomer;
use App\Notifications\Customer\DestroyedCustomer;
use App\Notifications\Customer\ResetPassword;
use App\Notifications\Customer\VerifyEmail;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Contracts\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Prunable;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
/**
*
* @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\DepartaimantsCollection>$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));
}
}