205 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			205 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
<?php
 | 
						|
 | 
						|
namespace App\Form\Models;
 | 
						|
 | 
						|
use App\Form\Actions\UpdateParticipantSearchIndexAction;
 | 
						|
use App\Form\Data\ExportData;
 | 
						|
use App\Form\Data\FieldCollection;
 | 
						|
use App\Form\Data\FormConfigData;
 | 
						|
use App\Lib\Editor\Condition;
 | 
						|
use App\Lib\Editor\EditorData;
 | 
						|
use App\Lib\Sorting;
 | 
						|
use Cviebrock\EloquentSluggable\Sluggable;
 | 
						|
use Database\Factories\Form\Models\FormFactory;
 | 
						|
use Illuminate\Database\Eloquent\Factories\HasFactory;
 | 
						|
use Illuminate\Database\Eloquent\Model;
 | 
						|
use Illuminate\Database\Eloquent\Relations\HasMany;
 | 
						|
use Laravel\Scout\Searchable;
 | 
						|
use Spatie\Image\Enums\Fit;
 | 
						|
use Spatie\MediaLibrary\HasMedia;
 | 
						|
use Spatie\MediaLibrary\InteractsWithMedia;
 | 
						|
use Spatie\MediaLibrary\MediaCollections\Models\Media;
 | 
						|
use Zoomyboy\MedialibraryHelper\DefersUploads;
 | 
						|
 | 
						|
/** @todo replace editor content with EditorData cast */
 | 
						|
class Form extends Model implements HasMedia
 | 
						|
{
 | 
						|
    /** @use HasFactory<FormFactory> */
 | 
						|
    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<Participant>
 | 
						|
     */
 | 
						|
    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<string, mixed>
 | 
						|
     */
 | 
						|
    public function getRegistrationRules(): array
 | 
						|
    {
 | 
						|
        return $this->getFields()->reduce(fn ($carry, $field) => [
 | 
						|
            ...$carry,
 | 
						|
            ...$field->getRegistrationRules($this),
 | 
						|
        ], []);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @return array<string, mixed>
 | 
						|
     */
 | 
						|
    public function getRegistrationMessages(): array
 | 
						|
    {
 | 
						|
        return $this->getFields()->reduce(fn ($carry, $field) => [
 | 
						|
            ...$carry,
 | 
						|
            ...$field->getRegistrationMessages($this),
 | 
						|
        ], []);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @return array<string, mixed>
 | 
						|
     */
 | 
						|
    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<string, mixed>
 | 
						|
     */
 | 
						|
    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;
 | 
						|
    }
 | 
						|
}
 |