Add register action
This commit is contained in:
parent
89429f9812
commit
5d9d7a0ffc
app/Form
Actions
Fields
CheckboxField.phpCheckboxesField.phpDateField.phpDropdownField.phpField.phpGroupField.phpRadioField.phpTextField.phpTextareaField.php
Models
database/migrations
routes
tests/Feature/Form
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Form\Actions;
|
||||||
|
|
||||||
|
use App\Form\Models\Form;
|
||||||
|
use App\Form\Models\Participant;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Lorisleiva\Actions\ActionRequest;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
|
class RegisterAction
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
|
||||||
|
public function handle(Form $form, array $input): Participant
|
||||||
|
{
|
||||||
|
return $form->participants()->create([
|
||||||
|
'data' => $input
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
/** @var Form */
|
||||||
|
$form = request()->route('form');
|
||||||
|
|
||||||
|
return $form->getRegistrationRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function getValidationAttributes(): array
|
||||||
|
{
|
||||||
|
/** @var Form */
|
||||||
|
$form = request()->route('form');
|
||||||
|
|
||||||
|
return $form->getRegistrationAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function getValidationMessages(): array
|
||||||
|
{
|
||||||
|
/** @var Form */
|
||||||
|
$form = request()->route('form');
|
||||||
|
|
||||||
|
return $form->getRegistrationMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asController(ActionRequest $request, Form $form): JsonResponse
|
||||||
|
{
|
||||||
|
$participant = $this->handle($form, $request->validated());
|
||||||
|
|
||||||
|
return response()->json($participant);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,9 +3,15 @@
|
||||||
namespace App\Form\Fields;
|
namespace App\Form\Fields;
|
||||||
|
|
||||||
use Faker\Generator;
|
use Faker\Generator;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class CheckboxField extends Field
|
class CheckboxField extends Field
|
||||||
{
|
{
|
||||||
|
public string $name;
|
||||||
|
public string $key;
|
||||||
|
public bool $required;
|
||||||
|
public string $description;
|
||||||
|
|
||||||
public static function name(): string
|
public static function name(): string
|
||||||
{
|
{
|
||||||
return 'Checkbox';
|
return 'Checkbox';
|
||||||
|
@ -31,4 +37,32 @@ class CheckboxField extends Field
|
||||||
'required' => $faker->boolean(),
|
'required' => $faker->boolean(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationRules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
$this->key => $this->required ? ['boolean', 'accepted'] : ['present', 'boolean'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationAttributes(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
$this->key => $this->name,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationMessages(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,15 @@
|
||||||
namespace App\Form\Fields;
|
namespace App\Form\Fields;
|
||||||
|
|
||||||
use Faker\Generator;
|
use Faker\Generator;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class CheckboxesField extends Field
|
class CheckboxesField extends Field
|
||||||
{
|
{
|
||||||
|
public string $name;
|
||||||
|
public string $key;
|
||||||
|
/** @var array<int, string> */
|
||||||
|
public array $options;
|
||||||
|
|
||||||
public static function name(): string
|
public static function name(): string
|
||||||
{
|
{
|
||||||
return 'Checkboxes';
|
return 'Checkboxes';
|
||||||
|
@ -29,4 +35,34 @@ class CheckboxesField extends Field
|
||||||
'options' => $faker->words(4),
|
'options' => $faker->words(4),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationRules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
$this->key => 'array',
|
||||||
|
$this->key . '.*' => ['string', Rule::in($this->options)],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationAttributes(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
...collect($this->options)->mapWithKeys(fn ($option, $key) => [$this->key . '.' . $key => $this->name])->toArray(),
|
||||||
|
$this->key => $this->name,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationMessages(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,12 @@ use Faker\Generator;
|
||||||
|
|
||||||
class DateField extends Field
|
class DateField extends Field
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public string $name;
|
||||||
|
public string $key;
|
||||||
|
public bool $required;
|
||||||
|
public bool $maxToday;
|
||||||
|
|
||||||
public static function name(): string
|
public static function name(): string
|
||||||
{
|
{
|
||||||
return 'Datum';
|
return 'Datum';
|
||||||
|
@ -31,4 +37,40 @@ class DateField extends Field
|
||||||
'max_today' => $faker->boolean(),
|
'max_today' => $faker->boolean(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationRules(): array
|
||||||
|
{
|
||||||
|
$rules = [$this->required ? 'required' : 'nullable'];
|
||||||
|
|
||||||
|
$rules[] = 'date';
|
||||||
|
|
||||||
|
if ($this->maxToday) {
|
||||||
|
$rules[] = 'before_or_equal:' . now()->format('Y-m-d');
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$this->key => $rules];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationAttributes(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
$this->key => $this->name,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationMessages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
$this->key . '.before_or_equal' => $this->name . ' muss ein Datum vor oder gleich dem ' . now()->format('d.m.Y') . ' sein.',
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,16 @@
|
||||||
namespace App\Form\Fields;
|
namespace App\Form\Fields;
|
||||||
|
|
||||||
use Faker\Generator;
|
use Faker\Generator;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class DropdownField extends Field
|
class DropdownField extends Field
|
||||||
{
|
{
|
||||||
|
public string $name;
|
||||||
|
public string $key;
|
||||||
|
public bool $required;
|
||||||
|
/** @var array<int, string> */
|
||||||
|
public array $options;
|
||||||
|
|
||||||
public static function name(): string
|
public static function name(): string
|
||||||
{
|
{
|
||||||
return 'Dropdown';
|
return 'Dropdown';
|
||||||
|
@ -31,4 +38,30 @@ class DropdownField extends Field
|
||||||
'required' => $faker->boolean(),
|
'required' => $faker->boolean(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationRules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
$this->key => $this->required ? ['required', 'string', Rule::in($this->options)] : ['nullable', 'string', Rule::in($this->options)],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationAttributes(): array
|
||||||
|
{
|
||||||
|
return [$this->key => $this->name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationMessages(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,12 @@ namespace App\Form\Fields;
|
||||||
|
|
||||||
use Faker\Generator;
|
use Faker\Generator;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Spatie\LaravelData\Data;
|
||||||
|
use Spatie\LaravelData\Attributes\MapInputName;
|
||||||
|
use Spatie\LaravelData\Mappers\SnakeCaseMapper;
|
||||||
|
|
||||||
abstract class Field
|
#[MapInputName(SnakeCaseMapper::class)]
|
||||||
|
abstract class Field extends Data
|
||||||
{
|
{
|
||||||
|
|
||||||
abstract public static function name(): string;
|
abstract public static function name(): string;
|
||||||
|
@ -16,6 +20,15 @@ abstract class Field
|
||||||
/** @return mixed */
|
/** @return mixed */
|
||||||
abstract public static function default();
|
abstract public static function default();
|
||||||
|
|
||||||
|
/** @return array<string, mixed> */
|
||||||
|
abstract public function getRegistrationRules(): array;
|
||||||
|
|
||||||
|
/** @return array<string, mixed> */
|
||||||
|
abstract public function getRegistrationAttributes(): array;
|
||||||
|
|
||||||
|
/** @return array<string, mixed> */
|
||||||
|
abstract public function getRegistrationMessages(): array;
|
||||||
|
|
||||||
/** @return array<string, mixed> */
|
/** @return array<string, mixed> */
|
||||||
abstract public static function fake(Generator $faker): array;
|
abstract public static function fake(Generator $faker): array;
|
||||||
|
|
||||||
|
@ -50,6 +63,14 @@ abstract class Field
|
||||||
return $fieldClass;
|
return $fieldClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $config
|
||||||
|
*/
|
||||||
|
public static function fromConfig(array $config): static
|
||||||
|
{
|
||||||
|
return static::classFromType($config['type'])::withoutMagicalCreationFrom($config);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array<string, string>
|
* @return array<string, string>
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -9,6 +9,12 @@ use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class GroupField extends Field
|
class GroupField extends Field
|
||||||
{
|
{
|
||||||
|
public string $name;
|
||||||
|
public string $key;
|
||||||
|
public bool $required;
|
||||||
|
public ?string $parentField = null;
|
||||||
|
public ?int $parentGroup = null;
|
||||||
|
|
||||||
public static function name(): string
|
public static function name(): string
|
||||||
{
|
{
|
||||||
return 'Gruppierungs-Auswahl';
|
return 'Gruppierungs-Auswahl';
|
||||||
|
@ -36,4 +42,41 @@ class GroupField extends Field
|
||||||
'parent_group' => null,
|
'parent_group' => null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationRules(): array
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [$this->required ? 'required' : 'nullable'];
|
||||||
|
|
||||||
|
$rules[] = 'integer';
|
||||||
|
|
||||||
|
if ($this->parentGroup) {
|
||||||
|
$rules[] = Rule::in(Group::find($this->parentGroup)->children()->pluck('id'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->parentField && request()->input($this->parentField)) {
|
||||||
|
$rules[] = Rule::in(Group::find(request()->input($this->parentField))->children()->pluck('id'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$this->key => $rules];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationAttributes(): array
|
||||||
|
{
|
||||||
|
return [$this->key => $this->name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationMessages(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,16 @@
|
||||||
namespace App\Form\Fields;
|
namespace App\Form\Fields;
|
||||||
|
|
||||||
use Faker\Generator;
|
use Faker\Generator;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class RadioField extends Field
|
class RadioField extends Field
|
||||||
{
|
{
|
||||||
|
public string $name;
|
||||||
|
public string $key;
|
||||||
|
public bool $required;
|
||||||
|
/** @var array<int, string> */
|
||||||
|
public array $options;
|
||||||
|
|
||||||
public static function name(): string
|
public static function name(): string
|
||||||
{
|
{
|
||||||
return 'Radio';
|
return 'Radio';
|
||||||
|
@ -31,4 +38,30 @@ class RadioField extends Field
|
||||||
'required' => $faker->boolean(),
|
'required' => $faker->boolean(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationRules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
$this->key => $this->required ? ['required', 'string', Rule::in($this->options)] : ['nullable', 'string', Rule::in($this->options)],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationAttributes(): array
|
||||||
|
{
|
||||||
|
return [$this->key => $this->name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationMessages(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,11 @@ use Faker\Generator;
|
||||||
|
|
||||||
class TextField extends Field
|
class TextField extends Field
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public string $name;
|
||||||
|
public string $key;
|
||||||
|
public bool $required;
|
||||||
|
|
||||||
public static function name(): string
|
public static function name(): string
|
||||||
{
|
{
|
||||||
return 'Text';
|
return 'Text';
|
||||||
|
@ -29,4 +34,28 @@ class TextField extends Field
|
||||||
'required' => $faker->boolean(),
|
'required' => $faker->boolean(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationRules(): array
|
||||||
|
{
|
||||||
|
return [$this->key => $this->required ? ['required', 'string'] : ['nullable', 'string']];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationAttributes(): array
|
||||||
|
{
|
||||||
|
return [$this->key => $this->name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationMessages(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,10 @@ use Faker\Generator;
|
||||||
|
|
||||||
class TextareaField extends Field
|
class TextareaField extends Field
|
||||||
{
|
{
|
||||||
|
public string $name;
|
||||||
|
public string $key;
|
||||||
|
public bool $required;
|
||||||
|
|
||||||
public static function name(): string
|
public static function name(): string
|
||||||
{
|
{
|
||||||
return 'Textarea';
|
return 'Textarea';
|
||||||
|
@ -31,4 +35,28 @@ class TextareaField extends Field
|
||||||
'required' => $faker->boolean(),
|
'required' => $faker->boolean(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationRules(): array
|
||||||
|
{
|
||||||
|
return [$this->key => $this->required ? ['required', 'string'] : ['nullable', 'string']];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationAttributes(): array
|
||||||
|
{
|
||||||
|
return [$this->key => $this->name];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
public function getRegistrationMessages(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,12 @@
|
||||||
|
|
||||||
namespace App\Form\Models;
|
namespace App\Form\Models;
|
||||||
|
|
||||||
|
use App\Form\Fields\Field;
|
||||||
use Cviebrock\EloquentSluggable\Sluggable;
|
use Cviebrock\EloquentSluggable\Sluggable;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
use Laravel\Scout\Searchable;
|
use Laravel\Scout\Searchable;
|
||||||
use Spatie\Image\Manipulations;
|
use Spatie\Image\Manipulations;
|
||||||
use Spatie\MediaLibrary\HasMedia;
|
use Spatie\MediaLibrary\HasMedia;
|
||||||
|
@ -27,6 +30,9 @@ class Form extends Model implements HasMedia
|
||||||
'description' => 'json',
|
'description' => 'json',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/** @var array<int, string> */
|
||||||
|
public $dates = ['from', 'to', 'registration_from', 'registration_until'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return SluggableConfig
|
* @return SluggableConfig
|
||||||
*/
|
*/
|
||||||
|
@ -37,6 +43,15 @@ class Form extends Model implements HasMedia
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return HasMany<Participant, self>
|
||||||
|
*/
|
||||||
|
public function participants(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Participant::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function registerMediaCollections(): void
|
public function registerMediaCollections(): void
|
||||||
{
|
{
|
||||||
$this->addMediaCollection('headerImage')
|
$this->addMediaCollection('headerImage')
|
||||||
|
@ -48,8 +63,59 @@ class Form extends Model implements HasMedia
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var array<int, string> */
|
/**
|
||||||
public $dates = ['from', 'to', 'registration_from', 'registration_until'];
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function getRegistrationRules(): array
|
||||||
|
{
|
||||||
|
return $this->getFields()->reduce(function ($carry, $current) {
|
||||||
|
$field = Field::fromConfig($current);
|
||||||
|
|
||||||
|
return [
|
||||||
|
...$carry,
|
||||||
|
...$field->getRegistrationRules(),
|
||||||
|
];
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function getRegistrationMessages(): array
|
||||||
|
{
|
||||||
|
return $this->getFields()->reduce(function ($carry, $current) {
|
||||||
|
$field = Field::fromConfig($current);
|
||||||
|
|
||||||
|
return [
|
||||||
|
...$carry,
|
||||||
|
...$field->getRegistrationMessages(),
|
||||||
|
];
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function getRegistrationAttributes(): array
|
||||||
|
{
|
||||||
|
return $this->getFields()->reduce(function ($carry, $current) {
|
||||||
|
$field = Field::fromConfig($current);
|
||||||
|
|
||||||
|
return [
|
||||||
|
...$carry,
|
||||||
|
...$field->getRegistrationAttributes(),
|
||||||
|
];
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection<string, mixed>
|
||||||
|
*/
|
||||||
|
public function getFields(): Collection
|
||||||
|
{
|
||||||
|
return collect($this->config['sections'])->reduce(fn ($carry, $current) => $carry->merge($current['fields']), collect([]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------- Searching ---------------------------------
|
// --------------------------------- Searching ---------------------------------
|
||||||
// *****************************************************************************
|
// *****************************************************************************
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Form\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Participant extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
public $guarded = [];
|
||||||
|
|
||||||
|
public $casts = [
|
||||||
|
'data' => 'json',
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('participants', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->json('data');
|
||||||
|
$table->foreignId('form_id');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('participants');
|
||||||
|
}
|
||||||
|
};
|
|
@ -30,6 +30,7 @@ use App\Form\Actions\FormtemplateIndexAction;
|
||||||
use App\Form\Actions\FormtemplateStoreAction;
|
use App\Form\Actions\FormtemplateStoreAction;
|
||||||
use App\Form\Actions\FormtemplateUpdateAction;
|
use App\Form\Actions\FormtemplateUpdateAction;
|
||||||
use App\Form\Actions\FormUpdateAction;
|
use App\Form\Actions\FormUpdateAction;
|
||||||
|
use App\Form\Actions\RegisterAction;
|
||||||
use App\Initialize\Actions\InitializeAction;
|
use App\Initialize\Actions\InitializeAction;
|
||||||
use App\Initialize\Actions\InitializeFormAction;
|
use App\Initialize\Actions\InitializeFormAction;
|
||||||
use App\Initialize\Actions\NamiGetSearchLayerAction;
|
use App\Initialize\Actions\NamiGetSearchLayerAction;
|
||||||
|
@ -156,6 +157,7 @@ Route::group(['middleware' => 'auth:web'], function (): void {
|
||||||
Route::post('/formtemplate', FormtemplateStoreAction::class)->name('formtemplate.store');
|
Route::post('/formtemplate', FormtemplateStoreAction::class)->name('formtemplate.store');
|
||||||
Route::patch('/formtemplate/{formtemplate}', FormtemplateUpdateAction::class)->name('formtemplate.update');
|
Route::patch('/formtemplate/{formtemplate}', FormtemplateUpdateAction::class)->name('formtemplate.update');
|
||||||
Route::post('/form', FormStoreAction::class)->name('form.store');
|
Route::post('/form', FormStoreAction::class)->name('form.store');
|
||||||
|
Route::post('/form/{form}/register', RegisterAction::class)->name('form.register');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::get('/api/group/{group?}', GroupApiIndexAction::class)->name('api.group');
|
Route::get('/api/group/{group?}', GroupApiIndexAction::class)->name('api.group');
|
||||||
|
|
|
@ -0,0 +1,276 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature\Form;
|
||||||
|
|
||||||
|
use App\Form\Fields\CheckboxesField;
|
||||||
|
use App\Form\Fields\CheckboxField;
|
||||||
|
use App\Form\Fields\DateField;
|
||||||
|
use App\Form\Fields\DropdownField;
|
||||||
|
use App\Form\Fields\GroupField;
|
||||||
|
use App\Form\Fields\RadioField;
|
||||||
|
use App\Form\Fields\TextareaField;
|
||||||
|
use App\Form\Fields\TextField;
|
||||||
|
use App\Form\Models\Form;
|
||||||
|
use App\Group;
|
||||||
|
use Generator;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
class FormRegisterActionTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
Storage::fake('temp');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItSavesParticipantAsModel(): void
|
||||||
|
{
|
||||||
|
$this->login()->loginNami()->withoutExceptionHandling();
|
||||||
|
$form = Form::factory()
|
||||||
|
->sections([
|
||||||
|
FormtemplateSectionRequest::new()->fields([
|
||||||
|
FormtemplateFieldRequest::type(TextField::class)->key('vorname'),
|
||||||
|
FormtemplateFieldRequest::type(TextField::class)->key('nachname'),
|
||||||
|
]),
|
||||||
|
FormtemplateSectionRequest::new()->fields([
|
||||||
|
FormtemplateFieldRequest::type(TextField::class)->key('spitzname'),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
->create();
|
||||||
|
|
||||||
|
$this->postJson(route('form.register', ['form' => $form]), ['vorname' => 'Max', 'nachname' => 'Muster', 'spitzname' => 'Abraham'])
|
||||||
|
->assertOk();
|
||||||
|
|
||||||
|
$participants = $form->fresh()->participants;
|
||||||
|
$this->assertCount(1, $participants);
|
||||||
|
$this->assertEquals('Max', $participants->first()->data['vorname']);
|
||||||
|
$this->assertEquals('Muster', $participants->first()->data['nachname']);
|
||||||
|
$this->assertEquals('Abraham', $participants->first()->data['spitzname']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider validationDataProvider
|
||||||
|
*/
|
||||||
|
public function testItValidatesInput(FormtemplateFieldRequest $fieldGenerator, array $payload, ?array $messages): void
|
||||||
|
{
|
||||||
|
$this->login()->loginNami();
|
||||||
|
$form = Form::factory()
|
||||||
|
->sections([FormtemplateSectionRequest::new()->fields([$fieldGenerator])])
|
||||||
|
->create();
|
||||||
|
|
||||||
|
$response = $this->postJson(route('form.register', ['form' => $form]), $payload);
|
||||||
|
|
||||||
|
if ($messages) {
|
||||||
|
$response->assertJsonValidationErrors($messages);
|
||||||
|
} else {
|
||||||
|
$response->assertOk();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validationDataProvider(): Generator
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(DateField::class)->name('Geburtsdatum')->maxToday(false)->key('birthday'),
|
||||||
|
['birthday' => 'aa'],
|
||||||
|
['birthday' => 'Geburtsdatum muss ein gültiges Datum sein.']
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(DateField::class)->name('Geburtsdatum')->maxToday(false)->key('birthday'),
|
||||||
|
['birthday' => '2021-05-06'],
|
||||||
|
null,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(DateField::class)->name('Geburtsdatum')->maxToday(true)->key('birthday'),
|
||||||
|
['birthday' => now()->addDay(1)->format('Y-m-d')],
|
||||||
|
['birthday' => 'Geburtsdatum muss ein Datum vor oder gleich dem ' . now()->format('d.m.Y') . ' sein.'],
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(DateField::class)->name('Geburtsdatum')->maxToday(true)->key('birthday'),
|
||||||
|
['birthday' => now()->format('Y-m-d')],
|
||||||
|
null,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(TextField::class)->name('Vorname der Mutter')->required(true)->key('vorname'),
|
||||||
|
['vorname' => ''],
|
||||||
|
['vorname' => 'Vorname der Mutter ist erforderlich.']
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(TextField::class)->name('Vorname der Mutter')->required(true)->key('vorname'),
|
||||||
|
['vorname' => 5],
|
||||||
|
['vorname' => 'Vorname der Mutter muss ein String sein.']
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(RadioField::class)->name('Ja oder Nein')->required(true)->key('yes_or_no'),
|
||||||
|
['yes_or_no' => null],
|
||||||
|
['yes_or_no' => 'Ja oder Nein ist erforderlich.']
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(RadioField::class)->name('Buchstabe')->options(['A', 'B'])->required(false)->key('letter'),
|
||||||
|
['letter' => 'Z'],
|
||||||
|
['letter' => 'Der gewählte Wert für Buchstabe ist ungültig.']
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(RadioField::class)->name('Buchstabe')->options(['A', 'B'])->required(true)->key('letter'),
|
||||||
|
['letter' => 'Z'],
|
||||||
|
['letter' => 'Der gewählte Wert für Buchstabe ist ungültig.']
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(RadioField::class)->name('Buchstabe')->options(['A', 'B'])->required(true)->key('letter'),
|
||||||
|
['letter' => 'A'],
|
||||||
|
null
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(CheckboxesField::class)->name('Buchstabe')->options(['A', 'B'])->key('letter'),
|
||||||
|
['letter' => ['Z']],
|
||||||
|
['letter.0' => 'Der gewählte Wert für Buchstabe ist ungültig.'],
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(CheckboxesField::class)->name('Buchstabe')->options(['A', 'B'])->key('letter'),
|
||||||
|
['letter' => 77],
|
||||||
|
['letter' => 'Buchstabe muss ein Array sein.'],
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(CheckboxesField::class)->name('Buchstabe')->options(['A', 'B'])->key('letter'),
|
||||||
|
['letter' => ['A']],
|
||||||
|
null,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(CheckboxesField::class)->name('Buchstabe')->options(['A', 'B'])->key('letter'),
|
||||||
|
['letter' => []],
|
||||||
|
null,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(CheckboxField::class)->name('Datenschutz')->required(false)->key('data'),
|
||||||
|
['data' => 5],
|
||||||
|
['data' => 'Datenschutz muss ein Wahrheitswert sein.'],
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(CheckboxField::class)->name('Datenschutz')->required(false)->key('data'),
|
||||||
|
['data' => false],
|
||||||
|
null
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(CheckboxField::class)->name('Datenschutz')->required(true)->key('data'),
|
||||||
|
['data' => false],
|
||||||
|
['data' => 'Datenschutz muss akzeptiert werden.'],
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(CheckboxField::class)->name('Datenschutz')->required(true)->key('data'),
|
||||||
|
['data' => true],
|
||||||
|
null,
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(DropdownField::class)->name('Ja oder Nein')->required(true)->key('yes_or_no'),
|
||||||
|
['yes_or_no' => null],
|
||||||
|
['yes_or_no' => 'Ja oder Nein ist erforderlich.']
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(DropdownField::class)->name('Buchstabe')->options(['A', 'B'])->required(false)->key('letter'),
|
||||||
|
['letter' => 'Z'],
|
||||||
|
['letter' => 'Der gewählte Wert für Buchstabe ist ungültig.']
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(DropdownField::class)->name('Buchstabe')->options(['A', 'B'])->required(true)->key('letter'),
|
||||||
|
['letter' => 'Z'],
|
||||||
|
['letter' => 'Der gewählte Wert für Buchstabe ist ungültig.']
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(DropdownField::class)->name('Buchstabe')->options(['A', 'B'])->required(true)->key('letter'),
|
||||||
|
['letter' => 'A'],
|
||||||
|
null
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(TextareaField::class)->name('Vorname der Mutter')->required(true)->key('vorname'),
|
||||||
|
['vorname' => ''],
|
||||||
|
['vorname' => 'Vorname der Mutter ist erforderlich.']
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(TextareaField::class)->name('Vorname der Mutter')->required(true)->key('vorname'),
|
||||||
|
['vorname' => 5],
|
||||||
|
['vorname' => 'Vorname der Mutter muss ein String sein.']
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
FormtemplateFieldRequest::type(TextareaField::class)->name('Vorname der Mutter')->required(true)->key('vorname'),
|
||||||
|
['vorname' => 5],
|
||||||
|
['vorname' => 'Vorname der Mutter muss ein String sein.']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItValidatesGroupFieldWithParentGroupField(): void
|
||||||
|
{
|
||||||
|
$this->login()->loginNami();
|
||||||
|
$group = Group::factory()->has(Group::factory()->count(3), 'children')->create();
|
||||||
|
$foreignGroup = Group::factory()->create();
|
||||||
|
$form = Form::factory()
|
||||||
|
->sections([FormtemplateSectionRequest::new()->fields([
|
||||||
|
FormtemplateFieldRequest::type(GroupField::class)->name('Gruppe')->parentGroup($group->id)->required(true)->key('group')
|
||||||
|
])])
|
||||||
|
->create();
|
||||||
|
|
||||||
|
$this->postJson(route('form.register', ['form' => $form]), ['group' => null])
|
||||||
|
->assertJsonValidationErrors(['group' => 'Gruppe ist erforderlich.']);
|
||||||
|
$this->postJson(route('form.register', ['form' => $form]), ['group' => $foreignGroup->id])
|
||||||
|
->assertJsonValidationErrors(['group' => 'Der gewählte Wert für Gruppe ist ungültig.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGroupCanBeNull(): void
|
||||||
|
{
|
||||||
|
$this->login()->loginNami();
|
||||||
|
$form = Form::factory()
|
||||||
|
->sections([FormtemplateSectionRequest::new()->fields([
|
||||||
|
FormtemplateFieldRequest::type(GroupField::class)->parentGroup(Group::factory()->create()->id)->required(false)->key('group')
|
||||||
|
])])
|
||||||
|
->create();
|
||||||
|
|
||||||
|
$this->postJson(route('form.register', ['form' => $form]), ['group' => null])
|
||||||
|
->assertOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItValidatesGroupWithParentFieldField(): void
|
||||||
|
{
|
||||||
|
$this->login()->loginNami();
|
||||||
|
$group = Group::factory()->has(Group::factory()->has(Group::factory()->count(3), 'children'), 'children')->create();
|
||||||
|
$foreignGroup = Group::factory()->create();
|
||||||
|
$form = Form::factory()
|
||||||
|
->sections([FormtemplateSectionRequest::new()->fields([
|
||||||
|
FormtemplateFieldRequest::type(GroupField::class)->name('Übergeordnete Gruppe')->parentGroup($group->id)->required(true)->key('parentgroup'),
|
||||||
|
FormtemplateFieldRequest::type(GroupField::class)->name('Gruppe')->parentField('parentgroup')->required(true)->key('group')
|
||||||
|
])])
|
||||||
|
->create();
|
||||||
|
|
||||||
|
$this->postJson(route('form.register', ['form' => $form]), ['parentgroup' => $group->children->first()->id, 'group' => $foreignGroup->id])
|
||||||
|
->assertJsonValidationErrors(['group' => 'Der gewählte Wert für Gruppe ist ungültig.']);
|
||||||
|
$this->postJson(route('form.register', ['form' => $form]), ['parentgroup' => $group->children->first()->id, 'group' => $group->children->first()->children->first()->id])
|
||||||
|
->assertOk();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue