Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Student Research Form Validations #166

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions app/Http/Controllers/StudentsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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,
Expand Down
152 changes: 152 additions & 0 deletions app/Http/Requests/StudentUpdateRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
<?php

namespace App\Http\Requests;

use App\Student;
use App\StudentData;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;

class StudentUpdateRequest extends FormRequest
{

/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\Rule|array|string>

Check failure on line 16 in app/Http/Requests/StudentUpdateRequest.php

View workflow job for this annotation

GitHub Actions / Profiles Tests (PHP 8.3)

InvalidReturnType

app/Http/Requests/StudentUpdateRequest.php:16:16: InvalidReturnType: The declared return type 'array<string, Illuminate\Contracts\Validation\Rule|array<array-key, mixed>|string>' for App\Http\Requests\StudentUpdateRequest::rules is incorrect, got 'array{'faculty.*': list{'integer', Illuminate\Validation\Rules\Exists&static}, 'research_profile.*': Closure, 'research_profile.availability': 'sometimes|array', 'research_profile.brief_intro': 'sometimes|string|max:280', 'research_profile.credit': 'required|numeric|between:-1,1', 'research_profile.graduation_date': 'required|date|after:today', 'research_profile.interest': 'sometimes|string|max:280', 'research_profile.intro': 'sometimes|string|max:280', 'research_profile.lang_proficiency': 'sometimes|array', 'research_profile.lang_proficiency.*': 'string|in:limited,basic,professional,native', 'research_profile.languages': 'sometimes|array', 'research_profile.languages.*': list{Illuminate\Validation\Rules\In}, 'research_profile.major': list{'required', Illuminate\Validation\Rules\In}, 'research_profile.schools': 'required|array', 'research_profile.schools.*': list{'sometimes', 'string', Illuminate\Validation\Rules\In}, 'research_profile.semesters': 'required|array', 'research_profile.semesters.*': list{'required', 'string', 'regex:/\\b(Winter|Spring|Summer|Fall)\\s\\d{4}\\b/'}, full_name: 'required|string'}' (see https://psalm.dev/011)
*/
public function rules(): array
{
$schools = Student::participatingSchools()->keys()->all();

return [

Check failure on line 22 in app/Http/Requests/StudentUpdateRequest.php

View workflow job for this annotation

GitHub Actions / Profiles Tests (PHP 8.3)

InvalidReturnStatement

app/Http/Requests/StudentUpdateRequest.php:22:16: InvalidReturnStatement: The inferred type 'array{'faculty.*': list{'integer', Illuminate\Validation\Rules\Exists&static}, 'research_profile.*': Closure, 'research_profile.availability': 'sometimes|array', 'research_profile.brief_intro': 'sometimes|string|max:280', 'research_profile.credit': 'required|numeric|between:-1,1', 'research_profile.graduation_date': 'required|date|after:today', 'research_profile.interest': 'sometimes|string|max:280', 'research_profile.intro': 'sometimes|string|max:280', 'research_profile.lang_proficiency': 'sometimes|array', 'research_profile.lang_proficiency.*': 'string|in:limited,basic,professional,native', 'research_profile.languages': 'sometimes|array', 'research_profile.languages.*': list{Illuminate\Validation\Rules\In}, 'research_profile.major': list{'required', Illuminate\Validation\Rules\In}, 'research_profile.schools': 'required|array', 'research_profile.schools.*': list{'sometimes', 'string', Illuminate\Validation\Rules\In}, 'research_profile.semesters': 'required|array', 'research_profile.semesters.*': list{'required', 'string', 'regex:/\\b(Winter|Spring|Summer|Fall)\\s\\d{4}\\b/'}, full_name: 'required|string'}' does not match the declared return type 'array<string, Illuminate\Contracts\Validation\Rule|array<array-key, mixed>|string>' for App\Http\Requests\StudentUpdateRequest::rules (see https://psalm.dev/128)
'full_name' => 'required|string',
'faculty.*' => [
'integer',
Rule::exists('profiles', 'id')->where('public', 1),
],
'research_profile.major' => [
'required',
Rule::in(StudentData::majors())

Check failure on line 30 in app/Http/Requests/StudentUpdateRequest.php

View workflow job for this annotation

GitHub Actions / Profiles Tests (PHP 8.3)

ImplicitToStringCast

app/Http/Requests/StudentUpdateRequest.php:30:26: ImplicitToStringCast: Argument 1 of Illuminate\Validation\Rule::in expects Illuminate\Contracts\Support\Arrayable<array-key, mixed>|array<array-key, mixed>|string, but Illuminate\Support\Collection provided with a __toString method (see https://psalm.dev/060)
],
'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',
Rule::in($schools),
],
'research_profile.availability' => 'sometimes|array',
'research_profile.semesters' => 'required|array',
'research_profile.semesters.*' => [
'required',
'string',
'regex:/\b(Winter|Spring|Summer|Fall)\s\d{4}\b/',
],
'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(),
'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.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.',
];
}

/**
* 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',
'research_profile.brief_intro' => 'research opportunity reasons',
'research_profile.intro' => 'future goals',
'research_profile.interest' => 'interest',
];
}

/**
* 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(fn($q) => isset($q['name'], $q['type']) && $q['name'] === $question_name);

if (is_null($question_settings)) {
return false;
}

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));
}
}
10 changes: 10 additions & 0 deletions resources/views/students/edit.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@
<h1 class="mb-0">Student Research Application</h1>
<h2 class="mt-0 text-muted">for {{ $student->full_name }}</h2>

@if ($errors->any())
<div class="alert alert-danger alert-dismissable" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<p><strong>There are some errors. Please correct them and try again.</strong></p>
@foreach ($errors->all() as $error)
{{ $error }}<br>
@endforeach
</div>
@endif

<div class="alert alert-success" role="alert">
<p class="mb-0">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.</p>
</div>
Expand Down
Loading