Files
crewli/api/app/Models/Event.php
bert.hausmans 6848bc2c49 feat: schema v1.7 + sections/shifts frontend
- Universeel festival/event model (parent_event_id, event_type)
- event_person_activations pivot tabel
- Event model: parent/children relaties + helper scopes
- DevSeeder: festival structuur met sub-events
- Sections & Shifts frontend (twee-kolom layout)
- BACKLOG.md aangemaakt met 22 gedocumenteerde wensen
2026-04-08 07:23:56 +02:00

169 lines
4.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
final class Event extends Model
{
use HasFactory;
use HasUlids;
use SoftDeletes;
protected $fillable = [
'organisation_id',
'parent_event_id',
'name',
'slug',
'start_date',
'end_date',
'timezone',
'status',
'event_type',
'event_type_label',
'sub_event_label',
'is_recurring',
'recurrence_rule',
'recurrence_exceptions',
];
protected function casts(): array
{
return [
'start_date' => 'date',
'end_date' => 'date',
'is_recurring' => 'boolean',
'recurrence_exceptions' => 'array',
'event_type' => 'string',
];
}
public function organisation(): BelongsTo
{
return $this->belongsTo(Organisation::class);
}
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class, 'event_user_roles')
->withPivot('role')
->withTimestamps();
}
public function invitations(): HasMany
{
return $this->hasMany(UserInvitation::class);
}
public function locations(): HasMany
{
return $this->hasMany(Location::class);
}
public function festivalSections(): HasMany
{
return $this->hasMany(FestivalSection::class);
}
public function timeSlots(): HasMany
{
return $this->hasMany(TimeSlot::class);
}
public function persons(): HasMany
{
return $this->hasMany(Person::class);
}
public function crowdLists(): HasMany
{
return $this->hasMany(CrowdList::class);
}
public function parent(): BelongsTo
{
return $this->belongsTo(Event::class, 'parent_event_id');
}
public function children(): HasMany
{
return $this->hasMany(Event::class, 'parent_event_id')
->orderBy('start_date')
->orderBy('name');
}
// ----- Scopes -----
public function scopeTopLevel(Builder $query): Builder
{
return $query->whereNull('parent_event_id');
}
public function scopeChildren(Builder $query): Builder
{
return $query->whereNotNull('parent_event_id');
}
public function scopeFestivals(Builder $query): Builder
{
return $query->whereIn('event_type', ['festival', 'series']);
}
public function scopeWithChildren(Builder $query): Builder
{
return $query->where(function (Builder $q) {
$q->whereIn('id', function ($sub) {
$sub->select('id')->from('events')->whereNull('parent_event_id');
})->orWhereIn('parent_event_id', function ($sub) {
$sub->select('id')->from('events')->whereNull('parent_event_id');
});
});
}
// ----- Helpers -----
public function isFestival(): bool
{
return $this->event_type !== 'event' && $this->parent_event_id === null;
}
public function isSubEvent(): bool
{
return $this->parent_event_id !== null;
}
public function isFlatEvent(): bool
{
return $this->parent_event_id === null && $this->children()->count() === 0;
}
public function hasChildren(): bool
{
return $this->children()->exists();
}
public function scopeDraft(Builder $query): Builder
{
return $query->where('status', 'draft');
}
public function scopePublished(Builder $query): Builder
{
return $query->where('status', 'published');
}
public function scopeActive(Builder $query): Builder
{
return $query->whereIn('status', ['showday', 'buildup', 'teardown']);
}
}