kithkin/app/Models/User.php

219 lines
5.8 KiB
PHP

<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use App\Models\UserSetting;
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Str;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, Notifiable;
use HasUlids; // generates ULIDs automatically
protected $keyType = 'string';
public $incrementing = false;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'firstname',
'lastname',
'displayname',
'name',
'email',
'timezone',
'phone',
'locale',
];
/**
* The attributes that should be hidden for serialization.
*
* @var list<string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
/**
* Expose a Breeze-compatible "name" attribute without a physical column.
* Preference: displayname (explicit override), then first + last, then email.
*/
public function getNameAttribute(): string
{
$displayname = is_string($this->displayname) ? trim($this->displayname) : '';
if ($displayname !== '') {
return $displayname;
}
$first = is_string($this->firstname) ? trim($this->firstname) : '';
$last = is_string($this->lastname) ? trim($this->lastname) : '';
$full = trim($first . ' ' . $last);
if ($full !== '') {
return $full;
}
return (string) ($this->email ?? '');
}
/**
* Map "name" writes to first/last names, keeping displayname optional.
*/
public function setNameAttribute(?string $value): void
{
$incoming = trim((string) $value);
$currentFirst = is_string($this->attributes['firstname'] ?? null)
? trim((string) $this->attributes['firstname'])
: '';
$currentLast = is_string($this->attributes['lastname'] ?? null)
? trim((string) $this->attributes['lastname'])
: '';
$currentGenerated = trim($currentFirst . ' ' . $currentLast);
if ($incoming === '') {
$this->attributes['firstname'] = null;
$this->attributes['lastname'] = null;
return;
}
$parts = preg_split('/\s+/', $incoming, 2);
$this->attributes['firstname'] = $parts[0] ?? null;
$this->attributes['lastname'] = $parts[1] ?? null;
$displayname = is_string($this->attributes['displayname'] ?? null)
? trim((string) $this->attributes['displayname'])
: '';
if ($displayname !== '' && $displayname === $currentGenerated) {
$this->attributes['displayname'] = $incoming;
}
}
/**
* user can own many calendars
*/
public function calendars(): HasMany
{
return $this->hasMany(Calendar::class);
}
/**
* get the current user's principal uri
*/
public function getPrincipalUriAttribute(): string
{
return 'principals/' . $this->email;
}
/**
* get all user addresses
*/
public function addresses()
{
return $this->hasMany(\App\Models\UserAddress::class, 'user_id', 'id');
}
/**
* get the user's billing address
*/
public function billingAddress()
{
return $this->addresses()
->where('kind', 'billing')
->where('is_primary', 1)
->first();
}
/**
* user can have many settings
*/
public function userSettings(): HasMany
{
return $this->hasMany(UserSetting::class, 'user_id');
}
/**
* get a user setting by key
*/
public function getSetting(string $key, mixed $default = null): mixed
{
// avoid repeated queries if the relationship is already eager loaded
if ($this->relationLoaded('userSettings')) {
$match = $this->userSettings->firstWhere('key', $key);
return $match?->value ?? $default;
}
$value = $this->userSettings()
->where('key', $key)
->value('value');
return $value ?? $default;
}
/**
* set a user setting by key
*/
public function setSetting(string $key, mixed $value): void
{
// store everything as a string in the value column
$stringValue = is_null($value) ? null : (string) $value;
$this->userSettings()->updateOrCreate(
['key' => $key],
['value' => $stringValue],
);
// keep in-memory relation in sync if it was loaded
if ($this->relationLoaded('userSettings')) {
$existing = $this->userSettings->firstWhere('key', $key);
if ($existing) {
$existing->value = $stringValue;
} else {
$this->userSettings->push(new UserSetting([
'user_id' => $this->getKey(),
'key' => $key,
'value' => $stringValue,
]));
}
}
}
/**
* convenience: set many settings at once
*/
public function setSettings(array $pairs): void
{
foreach ($pairs as $key => $value) {
$this->setSetting($key, $value);
}
}
}