Passed
Push — feature/timeline-application-v... ( b4b573 )
by Grant
06:17
created

ApplicationValidator::questionAnswerComplete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
namespace App\Services\Validation;
4
5
use App\Models\JobApplication;
6
use App\Models\Lookup\CriteriaType;
7
use App\Services\Validation\JobApplicationAnswerValidator;
8
use App\Services\Validation\Rules\ContainsObjectWithAttributeRule;
9
use Illuminate\Support\Facades\Log;
10
use Illuminate\Support\Facades\Validator;
11
12
class ApplicationValidator
13
{
14
15
    public $backendRules =  [
16
        'job_poster_id' => 'required',
17
        'application_status_id' => 'required',
18
        'applicant_id' => 'required',
19
    ];
20
    public function validator(JobApplication $application)
21
    {
22
        $data = $application->toArray();
23
24
        $rules = array_merge(
25
            $this->backendRules,
26
            $this->experienceRules,
27
            $this->affirmationRules
28
        );
29
30
        // Combining and simplifying error messages
31
        $rules = array_merge(
32
            $rules,
33
            ['application_step_1' => 'required|boolean|accepted'],
34
            ['application_step_3' => 'required|boolean|accepted']
35
        );
36
        $data = array_merge(
37
            $data,
38
            ['application_step_1' => $this->basicsComplete($application)],
39
            ['application_step_3' => $this->essentialSkillsComplete($application)]
40
        );
41
42
        // Validate basic data is filled in
43
        return Validator::make($data, $rules);
44
    }
45
46
    public function validate(JobApplication $application)
47
    {
48
        $this->validator($application)->validate();
49
    }
50
51
    public function validateComplete(JobApplication $application)
52
    {
53
        return $this->validator($application)->passes();
54
    }
55
56
    public function detailedValidatorErrors(JobApplication $application)
57
    {
58
        return array_merge(
59
            Validator::make($application->toArray(), $this->backendRules)->errors()->all(),
60
            $this->basicsValidator($application)->errors()->all(),
61
            $this->experienceValidator($application)->errors()->all(),
62
            $this->essentialSkillsValidator($application)->errors()->all(),
63
            $this->affirmationValidator($application)->errors()->all()
64
        );
65
    }
66
67
    /**
68
     * Return a copy of $array, with function $fn applied to each key, but values left unchanged.
69
     *
70
     * @param function $fn    Function applied to each key.
71
     * @param array    $array Array to operate on.
72
     * @return array
73
     */
74
    protected function arrayMapKeys($fn, $array): array
75
    {
76
        $newArray = [];
77
        foreach ($array as $key => $value) {
78
            $newArray[$fn($key)] = $value;
79
        }
80
        return $newArray;
81
    }
82
83
    protected function addNestedValidatorRules($nestedAttribute, $validatorRules, $rules = [])
84
    {
85
        // prepend the attribute name of each validator rule with the nested attribute name
86
        $newRules = $this->arrayMapKeys(
87
            function ($key) use ($nestedAttribute) {
0 ignored issues
show
Bug introduced by
function(...) { /* ... */ } of type callable is incompatible with the type App\Services\Validation\function expected by parameter $fn of App\Services\Validation\...lidator::arrayMapKeys(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

87
            /** @scrutinizer ignore-type */ function ($key) use ($nestedAttribute) {
Loading history...
88
                return implode('.', [$nestedAttribute, $key]);
89
            },
90
            $validatorRules
91
        );
92
        // Merge new rules with old rules
93
        $rules = array_merge($rules, $newRules);
94
        return $rules;
95
    }
96
97
    protected function basicInfoSimpleRules()
98
    {
99
        return [
100
            'language_requirement_confirmed' => ['required', 'boolean'],
101
            'citizenship_declaration_id' => ['required', 'exists:citizenship_declarations,id'],
102
            'veteran_status_id' => ['required', 'exists:veteran_statuses,id'],
103
            'preferred_language_id' => ['required', 'exists:preferred_languages,id'],
104
            'language_test_confirmed' => ['required', 'boolean'],
105
            'education_requirement_confirmed' => ['required', 'boolean']
106
        ];
107
    }
108
109
    protected function questionAnswerRules(JobApplication $application)
110
    {
111
        // Start with Answer rules, that ensure each answer is complete
112
        $answerValidator = new JobApplicationAnswerValidator($application);
113
        $rules = $this->addNestedValidatorRules(
114
            'job_application_answers.*',
115
            $answerValidator->rules(),
116
            []
117
        );
118
119
        // Validate that each question has been answered
120
        $jobPosterQuestionRules = [];
121
        foreach ($application->job_poster->job_poster_questions as $question) {
122
            $jobPosterQuestionRules[] = new ContainsObjectWithAttributeRule('job_poster_question_id', $question->id);
123
        }
124
        $rules['job_application_answers'] = $jobPosterQuestionRules;
125
126
        return $rules;
127
    }
128
129
    public function basicsValidator(JobApplication $application)
130
    {
131
        $validator = Validator::make($application->toArray(), $this->basicInfoSimpleRules($application));
0 ignored issues
show
Unused Code introduced by
The call to App\Services\Validation\...:basicInfoSimpleRules() has too many arguments starting with $application. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

131
        $validator = Validator::make($application->toArray(), $this->/** @scrutinizer ignore-call */ basicInfoSimpleRules($application));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
132
        return $validator;
133
    }
134
135
    public function basicsComplete(JobApplication $application)
136
    {
137
        $validator = $this->basicsValidator($application);
138
        return $validator->passes();
139
    }
140
141
    public function questionAnswerValidator(JobApplication $application)
142
    {
143
        // Load application answers so they are included in application->toArray().
144
        $application->load('job_application_answers');
145
        $validator = Validator::make($application->toArray(), $this->questionAnswerRules($application));
146
        return $validator;
147
    }
148
149
    public function questionAnswerComplete(JobApplication $application)
150
    {
151
        $validator = $this->questionAnswerValidator($application);
152
        return $validator->passes();
153
    }
154
155
    public $experienceRules = ['experience_saved' => 'required|boolean|accepted'];
156
    public function experienceValidator(JobApplication $application)
157
    {
158
        return Validator::make($application->attributesToArray(), $this->experienceRules);
159
    }
160
161
    public function experienceComplete(JobApplication $application)
162
    {
163
        return $this->experienceValidator($application)->passes();
164
    }
165
166
    protected function skillsValidator(JobApplication $application, $criteria_type)
167
    {
168
        $rules = [];
169
170
        // If application is still a draft, check skills attached to applicant profile. If submitted, use application itself.
171
        $skillDeclarationsAttribute = $application->isDraft() ? 'applicant.skill_declarations' : 'skill_declarations';
172
        $application->load($skillDeclarationsAttribute);
173
        $skillDeclarations = $application->isDraft()
174
            ? $application->applicant->skill_declarations
175
            : $application->skill_declarations;
176
177
        $skillDeclarationRules = [];
178
        $criteriaTypeId = CriteriaType::where('name', $criteria_type)->firstOrFail()->id;
179
        $criteria = $application->job_poster->criteria
180
            ->where('criteria_type_id', $criteriaTypeId)
181
            ->filter(function ($value, $key) {
182
                // Only hard skills need to be part of the application.
183
                return $value->skill->skill_type->name == 'hard';
184
            });
185
        foreach ($criteria as $criterion) {
186
            // Validate that every essential skill has a corresponding declaration.
187
            $skillDeclarationRules[] = new ContainsObjectWithAttributeRule('skill_id', $criterion->skill_id);
188
        }
189
        $rules[$skillDeclarationsAttribute] = $skillDeclarationRules;
190
191
        // Validate that those declarations are complete
192
        $skillDeclarationValidatorFactory = new SkillDeclarationValidator();
193
        $relevantSkillIds = $criteria->pluck('skill_id');
194
        foreach ($skillDeclarations as $key => $declaration) {
195
            if ($relevantSkillIds->contains($declaration->skill_id)) {
196
                $attribute = implode('.', [$skillDeclarationsAttribute, $key]);
197
                $skillDeclarationValidator = $skillDeclarationValidatorFactory->validator($declaration);
198
                $rules = $this->addNestedValidatorRules($attribute, $skillDeclarationValidator->getRules(), $rules);
199
            }
200
        }
201
202
        $validator = Validator::make($application->toArray(), $rules);
203
        return $validator;
204
    }
205
206
    public function essentialSkillsValidator(JobApplication $application)
207
    {
208
        return $this->skillsValidator($application, 'essential');
209
    }
210
211
    public function essentialSkillsComplete(JobApplication $application)
212
    {
213
        return $this->essentialSkillsValidator($application)->passes();
214
    }
215
216
    public function assetSkillsValidator(JobApplication $application)
217
    {
218
        return $this->skillsValidator($application, 'asset');
219
    }
220
221
    public function assetSkillsComplete(JobApplication $application)
222
    {
223
        return $this->assetSkillsValidator($application)->passes();
224
    }
225
226
    public $affirmationRules = [
227
        'submission_signature' => [
228
            'required',
229
            'string',
230
            'max:191',
231
        ],
232
        'submission_date' => [
233
            'required',
234
            'string',
235
            'max:191',
236
        ]
237
    ];
238
    public function affirmationValidator(JobApplication $application)
239
    {
240
        return Validator::make($application->toArray(), $this->affirmationRules);
241
    }
242
243
    public function affirmationComplete(JobApplication $application)
244
    {
245
        return $this->affirmationValidator($application)->passes();
246
    }
247
}
248