*/ use BumpsContentVersion, HasContentViews, HasFactory, HasRevisions, HasTranslations, RecordsSlugChanges; /** @var array */ public array $translatable = ['title', 'slug', 'description', 'what_you_get']; /** @var array */ protected $attributes = [ 'status' => CallStatus::Open->value, ]; protected function casts(): array { return [ 'status' => CallStatus::class, 'hours_per_week' => 'integer', 'duration_weeks' => 'integer', 'opens_at' => 'date', 'closes_at' => 'date', ]; } /** * The `site.paths` key this model publishes under, so a slug change knows * which URL it just broke. */ public function publicPathType(): string { return 'call'; } /** * @return BelongsTo */ public function project(): BelongsTo { return $this->belongsTo(Project::class); } /** * @return BelongsToMany */ public function technologies(): BelongsToMany { return $this->belongsToMany(Technology::class); } /** * The people who answered this call. * * @return HasMany */ public function applications(): HasMany { return $this->hasMany(Application::class); } /** * Open, within its window, and — when tied to a project — only while that * project is itself published. * * @param Builder<$this> $query * @return Builder<$this> */ public function scopeOpen(Builder $query): Builder { return $query ->where('status', CallStatus::Open) ->where(fn (Builder $q) => $q->whereNull('opens_at')->orWhere('opens_at', '<=', now())) ->where(fn (Builder $q) => $q->whereNull('closes_at')->orWhere('closes_at', '>=', now())); } /** * Total time being asked for, which is what a prospective contributor is * really weighing up. */ public function totalHours(): ?int { if ($this->hours_per_week === null || $this->duration_weeks === null) { return null; } return $this->hours_per_week * $this->duration_weeks; } /** * @param Builder<$this> $query * @return Builder<$this> */ public function scopeWhereSlug(Builder $query, string $slug, ?string $locale = null): Builder { $locale ??= app()->getLocale(); return $query->where("slug->{$locale}", $slug); } }