Files
landing-api/app/Models/Concerns/HasImages.php
Josep Piguillem 3897113313 Initial commit: Pireon Admin — headless admin panel and public API
Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer
collective, backed by the Pireon OAuth identity server. The public site is a
separate, server-rendered application consuming /api/public/v1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 17:55:27 +02:00

55 lines
1.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Models\Concerns;
use App\Models\Media;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* Keeps the media table in step with the image paths a record holds.
*
* The panel still uploads a file and stores its path, exactly as before; this
* is what turns that path into something the frontend can render properly.
* Models declare which of their attributes are images and expose an ordinary
* `belongsTo` relation for each, so a listing can eager-load them instead of
* asking once per row.
*/
trait HasImages
{
/**
* Attributes holding the path of an uploaded file.
*
* @return array<int, string>
*/
abstract public function imageAttributes(): array;
public static function bootHasImages(): void
{
static::saved(function (Model $model): void {
foreach ($model->imageAttributes() as $attribute) {
// Only on the way in or on a change: an unrelated save must
// not queue work for an image nobody touched.
if ($model->wasChanged($attribute) || $model->wasRecentlyCreated) {
Media::for($model->getAttribute($attribute));
}
}
});
}
/**
* Relation definition shared by every image attribute.
*
* The join is on the stored path rather than on an id, because the file is
* the identity: two records pointing at one upload share its dimensions
* and its derived versions instead of each deriving them again.
*/
protected function imageRelation(string $attribute): BelongsTo
{
return $this->belongsTo(Media::class, $attribute, 'path')
->where('media.disk', (string) config('media.disk', 'public'));
}
}