From c0c019afffef8a517d74b1c077e9b2bd6b1031b0 Mon Sep 17 00:00:00 2001 From: Betsy Castro <5490820+betsyecastro@users.noreply.github.com> Date: Tue, 8 Oct 2024 14:06:32 -0500 Subject: [PATCH 1/7] =?UTF-8?q?=F0=9F=A6=BA=20Adds=20student=20research=20?= =?UTF-8?q?form=20validations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/StudentsController.php | 5 +- app/Http/Requests/StudentUpdateRequest.php | 117 ++++++++++++++++++++ resources/views/students/edit.blade.php | 10 ++ resources/views/students/form.blade.php | 8 +- 4 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 app/Http/Requests/StudentUpdateRequest.php diff --git a/app/Http/Controllers/StudentsController.php b/app/Http/Controllers/StudentsController.php index cc33bd36..ec11c474 100644 --- a/app/Http/Controllers/StudentsController.php +++ b/app/Http/Controllers/StudentsController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers; use App\Events\StudentViewed; +use App\Http\Requests\StudentUpdateRequest; use App\Student; use App\StudentData; use App\User; @@ -50,7 +51,7 @@ public function index(): View|ViewContract /** * Create a new student research application. */ - public function create(Request $request): RedirectResponse + public function create(StudentUpdateRequest $request): RedirectResponse { $student = $request->user()->studentProfiles->first() ?? $this->store($request); @@ -127,7 +128,7 @@ public function edit(Student $student): View|ViewContract /** * Update the specified student research application in the database. */ - public function update(Request $request, Student $student): RedirectResponse + public function update(StudentUpdateRequest $request, Student $student): RedirectResponse { $updated = $student->update([ 'full_name' => $request->full_name, diff --git a/app/Http/Requests/StudentUpdateRequest.php b/app/Http/Requests/StudentUpdateRequest.php new file mode 100644 index 00000000..499cf68a --- /dev/null +++ b/app/Http/Requests/StudentUpdateRequest.php @@ -0,0 +1,117 @@ + + */ + public function rules(): array + { + return [ + 'full_name' => 'required|string', + 'faculty.*' => [ + 'integer', + Rule::exists('profiles', 'id')->where('public', 1), + ], + 'research_profile.semesters' => 'required|array|min:1', + 'research_profile.schools' => 'required|array|min:1', + 'research_profile.graduation_date' => 'required|date|after:today', + 'research_profile.credit' => 'required|numeric|between:-1,1', + ]; + } + + /** + * Get the error messages for the defined validation rules. + * + * @return array + */ + public function messages() + { + return [ + 'faculty.*.exists' => 'The faculty member(s) selected could not be validated.', + 'faculty.required' => 'You must selest at least one faculty member that you would like to work with', + 'research_profile.semesters.required' => 'At least one semester is required', + 'research_profile.schools.required' => 'At least one school is required', + 'research_profile.graduation_date.after' => 'The graduation date must be in the future', + 'research_profile.credit.between' => 'The credit value is invalid', + ]; + } + + /** + * Get custom attributes for validator errors. + * + * @return array + */ + public function attributes() + { + return [ + 'full_name' => 'Display Name', + 'research_profile.semesters' => 'Semesters', + 'research_profile.schools' => 'School', + 'research_profile.graduation_date' => 'Graduation date', + 'research_profile.credit' => 'Credit', + ]; + } + + public function withValidator($validator) + { + $validator->after(function ($validator) { + $semesters = $this->input('research_profile.semesters', []); + $availability = $this->input('research_profile.availability', []); + $schools = $this->input('research_profile.schools', []); + $custom_questions = StudentData::customQuestions(); + $school_custom_questions = $this->input('research_profile.school_custom_questions', []); + $languages = $this->input('research_profile.languages', []); + $lang_proficiency = $this->input('research_profile.lang_proficiency', []); + $languages_attr = StudentData::$languages; + $hours_available = [ + 'hours' => 'per week', + 'hours_weekdays' => 'per days', + 'hours_weekends' => 'for weekends', + 'hours_specific' => 'specific' + ]; + + foreach ($semesters as $semester) { // Validates the presence of the hours availability based on the semesters selection + $semester_key = Str::lower(Str::replace(' ', '-', $semester)); + if (!isset($availability[$semester_key])) { + $validator->errors()->add('availability.' . $semester_key, "The availability for $semester is required."); + } + else { + foreach ($hours_available as $hours => $frequency) { + if (is_null($availability[$semester_key][$hours])) { + $validator->errors()->add("availability.{$semester_key}.{$hours}", "The number of hours {$frequency} are required for $semester."); + } + } + } + } + + foreach ($languages as $language) { // Validates the presence of the language proficiency based on the language selection + if (!array_key_exists($language, $lang_proficiency) || is_null($lang_proficiency[$language])) { + $validator->errors()->add("research_profile.lang_proficiency.{$language}", "The level of proficiency for $languages_attr[$language] is required."); + } + } + + foreach ($schools as $key => $school) { + if (!isset($school_custom_questions[$school])) { + $validator->errors()->add("research_profile.school_custom_questions.{$school}", "The specific questions for $school are required."); + } + foreach ($custom_questions[$school] as $question) { + if (!isset($school_custom_questions[$school][$question['name']])) { + $validator->errors()->add("research_profile.school_custom_questions.{$school}", "The specific questions for $school are required."); + } + } + } + }); + } + +} diff --git a/resources/views/students/edit.blade.php b/resources/views/students/edit.blade.php index 45772032..18794325 100644 --- a/resources/views/students/edit.blade.php +++ b/resources/views/students/edit.blade.php @@ -29,6 +29,16 @@

Student Research Application

for {{ $student->full_name }}

+ @if ($errors->any()) + + @endif + diff --git a/resources/views/students/form.blade.php b/resources/views/students/form.blade.php index 36f1a927..29ec852a 100644 --- a/resources/views/students/form.blade.php +++ b/resources/views/students/form.blade.php @@ -194,24 +194,24 @@ @case('text')
{!! Form::label("research_profile[{$question['name']}]", $question['label'], ['class' => 'form-label']) !!} - {!! Form::text("research_profile[{$question['name']}]", $student->research_profile?->{$question['name']}, ['class' => 'form-control']) !!} + {!! Form::text("research_profile[school_custom_questions][$school_shortname][{$question['name']}]", $student->research_profile?->{$question['name']}, ['class' => 'form-control']) !!}
@break @case('textarea')
{!! Form::label("research_profile[{$question['name']}]", $question['label'], ['class' => 'form-label']) !!} - {!! Form::textarea("research_profile[{$question['name']}]", $student->research_profile?->{$question['name']}, ['class' => 'form-control']) !!} + {!! Form::textarea("research_profile[school_custom_questions][$school_shortname][{$question['name']}]", $student->research_profile?->{$question['name']}, ['class' => 'form-control']) !!}
@break @case('yes_no') {!! $question['label'] !!}
- {!! Form::radio("research_profile[{$question['name']}]", '1', $student->research_profile->{$question['name']} === '1', ['id' => "{$question['name']}_yes", 'class' => 'form-check-input']) !!} + {!! Form::radio("research_profile[school_custom_questions][$school_shortname][{$question['name']}]", '1', $student->research_profile->{$question['name']} === '1', ['id' => "{$question['name']}_yes", 'class' => 'form-check-input']) !!} {!! Form::label("{$question['name']}_yes", "Yes", ['class' => 'form-check-label']) !!}
- {!! Form::radio("research_profile[{$question['name']}]", '0', $student->research_profile->{$question['name']} === '0', ['id' => "{$question['name']}_no", 'class' => 'form-check-input']) !!} + {!! Form::radio("research_profile[school_custom_questions][$school_shortname][{$question['name']}]", '0', $student->research_profile->{$question['name']} === '0', ['id' => "{$question['name']}_no", 'class' => 'form-check-input']) !!} {!! Form::label("{$question['name']}_no", "No", ['class' => 'form-check-label']) !!}
From 0ff3812abfe6f5f3b103e76260e9ae11c0e1cc77 Mon Sep 17 00:00:00 2001 From: Betsy Castro <5490820+betsyecastro@users.noreply.github.com> Date: Tue, 8 Oct 2024 17:00:27 -0500 Subject: [PATCH 2/7] Adds validation for presence and length of intro, brief_intro and interests. --- app/Http/Requests/StudentUpdateRequest.php | 36 ++++++++++++++++++---- app/Rules/MinWords.php | 26 ++++++++++++++++ 2 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 app/Rules/MinWords.php diff --git a/app/Http/Requests/StudentUpdateRequest.php b/app/Http/Requests/StudentUpdateRequest.php index 499cf68a..21848b27 100644 --- a/app/Http/Requests/StudentUpdateRequest.php +++ b/app/Http/Requests/StudentUpdateRequest.php @@ -2,6 +2,7 @@ namespace App\Http\Requests; +use App\Rules\MinWords; use App\StudentData; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; @@ -19,10 +20,29 @@ public function rules(): array { return [ 'full_name' => 'required|string', + 'major' => 'required', 'faculty.*' => [ 'integer', Rule::exists('profiles', 'id')->where('public', 1), ], + 'research_profile.brief_intro' => [ + 'required', + 'string', + 'max:280', + new MinWords(5), + ], + 'research_profile.intro' => [ + 'required', + 'string', + 'max:250', + new MinWords(5), + ], + 'research_profile.interest' => [ + 'required', + 'string', + 'max:200', + new MinWords(5), + ], 'research_profile.semesters' => 'required|array|min:1', 'research_profile.schools' => 'required|array|min:1', 'research_profile.graduation_date' => 'required|date|after:today', @@ -40,6 +60,7 @@ public function messages() return [ 'faculty.*.exists' => 'The faculty member(s) selected could not be validated.', 'faculty.required' => 'You must selest at least one faculty member that you would like to work with', + 'research_profile.major' => 'The major field is required', 'research_profile.semesters.required' => 'At least one semester is required', 'research_profile.schools.required' => 'At least one school is required', 'research_profile.graduation_date.after' => 'The graduation date must be in the future', @@ -55,11 +76,14 @@ public function messages() public function attributes() { return [ - 'full_name' => 'Display Name', - 'research_profile.semesters' => 'Semesters', - 'research_profile.schools' => 'School', - 'research_profile.graduation_date' => 'Graduation date', - 'research_profile.credit' => 'Credit', + 'full_name' => 'display name', + 'research_profile.semesters' => 'semesters', + 'research_profile.schools' => 'school', + 'research_profile.graduation_date' => 'graduation date', + 'research_profile.credit' => 'credit', + 'research_profile.brief_intro' => 'research opportunity reasons', + 'research_profile.intro' => 'future goals', + 'research_profile.interest' => 'interest', ]; } @@ -101,7 +125,7 @@ public function withValidator($validator) } } - foreach ($schools as $key => $school) { + foreach ($schools as $key => $school) { // Validates the answers to the custom questions based on the school selection if (!isset($school_custom_questions[$school])) { $validator->errors()->add("research_profile.school_custom_questions.{$school}", "The specific questions for $school are required."); } diff --git a/app/Rules/MinWords.php b/app/Rules/MinWords.php new file mode 100644 index 00000000..19c7ce20 --- /dev/null +++ b/app/Rules/MinWords.php @@ -0,0 +1,26 @@ +minWords = $minWords; + } + + /** + * Run the validation rule. + */ + public function validate(string $attribute, mixed $value, Closure $fail): void + { + if (str_word_count($value) < $this->minWords) { + $fail("The :attribute field must have at least {$this->minWords} words."); + } + } +} From 61803856e870522850a5304c6b10d5cbcc65278e Mon Sep 17 00:00:00 2001 From: Betsy Castro <5490820+betsyecastro@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:49:36 -0500 Subject: [PATCH 3/7] Removes min length required for the intro, brief_intro and interest fields --- app/Http/Requests/StudentUpdateRequest.php | 5 ----- app/Rules/MinWords.php | 26 ---------------------- 2 files changed, 31 deletions(-) delete mode 100644 app/Rules/MinWords.php diff --git a/app/Http/Requests/StudentUpdateRequest.php b/app/Http/Requests/StudentUpdateRequest.php index 21848b27..e3d45b7f 100644 --- a/app/Http/Requests/StudentUpdateRequest.php +++ b/app/Http/Requests/StudentUpdateRequest.php @@ -2,7 +2,6 @@ namespace App\Http\Requests; -use App\Rules\MinWords; use App\StudentData; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; @@ -20,7 +19,6 @@ public function rules(): array { return [ 'full_name' => 'required|string', - 'major' => 'required', 'faculty.*' => [ 'integer', Rule::exists('profiles', 'id')->where('public', 1), @@ -29,19 +27,16 @@ public function rules(): array 'required', 'string', 'max:280', - new MinWords(5), ], 'research_profile.intro' => [ 'required', 'string', 'max:250', - new MinWords(5), ], 'research_profile.interest' => [ 'required', 'string', 'max:200', - new MinWords(5), ], 'research_profile.semesters' => 'required|array|min:1', 'research_profile.schools' => 'required|array|min:1', diff --git a/app/Rules/MinWords.php b/app/Rules/MinWords.php deleted file mode 100644 index 19c7ce20..00000000 --- a/app/Rules/MinWords.php +++ /dev/null @@ -1,26 +0,0 @@ -minWords = $minWords; - } - - /** - * Run the validation rule. - */ - public function validate(string $attribute, mixed $value, Closure $fail): void - { - if (str_word_count($value) < $this->minWords) { - $fail("The :attribute field must have at least {$this->minWords} words."); - } - } -} From d0f1608a53d72df331244a0466af18918301cc38 Mon Sep 17 00:00:00 2001 From: Betsy Castro <5490820+betsyecastro@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:50:40 -0500 Subject: [PATCH 4/7] Corrects the array key for the `major` field --- app/Http/Requests/StudentUpdateRequest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Http/Requests/StudentUpdateRequest.php b/app/Http/Requests/StudentUpdateRequest.php index e3d45b7f..6e7140f4 100644 --- a/app/Http/Requests/StudentUpdateRequest.php +++ b/app/Http/Requests/StudentUpdateRequest.php @@ -23,6 +23,7 @@ public function rules(): array 'integer', Rule::exists('profiles', 'id')->where('public', 1), ], + 'research_profile.major' => 'required', 'research_profile.brief_intro' => [ 'required', 'string', From 89dc96fa6edc8e403033a0775df70c288d7c25ce Mon Sep 17 00:00:00 2001 From: Betsy Castro <5490820+betsyecastro@users.noreply.github.com> Date: Mon, 11 Nov 2024 15:16:04 -0600 Subject: [PATCH 5/7] Data integrity validations --- app/Http/Requests/StudentUpdateRequest.php | 119 +++++++++++---------- resources/views/students/form.blade.php | 8 +- 2 files changed, 65 insertions(+), 62 deletions(-) diff --git a/app/Http/Requests/StudentUpdateRequest.php b/app/Http/Requests/StudentUpdateRequest.php index 6e7140f4..2eb66199 100644 --- a/app/Http/Requests/StudentUpdateRequest.php +++ b/app/Http/Requests/StudentUpdateRequest.php @@ -2,6 +2,7 @@ namespace App\Http\Requests; +use App\Student; use App\StudentData; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; @@ -17,30 +18,41 @@ class StudentUpdateRequest extends FormRequest */ public function rules(): array { + $schools = Student::participatingSchools()->keys()->all(); + return [ 'full_name' => 'required|string', 'faculty.*' => [ 'integer', Rule::exists('profiles', 'id')->where('public', 1), ], - 'research_profile.major' => 'required', - 'research_profile.brief_intro' => [ + 'research_profile.major' => [ 'required', - 'string', - 'max:280', + Rule::in(StudentData::majors()) ], - 'research_profile.intro' => [ - 'required', + 'research_profile.brief_intro' => 'sometimes|string|max:280', + 'research_profile.intro' => 'sometimes|string|max:280', + 'research_profile.interest' => 'sometimes|string|max:280', + 'research_profile.schools' => 'required|array', + 'research_profile.schools.*' => [ + 'sometimes', 'string', - 'max:250', + Rule::in($schools), ], - 'research_profile.interest' => [ + 'research_profile.availability' => 'sometimes|array', + 'research_profile.semesters' => 'required|array', + 'research_profile.semesters.*' => [ 'required', 'string', - 'max:200', + 'regex:/\b(Winter|Spring|Summer|Fall)\s\d{4}\b/', ], - 'research_profile.semesters' => 'required|array|min:1', - 'research_profile.schools' => 'required|array|min:1', + 'research_profile.languages' => 'sometimes|array', + 'research_profile.languages.*' => [ + Rule::in(array_keys(StudentData::$languages)), + ], + 'research_profile.lang_proficiency' => 'sometimes|array', + 'research_profile.lang_proficiency.*' => 'string|in:limited,basic,professional,native', + 'research_profile.*' => $this->validateCustomQuestions($schools), 'research_profile.graduation_date' => 'required|date|after:today', 'research_profile.credit' => 'required|numeric|between:-1,1', ]; @@ -55,12 +67,15 @@ public function messages() { return [ 'faculty.*.exists' => 'The faculty member(s) selected could not be validated.', - 'faculty.required' => 'You must selest at least one faculty member that you would like to work with', - 'research_profile.major' => 'The major field is required', - 'research_profile.semesters.required' => 'At least one semester is required', - 'research_profile.schools.required' => 'At least one school is required', - 'research_profile.graduation_date.after' => 'The graduation date must be in the future', - 'research_profile.credit.between' => 'The credit value is invalid', + 'faculty.required' => 'You must selest at least one faculty member that you would like to work with.', + 'research_profile.major.required' => 'The major field is required.', + 'research_profile.semesters.required' => 'At least one semester is required.', + 'research_profile.schools.required' => 'At least one school is required.', + 'research_profile.schools.*.in' => 'Wrong value :input. Please select a valid school.', + 'research_profile.semesters.*.regex' => 'Wrong value selected for semester. The semester must follow the "Season YYYY" format.', + 'research_profile.languages.*.in' => 'Wrong value :input selected for language. Please select a valid language.', + 'research_profile.graduation_date.after' => 'The graduation date must be in the future.', + 'research_profile.credit.between' => 'The credit value is invalid.', ]; } @@ -83,55 +98,43 @@ public function attributes() ]; } - public function withValidator($validator) + public function validateCustomQuestions($schools) { - $validator->after(function ($validator) { - $semesters = $this->input('research_profile.semesters', []); - $availability = $this->input('research_profile.availability', []); - $schools = $this->input('research_profile.schools', []); - $custom_questions = StudentData::customQuestions(); - $school_custom_questions = $this->input('research_profile.school_custom_questions', []); - $languages = $this->input('research_profile.languages', []); - $lang_proficiency = $this->input('research_profile.lang_proficiency', []); - $languages_attr = StudentData::$languages; - $hours_available = [ - 'hours' => 'per week', - 'hours_weekdays' => 'per days', - 'hours_weekends' => 'for weekends', - 'hours_specific' => 'specific' - ]; + return function($attr, $value, $fail) use ($schools) { + + $questions = StudentData::customQuestions()->flatten(1); + $school_key = substr($attr, strpos($attr, '.') + 1); - foreach ($semesters as $semester) { // Validates the presence of the hours availability based on the semesters selection - $semester_key = Str::lower(Str::replace(' ', '-', $semester)); - if (!isset($availability[$semester_key])) { - $validator->errors()->add('availability.' . $semester_key, "The availability for $semester is required."); - } - else { - foreach ($hours_available as $hours => $frequency) { - if (is_null($availability[$semester_key][$hours])) { - $validator->errors()->add("availability.{$semester_key}.{$hours}", "The number of hours {$frequency} are required for $semester."); - } - } - } + if (!in_array($school_key, $schools)) { + return; } - foreach ($languages as $language) { // Validates the presence of the language proficiency based on the language selection - if (!array_key_exists($language, $lang_proficiency) || is_null($lang_proficiency[$language])) { - $validator->errors()->add("research_profile.lang_proficiency.{$language}", "The level of proficiency for $languages_attr[$language] is required."); - } - } + foreach ($value as $question => $answer) { + + $settings_question = $questions->first(function ($q) use ($question, $school_key) { + return isset($q['name'], $q['school'], $q['type']) && $q['name'] === $question && $q['school'] === $school_key; + }); - foreach ($schools as $key => $school) { // Validates the answers to the custom questions based on the school selection - if (!isset($school_custom_questions[$school])) { - $validator->errors()->add("research_profile.school_custom_questions.{$school}", "The specific questions for $school are required."); + if (!$settings_question) { + $fail("Question '{$question}' for school '{$school_key}' is not valid."); + continue; } - foreach ($custom_questions[$school] as $question) { - if (!isset($school_custom_questions[$school][$question['name']])) { - $validator->errors()->add("research_profile.school_custom_questions.{$school}", "The specific questions for $school are required."); + + switch ($settings_question['type']) { + case 'yes_no': + if (!in_array($answer, ["1", "0"])) { + $formated_question_name = strtolower(str_replace('_', ' ', $question)); + $fail("The answer to {$formated_question_name} for school {$school_key} must be Yes or No."); + } + break; + default: + if (strlen($answer) > 1000) { + $formated_question_name = strtolower(str_replace('_', ' ', $question)); + $fail("The value for {$formated_question_name} in school {$school_key} question cannot exceed 1000 characters."); } + break; } } - }); + }; } - } diff --git a/resources/views/students/form.blade.php b/resources/views/students/form.blade.php index 29ec852a..4d739a0d 100644 --- a/resources/views/students/form.blade.php +++ b/resources/views/students/form.blade.php @@ -194,24 +194,24 @@ @case('text')
{!! Form::label("research_profile[{$question['name']}]", $question['label'], ['class' => 'form-label']) !!} - {!! Form::text("research_profile[school_custom_questions][$school_shortname][{$question['name']}]", $student->research_profile?->{$question['name']}, ['class' => 'form-control']) !!} + {!! Form::text("research_profile[$school_shortname][{$question['name']}]", $student->research_profile?->{$question['name']}, ['class' => 'form-control']) !!}
@break @case('textarea')
{!! Form::label("research_profile[{$question['name']}]", $question['label'], ['class' => 'form-label']) !!} - {!! Form::textarea("research_profile[school_custom_questions][$school_shortname][{$question['name']}]", $student->research_profile?->{$question['name']}, ['class' => 'form-control']) !!} + {!! Form::textarea("research_profile[$school_shortname][{$question['name']}]", $student->research_profile?->{$question['name']}, ['class' => 'form-control']) !!}
@break @case('yes_no') {!! $question['label'] !!}
- {!! Form::radio("research_profile[school_custom_questions][$school_shortname][{$question['name']}]", '1', $student->research_profile->{$question['name']} === '1', ['id' => "{$question['name']}_yes", 'class' => 'form-check-input']) !!} + {!! Form::radio("research_profile[$school_shortname][{$question['name']}]", '1', $student->research_profile->{$question['name']} === '1', ['id' => "{$question['name']}_yes", 'class' => 'form-check-input']) !!} {!! Form::label("{$question['name']}_yes", "Yes", ['class' => 'form-check-label']) !!}
- {!! Form::radio("research_profile[school_custom_questions][$school_shortname][{$question['name']}]", '0', $student->research_profile->{$question['name']} === '0', ['id' => "{$question['name']}_no", 'class' => 'form-check-input']) !!} + {!! Form::radio("research_profile[$school_shortname][{$question['name']}]", '0', $student->research_profile->{$question['name']} === '0', ['id' => "{$question['name']}_no", 'class' => 'form-check-input']) !!} {!! Form::label("{$question['name']}_no", "No", ['class' => 'form-check-label']) !!}
From 7930f9fe500fded0234520491bde7d9ea1e17faa Mon Sep 17 00:00:00 2001 From: Betsy Castro <5490820+betsyecastro@users.noreply.github.com> Date: Thu, 14 Nov 2024 15:08:16 -0600 Subject: [PATCH 6/7] Fixing key for custom questions --- app/Http/Requests/StudentUpdateRequest.php | 27 +++++++++------------- resources/views/students/form.blade.php | 8 +++---- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/app/Http/Requests/StudentUpdateRequest.php b/app/Http/Requests/StudentUpdateRequest.php index 2eb66199..2f6314f0 100644 --- a/app/Http/Requests/StudentUpdateRequest.php +++ b/app/Http/Requests/StudentUpdateRequest.php @@ -98,39 +98,34 @@ public function attributes() ]; } - public function validateCustomQuestions($schools) + public function validateCustomQuestions() { - return function($attr, $value, $fail) use ($schools) { + return function($attr, $value, $fail) { $questions = StudentData::customQuestions()->flatten(1); - $school_key = substr($attr, strpos($attr, '.') + 1); + $question_name = substr($attr, strpos($attr, '.') + 1); - if (!in_array($school_key, $schools)) { + $question_settings = $questions->first(function ($q) use ($question_name) { + return isset($q['name'], $q['type']) && $q['name'] === $question_name; + }); + + if (is_null($question_settings)) { return; } foreach ($value as $question => $answer) { - - $settings_question = $questions->first(function ($q) use ($question, $school_key) { - return isset($q['name'], $q['school'], $q['type']) && $q['name'] === $question && $q['school'] === $school_key; - }); - - if (!$settings_question) { - $fail("Question '{$question}' for school '{$school_key}' is not valid."); - continue; - } - switch ($settings_question['type']) { + switch ($question_settings['type']) { case 'yes_no': if (!in_array($answer, ["1", "0"])) { $formated_question_name = strtolower(str_replace('_', ' ', $question)); - $fail("The answer to {$formated_question_name} for school {$school_key} must be Yes or No."); + $fail("The answer to {$formated_question_name} must be Yes or No."); } break; default: if (strlen($answer) > 1000) { $formated_question_name = strtolower(str_replace('_', ' ', $question)); - $fail("The value for {$formated_question_name} in school {$school_key} question cannot exceed 1000 characters."); + $fail("The value for the {$formated_question_name} question cannot exceed 1000 characters."); } break; } diff --git a/resources/views/students/form.blade.php b/resources/views/students/form.blade.php index 4d739a0d..36f1a927 100644 --- a/resources/views/students/form.blade.php +++ b/resources/views/students/form.blade.php @@ -194,24 +194,24 @@ @case('text')
{!! Form::label("research_profile[{$question['name']}]", $question['label'], ['class' => 'form-label']) !!} - {!! Form::text("research_profile[$school_shortname][{$question['name']}]", $student->research_profile?->{$question['name']}, ['class' => 'form-control']) !!} + {!! Form::text("research_profile[{$question['name']}]", $student->research_profile?->{$question['name']}, ['class' => 'form-control']) !!}
@break @case('textarea')
{!! Form::label("research_profile[{$question['name']}]", $question['label'], ['class' => 'form-label']) !!} - {!! Form::textarea("research_profile[$school_shortname][{$question['name']}]", $student->research_profile?->{$question['name']}, ['class' => 'form-control']) !!} + {!! Form::textarea("research_profile[{$question['name']}]", $student->research_profile?->{$question['name']}, ['class' => 'form-control']) !!}
@break @case('yes_no') {!! $question['label'] !!}
- {!! Form::radio("research_profile[$school_shortname][{$question['name']}]", '1', $student->research_profile->{$question['name']} === '1', ['id' => "{$question['name']}_yes", 'class' => 'form-check-input']) !!} + {!! Form::radio("research_profile[{$question['name']}]", '1', $student->research_profile->{$question['name']} === '1', ['id' => "{$question['name']}_yes", 'class' => 'form-check-input']) !!} {!! Form::label("{$question['name']}_yes", "Yes", ['class' => 'form-check-label']) !!}
- {!! Form::radio("research_profile[$school_shortname][{$question['name']}]", '0', $student->research_profile->{$question['name']} === '0', ['id' => "{$question['name']}_no", 'class' => 'form-check-input']) !!} + {!! Form::radio("research_profile[{$question['name']}]", '0', $student->research_profile->{$question['name']} === '0', ['id' => "{$question['name']}_no", 'class' => 'form-check-input']) !!} {!! Form::label("{$question['name']}_no", "No", ['class' => 'form-check-label']) !!}
From 6b9dd8d64a3362ab163e8acf18799e10c3a4bb97 Mon Sep 17 00:00:00 2001 From: Betsy Castro <5490820+betsyecastro@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:53:38 -0600 Subject: [PATCH 7/7] validateCustomQuestions() method refactoring --- app/Http/Requests/StudentUpdateRequest.php | 59 ++++++++++++++-------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/app/Http/Requests/StudentUpdateRequest.php b/app/Http/Requests/StudentUpdateRequest.php index 2f6314f0..283769e0 100644 --- a/app/Http/Requests/StudentUpdateRequest.php +++ b/app/Http/Requests/StudentUpdateRequest.php @@ -6,7 +6,6 @@ use App\StudentData; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; -use Illuminate\Support\Str; class StudentUpdateRequest extends FormRequest { @@ -52,7 +51,7 @@ public function rules(): array ], 'research_profile.lang_proficiency' => 'sometimes|array', 'research_profile.lang_proficiency.*' => 'string|in:limited,basic,professional,native', - 'research_profile.*' => $this->validateCustomQuestions($schools), + 'research_profile.*' => $this->validateCustomQuestions(), 'research_profile.graduation_date' => 'required|date|after:today', 'research_profile.credit' => 'required|numeric|between:-1,1', ]; @@ -98,38 +97,56 @@ public function attributes() ]; } - public function validateCustomQuestions() + /** + * Check if attr is a custom question and validates the value based on the question type. + * Supported question types: + * - `yes_no`: Validates that the value is either "1" or "0". + * - Other types: Ensures the value does not exceed 1000 characters if it is a string. + * + * @return \Closure A validation closure to be used in validation rules. + */ + public function validateCustomQuestions() { return function($attr, $value, $fail) { + $errors = []; + $questions = StudentData::customQuestions()->flatten(1); $question_name = substr($attr, strpos($attr, '.') + 1); - $question_settings = $questions->first(function ($q) use ($question_name) { - return isset($q['name'], $q['type']) && $q['name'] === $question_name; - }); + $question_settings = $questions->first(fn($q) => isset($q['name'], $q['type']) && $q['name'] === $question_name); if (is_null($question_settings)) { - return; + return false; } - foreach ($value as $question => $answer) { - - switch ($question_settings['type']) { - case 'yes_no': - if (!in_array($answer, ["1", "0"])) { - $formated_question_name = strtolower(str_replace('_', ' ', $question)); - $fail("The answer to {$formated_question_name} must be Yes or No."); - } - break; - default: - if (strlen($answer) > 1000) { - $formated_question_name = strtolower(str_replace('_', ' ', $question)); - $fail("The value for the {$formated_question_name} question cannot exceed 1000 characters."); + switch ($question_settings['type']) { + case 'yes_no': + if (!in_array($value, ["1", "0"], true)) { + $formatted_question_name = $this->formatQuestionName($question_name); + $errors[] = "The answer to {$formatted_question_name} must be Yes or No."; + } + break; + default: + if (is_string($value) && strlen($value) > 1000) { + $formatted_question_name = $this->formatQuestionName($question_name); + $errors[] = "The value for the {$formatted_question_name} question cannot exceed 1000 characters."; } break; - } + } + + foreach ($errors as $error) { + $fail($error); } }; } + + /** + * Helper function to format question name + * @param string $question_name + * @return string + */ + function formatQuestionName($question_name) { + return strtolower(str_replace('_', ' ', $question_name)); + } }