Files
coruna-lab/app/Models/PhotoRead.php
T
2026-09-06 03:55:24 +08:00

104 lines
2.6 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\Relation;
class PhotoRead extends Model
{
public $timestamps = false;
protected $fillable = [
'photo_id',
'actor_guard',
'actor_id',
'read_at',
];
protected function casts(): array
{
return [
'read_at' => 'datetime',
];
}
public function photo(): BelongsTo
{
return $this->belongsTo(Photo::class);
}
public static function mark(Photo $photo, string $guard, int $actorId): void
{
static::query()->firstOrCreate(
[
'photo_id' => $photo->id,
'actor_guard' => $guard,
'actor_id' => $actorId,
],
['read_at' => now()],
);
}
/**
* @param list<int> $photoIds
* @return list<int>
*/
public static function readPhotoIds(string $guard, int $actorId, array $photoIds): array
{
if ($photoIds === []) {
return [];
}
return static::query()
->where('actor_guard', $guard)
->where('actor_id', $actorId)
->whereIn('photo_id', $photoIds)
->pluck('photo_id')
->map(static fn ($id) => (int) $id)
->all();
}
public static function applyFilter(Builder|Relation $q, string $guard, int $actorId, string $photoIdColumn, mixed $read): void
{
$flag = self::parseReadFilter($read);
if ($flag === null) {
return;
}
$exists = function ($sub) use ($guard, $actorId, $photoIdColumn) {
$sub->from('photo_reads')
->whereColumn('photo_reads.photo_id', $photoIdColumn)
->where('photo_reads.actor_guard', $guard)
->where('photo_reads.actor_id', $actorId);
};
if ($flag) {
$q->whereExists($exists);
} else {
$q->whereNotExists($exists);
}
}
public static function parseReadFilter(mixed $raw): ?bool
{
if ($raw === null) {
return null;
}
$value = is_string($raw) ? strtolower(trim($raw)) : $raw;
if ($value === '' || $value === 'all') {
return null;
}
if ($value === 0 || $value === '0' || $value === 'unread') {
return false;
}
if ($value === 1 || $value === '1' || $value === 'read') {
return true;
}
return null;
}
}