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>
This commit is contained in:
54
app/Models/Concerns/HasImages.php
Normal file
54
app/Models/Concerns/HasImages.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?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'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user