diff --git a/app/Http/Controllers/TagsController.php b/app/Http/Controllers/TagsController.php index b9c2c9db..7ff59b13 100644 --- a/app/Http/Controllers/TagsController.php +++ b/app/Http/Controllers/TagsController.php @@ -73,9 +73,9 @@ public function create(): View|ViewContract /** * Save the tag in the database. */ - public function store(Request $request): RedirectResponse + public function store(TagUpdateRequest $request): RedirectResponse { - Tag::findOrCreate(preg_split('/\r\n|\r|\n/', $request->tag_name ?? ''), $request->tag_type); + Tag::findOrCreate(preg_split('/\r\n|\r|\n/', $request->name ?? ''), $request->type); return redirect()->route('tags.table') ->with('flash_message', 'Added tags'); diff --git a/app/Http/Requests/TagUpdateRequest.php b/app/Http/Requests/TagUpdateRequest.php index d27b73f5..752723d6 100644 --- a/app/Http/Requests/TagUpdateRequest.php +++ b/app/Http/Requests/TagUpdateRequest.php @@ -2,11 +2,15 @@ namespace App\Http\Requests; +use App\Rules\EachIsUnique; +use App\Student; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; class TagUpdateRequest extends FormRequest { + public $tag_types = []; + /** * Determine if the user is authorized to make this request. * @@ -24,27 +28,35 @@ public function authorize() */ public function rules() { + $this->tag_types[] = "App\\Profile"; $locale = app()->getLocale(); + + foreach (Student::participatingSchools() as $shortname => $name) { + $this->tag_types[]= "App\\Student\\{$shortname}"; + } return [ - 'type' => 'required', - 'name' => [ + 'type' => [ + 'required', + 'string', + Rule::in($this->tag_types), + ], + 'name' => [ 'required', 'string', 'max:100', - Rule::unique('tags', 'name->'.$locale) - ->where('type', $this->input('type')) - ->ignore($this->input('id')) + (new EachIsUnique('/\r\n|\r|\n/', 'tags', 'name->'.$locale, ['type', $this->input('type')])) + ->ignore($this->route()->parameters['tag'] ?? null), ], ]; } public function messages() { + $types_allowed = implode(', ', $this->tag_types); + return [ - 'name.required' => 'The tag name is required.', - 'name.unique' => 'The tag name provided already exists.', - 'name.max' => 'The tag name provided exceeds maximum length of 100 characters.', + 'type.in' => "The tag types allowed are: {$types_allowed}", ]; } diff --git a/app/Rules/EachIsUnique.php b/app/Rules/EachIsUnique.php new file mode 100644 index 00000000..a48d6924 --- /dev/null +++ b/app/Rules/EachIsUnique.php @@ -0,0 +1,107 @@ +delimiter = $delimiter; + $this->table = $table; + $this->column = $column; + $this->constraint = $constraint; + } + + /** + * Run the validation rule. + * + * @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail + */ + public function validate(string $attribute, mixed $value, Closure $fail): void + { + $values = $errors = []; + + $values = is_string($value) ? preg_split($this->delimiter, $value) : []; + + $rule = Rule::unique($this->table, $this->column); + + if (isset($this->constraint)) { + $rule->where($this->constraint[0], $this->constraint[1]); + } + + if (isset($this->ignore_id)) { + $rule->ignore($this->ignore_id, $this->ignore_column); + } + + foreach ($values as $value) { + $valid = !validator([$attribute => $value], [$attribute => $rule])->fails(); + + if (!$valid) { + $errors[] = "The {$value} tag already exists for the {$this->constraint[1]} {$this->constraint[0]}."; + } + } + + foreach ($errors as $error) { + $fail($error); + } + } + + /** + * Set values to be excluded or ignored by the unique checks. + * + * @param mixed|null $id + * @param string|null $id_column + */ + public function ignore($id, $idColumn = null) + { + $this->ignore_id = $id; + $this->ignore_column = $idColumn; + + return $this; + } + +} diff --git a/resources/views/tags/create.blade.php b/resources/views/tags/create.blade.php index d9b3ba5b..884a8cc6 100644 --- a/resources/views/tags/create.blade.php +++ b/resources/views/tags/create.blade.php @@ -22,17 +22,18 @@

Add Tags

+ @include('errors/list') {!! Form::open(['route' => 'tags.store']) !!}
- {!! Form::label('tag_name', 'Tag name(s)', ['class' => 'form-label']) !!} + {!! Form::label('name', 'Tag name(s)', ['class' => 'form-label']) !!} One tag per line - {!! Form::textarea('tag_name', null, ['class' => 'form-control', 'required']) !!} + {!! Form::textarea('name', null, ['class' => 'form-control', 'required']) !!}
- {!! Form::label('tag_type', 'Tag type', ['class' => 'form-label']) !!} + {!! Form::label('type', 'Tag type', ['class' => 'form-label']) !!} e.g. App\Profile, App\Student, and etc. - {!! Form::text('tag_type', null, ['class' => 'form-control', 'required']) !!} + {!! Form::text('type', null, ['class' => 'form-control', 'required']) !!}
diff --git a/resources/views/tags/edit.blade.php b/resources/views/tags/edit.blade.php index faf96c78..0b0556ce 100644 --- a/resources/views/tags/edit.blade.php +++ b/resources/views/tags/edit.blade.php @@ -22,7 +22,7 @@

Edit Tag {{ $tag->name }}

- @include('errors/has') + @include('errors/list') {!! Form::model($tag, ['method' => 'PATCH','route' => ['tags.updateTag', $tag], 'class' => 'form-horizontal' ]) !!}