*/ use HasFactory; use Sluggable; use InteractsWithMedia; use DefersUploads; use Searchable; public $guarded = []; public $casts = [ 'config' => FormConfigData::class, 'meta' => 'json', 'description' => EditorData::class, 'mail_top' => EditorData::class, 'mail_bottom' => EditorData::class, 'is_active' => 'boolean', 'is_private' => 'boolean', 'export' => ExportData::class, 'needs_prevention' => 'boolean', 'prevention_text' => EditorData::class, 'prevention_conditions' => Condition::class, 'from' => 'datetime', 'to' => 'datetime', 'registration_from' => 'datetime', 'registration_until' => 'datetime', ]; /** * @return SluggableConfig */ public function sluggable(): array { return [ 'slug' => ['source' => ['name']], ]; } /** * @return HasMany */ public function participants(): HasMany { return $this->hasMany(Participant::class); } public function registerMediaCollections(): void { $this->addMediaCollection('headerImage') ->singleFile() ->maxWidth(fn() => 500) ->forceFileName(fn(Form $model, string $name) => $model->slug) ->convert(fn() => 'jpg') ->registerMediaConversions(function (Media $media) { $this->addMediaConversion('square')->fit(Fit::Crop, 400, 400); }); $this->addMediaCollection('mailattachments') ->withDefaultProperties(fn() => [ 'conditions' => [ 'mode' => 'all', 'ifs' => [] ], ]) ->withPropertyValidation(fn() => [ 'conditions.mode' => 'required|string|in:all,any', 'conditions.ifs' => 'array', 'conditions.ifs.*.field' => 'required', 'conditions.ifs.*.comparator' => 'required', 'conditions.ifs.*.value' => 'present', ]); } /** * @return array */ public function getRegistrationRules(): array { return $this->getFields()->reduce(fn($carry, $field) => [ ...$carry, ...$field->getRegistrationRules($this), ], []); } /** * @return array */ public function getRegistrationMessages(): array { return $this->getFields()->reduce(fn($carry, $field) => [ ...$carry, ...$field->getRegistrationMessages($this), ], []); } /** * @return array */ public function getRegistrationAttributes(): array { return $this->getFields()->reduce(fn($carry, $field) => [ ...$carry, ...$field->getRegistrationAttributes($this), ], []); } public function getFields(): FieldCollection { return $this->config->fields(); } // --------------------------------- Searching --------------------------------- // ***************************************************************************** /** * Get the indexable data array for the model. * * @return array */ public function toSearchableArray() { return [ 'from' => $this->from->timestamp, 'to' => $this->to->timestamp, 'name' => $this->name, 'is_active' => $this->is_active, 'is_private' => $this->is_private, ]; } public static function booted(): void { static::saving(function (self $model) { if (is_null(data_get($model->meta, 'active_columns'))) { $model->setAttribute('meta', [ 'active_columns' => $model->getFields()->count() ? $model->getFields()->take(4)->pluck('key')->toArray() : null, 'sorting' => Sorting::by('id'), ]); return; } if (is_array(data_get($model->meta, 'active_columns'))) { $model->setAttribute('meta', [ ...$model->meta, 'active_columns' => array_values(array_intersect([...$model->getFields()->pluck('key')->toArray(), 'created_at', 'prevention'], $model->meta['active_columns'])), ]); return; } }); static::saved(function ($model) { UpdateParticipantSearchIndexAction::dispatch($model); }); } public function participantsSearchableAs(): string { return config('scout.prefix') . 'forms_' . $this->id . '_participants'; } public function defaultSorting(): Sorting { return Sorting::from($this->meta['sorting']); } public function canRegister(): bool { if ($this->registration_from && $this->registration_from->gt(now())) { return false; } if ($this->registration_until && $this->registration_until->lt(now())) { return false; } return true; } public function payload(): array { return [ 'dateFrom' => $this->dateFrom()->format('Y-m-d'), 'eventName' => $this->name, 'members' => [], ]; } /** * @return class-string */ public function type(): string { return request()->input('type'); } public function dateFrom(): Carbon { return now(); } public function dateUntil(): Carbon { return now(); } public function zipLocation(): string { return ''; } public function eventName(): string { return $this->name; } public function members(): Collection { $members = []; $fields = [ [SpecialType::FIRSTNAME, 'firstname'], [SpecialType::LASTNAME, 'lastname'], [SpecialType::BIRTHDAY, 'birthday'], [SpecialType::ADDRESS, 'address'], [SpecialType::ZIP, 'zip'], [SpecialType::LOCATION, 'location'] ]; foreach ($this->participants as $participant) { $member = []; foreach ($fields as [$type, $name]) { $f = $this->getFields()->findBySpecialType($type); $member[$name] = $participant->getFields()->find($f)->value; } $members[] = [ 'is_leader' => false, 'gender' => null, ...$member, ]; } return MemberData::fromApi($members); } public function country(): ?Country { return Country::first(); } public function validateContribution(): void { $messages = []; foreach ($this->type()::requiredFormSpecialTypes() as $type) { if (!$this->getFields()->hasSpecialType($type)) { $messages[$type->name] = 'Kein Feld für ' . $type->value . ' vorhanden.'; } } if ($this->participants->count() === 0) { $messages['participants'] = 'Veranstaltung besitzt noch keine Teilnehmer*innen.'; } throw_unless(empty($messages), ValidationException::withMessages($messages)); } }