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())
+
+
×
+
There are some errors. Please correct them and try again.
+ @foreach ($errors->all() as $error)
+ {{ $error }}
+ @endforeach
+
+ @endif
+
Complete and submit your student research application below. This application will not be public, but will be made available to faculty researchers who may be looking for students. After submitting, you can always come back later to edit or withdraw your student research application.
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));
+ }
}