ldc-crm/app/Models/Customer.php
2025-07-28 09:07:54 +02:00

242 lines
7.9 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* @property integer $id Id.
* @property string $email Email.
* @property-read \Illuminate\Support\Carbon $created_at Created date.
* @property-read \Illuminate\Support\Carbon $updated_at Updated date.
*
* @property-read \Illuminate\Database\Eloquent\Collection<App\Models\CustomerInfo>
* $infos CustomerInfo HasMany relation.
* @property-read \Illuminate\Database\Eloquent\Collection<App\Models\CustomerLogin>
* $logins CustomerLogin HasMany relation.
* @property-read \Illuminate\Database\Eloquent\Collection<App\Models\CustomerOptInHistory>
* $optInHistory CustomerOptInHistory HasMany relation.
* @property-read \Illuminate\Database\Eloquent\Collection<App\Models\Brand>
* $brands Brand BelongsToMany relation.
* @property-read \Illuminate\Database\Eloquent\Collection<App\Models\Answer>
* $answers Answer morph many relation.
*/
class Customer extends Model
{
use HasFactory;
public const FIRST_OR_NULL = 0;
public const FIRST_OR_NEW = 1;
public const FIRST_OR_FAIL = 2;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'email',
];
// * RELATIONS
/**
* CustomerInfo has many relation.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function infos(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(CustomerInfo::class);
}
/**
* CustomerLogin has many relation.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function logins(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(CustomerLogin::class);
}
/**
* CustomerOptInHistory has many relation.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function optInHistory(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(CustomerOptInHistory::class);
}
/**
* Customer Brand belongs to many relation.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function brands(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
{
return $this->belongsToMany(Brand::class, CustomerInfo::class);
}
/**
* Answers morph to many relation.
*
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
*/
public function answers(): \Illuminate\Database\Eloquent\Relations\MorphToMany
{
return $this->morphToMany(Answer::class, 'model', 'model_answer', 'model_id', 'answer_id');
}
/**
* Claim has many relation.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function claims(): \Illuminate\Database\Eloquent\Relations\HasMany
{
return $this->hasMany(Claim::class);
}
// * METHODS
/**
* Get the CustomerInfo from a specific brand
* or create a New one if $firstOrNewOrFail is 1
* throw model not found exception if firstOrNewOrFail = 2.
*
* @param \App\Models\Brand $brand
* @param integer $firstOrNewOrFail
* @return \App\Models\CustomerLogin|null
*/
public function info(Brand $brand, int $firstOrNewOrFail = self::FIRST_OR_NULL): ?CustomerInfo
{
if (isset($this->relations['infos'])) {
/** @var \App\Models\CustomerInfo $info */
foreach ($this->relations['infos'] as $info) {
if ($info->brand_id === $brand->id) {
return $info;
}
}
}
$query = CustomerInfo::query()->whereHas('brand', function (Builder $q) use ($brand) {
$q->where('id', $brand->id);
})->whereHas('customer', function (Builder $q) {
$q->where('id', $this->id);
});
if ($firstOrNewOrFail === self::FIRST_OR_NEW) {
return $query->firstOrNew();
}
if ($firstOrNewOrFail === self::FIRST_OR_FAIL) {
return $query->firstOrFail();
}
return $query->first();
}
/**
* Get the CustomerLogin from a specific brand
* or create a New one if $firstOrNewOrFail is 1
* throw model not found exception if firstOrNewOrFail = 2.
*
* @param \App\Models\Brand $brand
* @param integer $firstOrNewOrFail
* @return \App\Models\CustomerLogin|null
*/
public function login(Brand $brand, int $firstOrNewOrFail = self::FIRST_OR_NULL): ?CustomerLogin
{
if (isset($this->relations['logins'])) {
/** @var \App\Models\CustomerLogin $login */
foreach ($this->relations['logins'] as $login) {
if ($login->brand_id === $brand->id) {
return $login;
}
}
}
$query = CustomerLogin::query()->whereHas('brand', function (Builder $q) use ($brand) {
$q->where('id', $brand->id);
})->whereHas('customer', function (Builder $q) {
$q->where('id', $this->id);
});
if ($firstOrNewOrFail === self::FIRST_OR_NEW) {
return $query->firstOrNew();
}
if ($firstOrNewOrFail === self::FIRST_OR_FAIL) {
return $query->firstOrFail();
}
return $query->first();
}
/**
* Load login and info for this customer and this specific brand.
*
* @param \App\Models\Brand $brand
* @param boolean $orFail
* @return self
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException If no login or info was found for the brand.
*/
public function loadBrandData(Brand $brand, bool $orFail = false): self
{
$this->load([
'logins' => function (HasMany $q) use ($brand) {
$q->where('brand_id', $brand->id);
},
'infos' => function (HasMany $q) use ($brand) {
$q->where('brand_id', $brand->id);
}
]);
if ($orFail and !isset($this->relations['logins'][0])) {
throw (new ModelNotFoundException())->setModel(CustomerLogin::class);
}
if ($orFail and !isset($this->relations['infos'][0])) {
throw (new ModelNotFoundException())->setModel(CustomerInfo::class);
}
return $this;
}
/**
* Set this customer as optin.
*
* @param \App\Models\Brand $brand
* @param boolean $optIn
* @return void
* @throws \Throwable If customer history update failed.
*/
public function setOptIn(Brand $brand, bool $optIn): void
{
$this->opt_in = $optIn;
// * Ajout dans la table d'historique des opt-in de la nouvelle valeur.
$optInHistory = new CustomerOptInHistory();
$optInHistory->new_value = $optIn;
$optInHistory->customer()->associate($this);
$optInHistory->brand()->associate($brand);
$optInHistory->saveOrFail();
}
/**
* Get All answers given by this customer
* for a specific service.
*
* @param \App\Models\Service $service
* @return \Illuminate\Database\Eloquent\Collection
*/
public function getAnswers(Service $service): \Illuminate\Database\Eloquent\Collection
{
return Answer::query()
->whereHas('customers', function (Builder $q) {
$q->where('id', $this->id);
})
->whereHas('question', function (Builder $q) use ($service) {
$q->whereHas('brand', function (Builder $q) use ($service) {
$q->where('id', $service->brand->id);
});
})
->get();
}
}