Passed
Push — feature/job_api_route ( e4c64b )
by Tristan
09:17
created

JobController::get()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 10
ccs 0
cts 7
cp 0
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 6
1
<?php
2
3
namespace App\Http\Controllers;
4
5
use Illuminate\Support\Facades\Lang;
6
use Illuminate\Support\Facades\Auth;
7
use Illuminate\Support\Facades\Log;
8
use Illuminate\Support\Facades\Mail;
9
use Illuminate\Http\RedirectResponse;
10
use Illuminate\Http\Request;
11
use Illuminate\Http\Response;
12
use Illuminate\View\View;
13
use App\Http\Controllers\Controller;
14
15
use Carbon\Carbon;
16
17
use App\Mail\JobPosterReviewRequested;
18
19
use App\Models\Criteria;
20
use App\Models\JobPoster;
21
use App\Models\JobPosterKeyTask;
22
use App\Models\JobPosterQuestion;
23
use App\Models\Lookup\JobTerm;
24
use App\Models\Lookup\Province;
25
use App\Models\Lookup\SecurityClearance;
26
use App\Models\Lookup\LanguageRequirement;
27
use App\Models\Lookup\Department;
28
use App\Models\Lookup\SkillLevel;
29
use App\Models\Lookup\CriteriaType;
30
use App\Models\Skill;
31
use App\Models\Manager;
32
33
use App\Services\Validation\JobPosterValidator;
34
use Jenssegers\Date\Date;
35
use App\Models\AssessmentPlanNotification;
36
use App\Models\Assessment;
37
38
class JobController extends Controller
39
{
40
    /**
41
     * Display a listing of JobPosters.
42
     *
43
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
44
     */
45
    public function index()
46
    {
47
        $now = Carbon::now();
48
49
        // Find published jobs that are currently open for applications.
50
        // Eager load required relationships: Department, Province, JobTerm.
51
        // Eager load the count of submitted applications, to prevent the relationship
52
        // from being actually loaded and firing off events.
53
        $jobs = JobPoster::where('open_date_time', '<=', $now)
54
            ->where('close_date_time', '>=', $now)
55
            ->where('published', true)
56
            ->with([
57
                'department',
58
                'province',
59
                'job_term',
60
            ])
61
            ->withCount([
62
                'submitted_applications',
63
            ])
64
            ->get();
65
        return view('applicant/job_index', [
66
            'job_index' => Lang::get('applicant/job_index'),
67
            'jobs' => $jobs
68
        ]);
69
    }
70
71
    /**
72
     * Display a listing of a manager's JobPosters.
73
     *
74
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
75
     */
76 1
    public function managerIndex()
77
    {
78 1
        $manager = Auth::user()->manager;
0 ignored issues
show
Bug introduced by
Accessing manager on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
79 1
        $jobs = JobPoster::where('manager_id', $manager->id)
80 1
            ->withCount('submitted_applications')
81 1
            ->get();
82
83 1
        return view('manager/job_index', [
84
            /*Localization Strings*/
85 1
            'jobs_l10n' => Lang::get('manager/job_index'),
86
87
            /* Data */
88 1
            'jobs' => $jobs,
89
        ]);
90
    }
91
92
    /**
93
     * Submit the Job Poster for review.
94
     *
95
     * @param \Illuminate\Http\Request $request   Incoming request object.
96
     * @param \App\Models\JobPoster    $jobPoster Job Poster object.
97
     *
98
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
99
     */
100 1
    public function submitForReview(Request $request, JobPoster $jobPoster)
101
    {
102
        // Update review request timestamp
103 1
        $jobPoster->review_requested_at = new Date();
104 1
        $jobPoster->save();
105
106
        // Refresh model instance with updated DB values.
107 1
        $jobPoster = JobPoster::withCount('submitted_applications')->where('id', $jobPoster->id)->first();
108
109
        // Send email
110 1
        $reviewer_email = config('mail.reviewer_email');
111 1
        if (isset($reviewer_email)) {
112 1
            Mail::to($reviewer_email)->send(new JobPosterReviewRequested($jobPoster, Auth::user()));
0 ignored issues
show
Bug introduced by
It seems like Illuminate\Support\Facades\Auth::user() can also be of type null; however, parameter $manager of App\Mail\JobPosterReviewRequested::__construct() does only seem to accept App\Models\User, maybe add an additional type check? ( Ignorable by Annotation )

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

112
            Mail::to($reviewer_email)->send(new JobPosterReviewRequested($jobPoster, /** @scrutinizer ignore-type */ Auth::user()));
Loading history...
113
        } else {
114
            Log::error('The reviewer email environment variable is not set.');
115
        }
116
117 1
        return view('manager/job_index/job', [
118
            /*Localization Strings*/
119 1
            'jobs_l10n' => Lang::get('manager/job_index'),
120 1
            'job' => $jobPoster
121
        ]);
122
    }
123
124
    /**
125
     * Delete a draft Job Poster.
126
     *
127
     * @param \Illuminate\Http\Request $request   Incoming request object.
128
     * @param \App\Models\JobPoster    $jobPoster Job Poster object.
129
     *
130
     * @return void
131
     */
132
    public function destroy(Request $request, JobPoster $jobPoster) : void
133
    {
134
        $jobPoster->delete();
135
    }
136
137
    /**
138
     * Display the specified job poster.
139
     *
140
     * @param \Illuminate\Http\Request $request   Incoming request object.
141
     * @param \App\Models\JobPoster    $jobPoster Job Poster object.
142
     *
143
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
144
     */
145 4
    public function show(Request $request, JobPoster $jobPoster)
146
    {
147 4
        $jobPoster->load([
148 4
            'department',
149
            'criteria.skill.skill_type',
150
            'manager.team_culture',
151
            'manager.work_environment'
152
        ]);
153
154 4
        $user = Auth::user();
0 ignored issues
show
Unused Code introduced by
The assignment to $user is dead and can be removed.
Loading history...
155
156
        //TODO: Improve workplace photos, and reference them in template direction from WorkEnvironment model
157 4
        $workplacePhotos = [];
158 4
        foreach ($jobPoster->manager->work_environment->workplace_photo_captions as $photoCaption) {
159
            $workplacePhotos[] = [
160
                'description' => $photoCaption->description,
161
                'url' => '/images/user.png'
162
            ];
163
        }
164
165
        //TODO: replace route('manager.show',manager.id) in templates with link using slug
166
167
        $criteria = [
168 4
            'essential' => $jobPoster->criteria->filter(
169
                function ($value, $key) {
170 4
                    return $value->criteria_type->name == 'essential';
171 4
                }
172
            ),
173 4
            'asset' => $jobPoster->criteria->filter(
174
                function ($value, $key) {
175 4
                    return $value->criteria_type->name == 'asset';
176 4
                }
177
            ),
178
        ];
179
180 4
        $jobLang = Lang::get('applicant/job_post');
181
182 4
        $applyButton = [];
183 4
        if (!$jobPoster->published && $this->authorize('update', $jobPoster)) {
184
            $applyButton = [
185 2
                'href' => route('manager.jobs.edit', $jobPoster->id),
186 2
                'title' => $jobLang['apply']['edit_link_title'],
187 2
                'text' => $jobLang['apply']['edit_link_label'],
188
            ];
189 2
        } elseif (Auth::check() && $jobPoster->isOpen()) {
190
            $applyButton = [
191 1
                'href' => route('job.application.edit.1', $jobPoster->id),
192 1
                'title' => $jobLang['apply']['apply_link_title'],
193 1
                'text' => $jobLang['apply']['apply_link_label'],
194
            ];
195 1
        } elseif (Auth::guest() && $jobPoster->isOpen()) {
196
            $applyButton = [
197 1
                'href' => route('job.application.edit.1', $jobPoster->id),
198 1
                'title' => $jobLang['apply']['login_link_title'],
199 1
                'text' => $jobLang['apply']['login_link_label'],
200
            ];
201
        } else {
202
            $applyButton = [
203
                'href' => null,
204
                'title' => null,
205
                'text' => $jobLang['apply']['job_closed_label'],
206
            ];
207
        }
208
209 4
        return view(
210 4
            'applicant/job_post',
211
            [
212 4
                'job_post' => $jobLang,
213 4
                'manager' => $jobPoster->manager,
214 4
                'manager_profile_photo_url' => '/images/user.png', //TODO get real photo
215 4
                'team_culture' => $jobPoster->manager->team_culture,
216 4
                'work_environment' => $jobPoster->manager->work_environment,
217 4
                'workplace_photos' => $workplacePhotos,
218 4
                'job' => $jobPoster,
219 4
                'criteria' => $criteria,
220 4
                'apply_button' => $applyButton,
221 4
                'skill_template' => Lang::get('common/skills'),
222
            ]
223
        );
224
    }
225
226
    /**
227
     * Create a blank job poster for the specified manager
228
     *
229
     * @param Manager $manager
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
230
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory Job Create view
231
     */
232 2
    public function createAsManager(Manager $manager)
233
    {
234 2
        $jobPoster = new JobPoster();
235 2
        $jobPoster->manager_id = $manager->id;
236 2
        $managerEn = $manager->translate('en');
237 2
        $managerFr = $manager->translate('fr');
238
239 2
        $jobPoster->fill([
240 2
            'department_id' => $manager->department_id,
241
            'en' => [
242 2
                'branch' => $managerEn->branch,
243 2
                'division' => $managerEn->division,
244
            ],
245
            'fr' => [
246 2
                'branch' => $managerFr->branch,
247 2
                'division' => $managerFr->division,
248
            ]
249
        ]);
250 2
        $jobPoster->save();
251
252 2
        $defaultQuestions = $this->populateDefaultQuestions();
253 2
        if (!empty($defaultQuestions)) {
254 2
            $jobPoster->job_poster_questions()->saveMany($defaultQuestions);
255
        }
256
257 2
        return redirect()->route('manager.jobs.edit', $jobPoster->id);
1 ignored issue
show
Bug Best Practice introduced by
The expression return redirect()->route....edit', $jobPoster->id) returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type Illuminate\Contracts\Vie...ry|Illuminate\View\View.
Loading history...
258
    }
259
260
    /**
261
     * Display the form for creating a new Job Poster
262
     *
263
     * @param \Illuminate\Http\Request $request Incoming request object.
264
     *
265
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory Job Create view
266
     */
267
    public function create(Request $request)
268
    {
269
        return $this->populateCreateView($request);
270
    }
271
272
    /**
273
     * Display the form for editing an existing Job Poster
274
     *
275
     * @param \Illuminate\Http\Request $request   Incoming request object.
276
     * @param \App\Models\JobPoster    $jobPoster Job Poster object.
277
     *
278
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory Job Create view
279
     */
280 1
    public function edit(Request $request, JobPoster $jobPoster)
281
    {
282 1
        return $this->populateCreateView($request, $jobPoster);
283
    }
284
285
    /**
286
     * Get the manager from the request object and check if creating or editing
287
     *
288
     * @param \Illuminate\Http\Request $request   Incoming request object.
289
     * @param \App\Models\JobPoster    $jobPoster Optional Job Poster object.
290
     *
291
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory Job Create view
292
     */
293 1
    public function populateCreateView(Request $request, JobPoster $jobPoster = null)
294
    {
295 1
        if ($jobPoster == null || $jobPoster->manager == null) {
296
            $manager = $request->user() ? $request->user()->manager : null;
297
        } else {
298 1
            $manager = $jobPoster->manager;
299
        }
300
301 1
        if (isset($jobPoster)) {
302 1
            $job = $jobPoster;
303 1
            $route = ['manager.jobs.update', $jobPoster];
304 1
            $jobHeading = 'manager/job_edit';
305
        } else {
306
            $job = [];
307
            $defaultQuestions = $this->populateDefaultQuestions();
308
            if (!empty($defaultQuestions)) {
309
                $job['job_poster_questions'] = $defaultQuestions;
310
            }
311
            $route = ['manager.jobs.store'];
312
            $jobHeading = 'manager/job_create';
313
        }
314
315 1
        $skillLangs = Lang::get('common/skills');
316
317 1
        $softSkills = Skill::whereHas(
318 1
            'skill_type',
319
            function ($query) : void {
320 1
                $query->where('name', '=', 'soft');
321 1
            }
322 1
        )->get()
323 1
            ->mapWithKeys(
324
                function ($skill) {
325
                    return [
326 1
                        $skill->id => $skill->name
327
                    ];
328 1
                }
329
            )
330 1
            ->all();
331
332 1
        $hardSkills = Skill::whereHas(
333 1
            'skill_type',
334
            function ($query) : void {
335 1
                $query->where('name', '=', 'hard');
336 1
            }
337 1
        )->get()
338 1
            ->mapWithKeys(
339
                function ($skill) {
340
                    return [
341 1
                        $skill->id => $skill->name
342
                    ];
343 1
                }
344
            )
345 1
            ->all();
346
347 1
        asort($softSkills, SORT_LOCALE_STRING);
348 1
        asort($hardSkills, SORT_LOCALE_STRING);
349
350
        $skills = [
351
            'essential' => [
352 1
                'hard' => $hardSkills,
353 1
                'soft' => $softSkills
354
            ],
355
            'asset' => [
356 1
                'hard' => $hardSkills,
357 1
                'soft' => $softSkills
358
            ]
359
        ];
360
361 1
        $skillLevelCollection = SkillLevel::all();
362
363 1
        $skillLevels = array();
364
365 1
        $skillLevels['hard'] = $skillLevelCollection->mapWithKeys(
366
            function ($skillLevel) use ($skillLangs) {
367 1
                return [$skillLevel->id => $skillLangs['skill_levels']['hard'][$skillLevel->name]];
368 1
            }
369 1
        )->all();
370
371 1
        $skillLevels['soft'] = $skillLevelCollection->mapWithKeys(
372
            function ($skillLevel) use ($skillLangs) {
373 1
                return [$skillLevel->id => $skillLangs['skill_levels']['soft'][$skillLevel->name]];
374 1
            }
375 1
        )->all();
376
377 1
        return view(
378 1
            'manager/job_create',
379
            [
380
                /*Localization Strings*/
381 1
                'job_l10n' => Lang::get('manager/job_create'),
382
383
                /* Data */
384 1
                'job' => Lang::get($jobHeading),
385 1
                'manager' => $manager,
386 1
                'provinces' => Province::all(),
387 1
                'departments' => Department::all(),
388 1
                'language_requirments' => LanguageRequirement::all(),
389 1
                'security_clearances' => SecurityClearance::all(),
390 1
                'job' => $job,
391 1
                'form_action_url' => route(/** @scrutinizer ignore-type */ ...$route), // phpcs:ignore
0 ignored issues
show
Bug introduced by
$route is expanded, but the parameter $name of route() does not expect variable arguments. ( Ignorable by Annotation )

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

391
                'form_action_url' => route(/** @scrutinizer ignore-type */ /** @scrutinizer ignore-type */ ...$route), // phpcs:ignore
Loading history...
392 1
                'skills' => $skills,
393 1
                'skill_levels' => $skillLevels,
394 1
                'skill_template' => $skillLangs,
395
            ]
396
        );
397
    }
398
399
    /**
400
     * Create a new resource in storage
401
     *
402
     * @param \Illuminate\Http\Request $request   Incoming request object.
403
     * @param \App\Models\JobPoster    $jobPoster Optional Job Poster object.
404
     *
405
     * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse A redirect to the Job Index
406
     */
407 3
    public function store(Request $request, JobPoster $jobPoster = null)
408
    {
409
        // Don't allow edits for published Job Posters
410
        // Also check auth while we're at it
411 3
        if (isset($jobPoster)) {
412 3
            $this->authorize('update', $jobPoster);
413 3
            JobPosterValidator::validateUnpublished($jobPoster);
414
        } else {
415
            $this->authorize('create', JobPoster::class);
416
        }
417
418 3
        $input = $request->input();
419
420 3
        $job = (isset($jobPoster) ? $jobPoster : new JobPoster());
421
422 3
        if ($job->manager_id == null) {
423
            $job->manager_id = $request->user()->manager->id;
424
            $job->save();
425
        }
426
427 3
        $this->fillAndSaveJobPoster($input, $job);
428
429 3
        $this->fillAndSaveJobPosterTasks($input, $job, isset($jobPoster));
430
431 3
        $this->fillAndSaveJobPosterQuestions($input, $job, isset($jobPoster));
432
433 3
        $this->fillAndSaveJobPosterCriteria($input, $job, isset($jobPoster));
0 ignored issues
show
Unused Code introduced by
The call to App\Http\Controllers\Job...SaveJobPosterCriteria() has too many arguments starting with IssetNode. ( Ignorable by Annotation )

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

433
        $this->/** @scrutinizer ignore-call */ 
434
               fillAndSaveJobPosterCriteria($input, $job, isset($jobPoster));

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...
434
435 3
        return redirect(route('manager.jobs.show', $job->id));
436
    }
437
438
    /**
439
     * Fill Job Poster model's properties and save
440
     *
441
     * @param mixed[]               $input     Field values.
442
     * @param \App\Models\JobPoster $jobPoster Job Poster object.
443
     *
444
     * @return void
445
     */
446 3
    protected function fillAndSaveJobPoster(array $input, JobPoster $jobPoster) : void
447
    {
448 3
        $jobPoster->fill(
449
            [
450 3
                'job_term_id' => JobTerm::where('name', 'month')->firstOrFail()->id,
451 3
                'term_qty' => $input['term_qty'],
452 3
                'open_date_time' => ptDayStartToUtcTime($input['open_date']),
453 3
                'close_date_time' => ptDayEndToUtcTime($input['close_date']),
454 3
                'start_date_time' => ptDayStartToUtcTime($input['start_date']),
455 3
                'department_id' => $input['department'],
456 3
                'province_id' => $input['province'],
457 3
                'salary_min' => $input['salary_min'],
458 3
                'salary_max' => $input['salary_max'],
459 3
                'noc' => $input['noc'],
460 3
                'classification' => $input['classification'],
461 3
                'security_clearance_id' => $input['security_clearance'],
462 3
                'language_requirement_id' => $input['language_requirement'],
463 3
                'remote_work_allowed' => (isset($input['remote_work_allowed']) ? $input['remote_work_allowed'] : false),
464
                'en' => [
465 3
                    'city' => $input['city'],
466 3
                    'title' => $input['title']['en'],
467 3
                    'impact' => $input['impact']['en'],
468 3
                    'branch' => $input['branch']['en'],
469 3
                    'division' => $input['division']['en'],
470 3
                    'education' => $input['education']['en'],
471
                ],
472
                'fr' => [
473 3
                    'city' => $input['city'],
474 3
                    'title' => $input['title']['fr'],
475 3
                    'impact' => $input['impact']['fr'],
476 3
                    'branch' => $input['branch']['fr'],
477 3
                    'division' => $input['division']['fr'],
478 3
                    'education' => $input['education']['fr'],
479
                ],
480
            ]
481
        );
482 3
        $jobPoster->save();
483 3
    }
484
485
    /**
486
     * Fill Job Poster's tasks and save
487
     *
488
     * @param mixed[]               $input     Field values.
489
     * @param \App\Models\JobPoster $jobPoster Job Poster object.
490
     * @param boolean               $replace   Remove existing relationships.
491
     *
492
     * @return void
493
     */
494 3
    protected function fillAndSaveJobPosterTasks(array $input, JobPoster $jobPoster, bool $replace) : void
495
    {
496 3
        if ($replace) {
497 3
            $jobPoster->job_poster_key_tasks()->delete();
498
        }
499
500 3
        if (!array_key_exists('task', $input) || !is_array($input['task'])) {
501 3
            return;
502
        }
503
504
        foreach ($input['task'] as $task) {
505
            $jobPosterTask = new JobPosterKeyTask();
506
            $jobPosterTask->job_poster_id = $jobPoster->id;
507
            $jobPosterTask->fill(
508
                [
509
                    'en' => [
510
                        'description' => $task['en']
511
                    ],
512
                    'fr' => [
513
                        'description' => $task['fr']
514
                    ]
515
                ]
516
            );
517
            $jobPosterTask->save();
518
        }
519
    }
520
521
    /**
522
     * Fill Job Poster's questions and save
523
     *
524
     * @param mixed[]               $input     Field values.
525
     * @param \App\Models\JobPoster $jobPoster Job Poster object.
526
     * @param boolean               $replace   Remove existing relationships.
527
     *
528
     * @return void
529
     */
530 3
    protected function fillAndSaveJobPosterQuestions(array $input, JobPoster $jobPoster, bool $replace) : void
531
    {
532 3
        if ($replace) {
533 3
            $jobPoster->job_poster_questions()->delete();
534
        }
535
536 3
        if (!array_key_exists('question', $input) || !is_array($input['question'])) {
537 3
            return;
538
        }
539
540
        foreach ($input['question'] as $question) {
541
            $jobQuestion = new JobPosterQuestion();
542
            $jobQuestion->job_poster_id = $jobPoster->id;
543
            $jobQuestion->fill(
544
                [
545
                    'en' => [
546
                        'question' => $question['question']['en'],
547
                        'description' => $question['description']['en']
548
                    ],
549
                    'fr' => [
550
                        'question' => $question['question']['fr'],
551
                        'description' => $question['description']['fr']
552
                    ]
553
                ]
554
            );
555
            $jobQuestion->save();
556
        }
557
    }
558
559
    /**
560
     * Fill Job Poster's criteria and save
561
     *
562
     * @param mixed[]               $input     Field values.
563
     * @param \App\Models\JobPoster $jobPoster Job Poster object.
564
     *
565
     * @return void
566
     */
567 3
    protected function fillAndSaveJobPosterCriteria(array $input, JobPoster $jobPoster) : void
568
    {
569 3
        if (!array_key_exists('criteria', $input) || !is_array($input['criteria'])) {
570 3
            return;
571
        }
572
573
        $criteria = $input['criteria'];
574
575
        $affectedCriteriaIds = [];
576
        // Old criteria must be updated, using the criteriaId that comes from the form element names.
577
        if (!empty($criteria['old'])) {
578
            foreach ($criteria['old'] as $criteriaType => $criteriaTypeInput) {
579
                foreach ($criteriaTypeInput as $skillTypeInput) {
580
                    foreach ($skillTypeInput as $criteriaId => $criteriaInput) {
581
                        $updatedCriteria = $this->processCriteriaForm($jobPoster, $criteriaType, $criteriaInput, $criteriaId);
582
                        $affectedCriteriaIds[] = $updatedCriteria->id;
583
                    }
584
                }
585
            }
586
        }
587
        // New criteria must be created from scratch, and the id in the form element name can be disregarded.
588
        if (!empty($criteria['new'])) {
589
            foreach ($criteria['new'] as $criteriaType => $criteriaTypeInput) {
590
                foreach ($criteriaTypeInput as $skillTypeInput) {
591
                    foreach ($skillTypeInput as $criteriaInput) {
592
                        $newCriteria = $this->processCriteriaForm($jobPoster, $criteriaType, $criteriaInput, null);
593
                        $affectedCriteriaIds[] = $newCriteria->id;
594
                    }
595
                }
596
            }
597
        }
598
        // Existing criteria which were not resubmitted must be deleted.
599
        $deleteCriteria = $jobPoster->criteria()->whereNotIn('id', $affectedCriteriaIds)->get();
600
        foreach ($deleteCriteria as $criteria) {
601
            $this->deleteCriteria($criteria);
602
        }
603
    }
604
605
    /**
606
     * Process intput representing a single criteria from Job Poster form.
607
     *
608
     * @param JobPoster    $jobPoster
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
609
     * @param string       $criteriaType
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
610
     * @param array        $criteriaInput
1 ignored issue
show
introduced by
@param annotation of method \App\Http\Controllers\JobController::processCriteriaForm() does not specify type hint for items of its traversable parameter $criteriaInput.
Loading history...
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
611
     * @param integer|null $criteriaId
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
612
     * @return Criteria
613
     */
614
    protected function processCriteriaForm(JobPoster $jobPoster, string $criteriaType, array $criteriaInput, ?int $criteriaId): Criteria
615
    {
616
        $skillId = $criteriaInput['skill_id'];
617
618
        //If no description was provided, use the default skill description
619
        $descriptionEn = $criteriaInput['description']['en'] ?
620
            $criteriaInput['description']['en'] : Skill::find($skillId)->getTranslation('description', 'en');
621
        $descriptionFr = $criteriaInput['description']['fr'] ?
622
            $criteriaInput['description']['fr'] : Skill::find($criteriaInput['skill_id'])->getTranslation('description', 'fr');
623
        $data = [
624
            'skill_id' => $criteriaInput['skill_id'],
625
            'criteria_type_id' => CriteriaType::where('name', $criteriaType)->firstOrFail()->id,
626
            'skill_level_id' => $criteriaInput['skill_level_id'],
627
            'en' => [
628
                'description' => $descriptionEn,
629
            ],
630
            'fr' => [
631
                'description' => $descriptionFr,
632
            ],
633
        ];
634
635
        if ($criteriaId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $criteriaId of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
636
            $existingCriteria = Criteria::find($criteriaId);
637
            $this->updateCriteria($existingCriteria, $data);
638
            return $existingCriteria;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $existingCriteria could return the type null which is incompatible with the type-hinted return App\Models\Criteria. Consider adding an additional type-check to rule them out.
Loading history...
639
        } else {
640
            $newCriteria = $this->createCriteria($jobPoster, $skillId, $data);
641
            return $newCriteria;
642
        }
643
    }
644
645
    /**
646
     * Create a Job Criteria
647
     *
648
     * @param JobPoster $jobPoster
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
649
     * @param integer   $skillId
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
650
     * @param array     $data
1 ignored issue
show
introduced by
@param annotation of method \App\Http\Controllers\JobController::createCriteria() does not specify type hint for items of its traversable parameter $data.
Loading history...
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
651
     * @return Criteria
652
     */
653
    protected function createCriteria(JobPoster $jobPoster, int $skillId, array $data): Criteria
654
    {
655
        $criteria = new Criteria();
656
        $criteria->job_poster_id = $jobPoster->id;
657
        $criteria->skill_id = $skillId;
658
        $criteria->fill($data);
659
        $criteria->save();
660
661
        $notification = $this->makeAssessmentPlanNotification(
662
            'CREATE',
663
            $criteria
664
        );
665
        $notification->save();
666
667
        return $criteria;
668
    }
669
670
    /**
671
     * Update an existing Job Criteria
672
     *
673
     * @param Criteria $criteria
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
674
     * @param array    $data
1 ignored issue
show
introduced by
@param annotation of method \App\Http\Controllers\JobController::updateCriteria() does not specify type hint for items of its traversable parameter $data.
Loading history...
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
675
     * @return void
676
     */
677
    protected function updateCriteria(Criteria $criteria, array $data): void
678
    {
679
        if ($criteria->skill_level_id != $data['skill_level_id'] ||
680
        $criteria->skill_id != $data['skill_id']) {
681
            $notification = $this->makeAssessmentPlanNotification(
682
                'UPDATE',
683
                $criteria,
684
                $data['skill_id'],
685
                $data['skill_level_id']
686
            );
687
            $notification->save();
688
        }
689
        $criteria->fill($data);
690
        $criteria->save();
691
    }
692
693
    /**
694
     * Delete existing Job Criteria
695
     *
696
     * @param Criteria $criteria
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
697
     * @return void
698
     */
699
    protected function deleteCriteria(Criteria $criteria): void
700
    {
701
        $notification = $notification = $this->makeAssessmentPlanNotification(
0 ignored issues
show
Unused Code introduced by
The assignment to $notification is dead and can be removed.
Loading history...
702
            'DELETE',
703
            $criteria
704
        );
705
        $notification->save();
706
707
        // Delete assessments related to this criteria
708
        Assessment::where("criterion_id", $criteria->id)->delete();
709
710
        $criteria->delete();
711
    }
712
713
    /**
714
     * Create a new AssessmentPlanNotification for a modification to a Criteria
715
     *
716
     * @param string       $type            Can be CREATE, UPDATE or DELETE.
717
     * @param Criteria     $criteria
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter comment
Loading history...
718
     * @param integer|null $newSkillId      Only used for UPDATE type notifications.
719
     * @param integer|null $newSkillLevelId Only used for UPDATE type notifications.
720
     * @return AssessmentPlanNotification
721
     */
722
    protected function makeAssessmentPlanNotification(string $type, Criteria $criteria, $newSkillId = null, $newSkillLevelId = null): AssessmentPlanNotification
0 ignored issues
show
introduced by
Method \App\Http\Controllers\JobController::makeAssessmentPlanNotification() does not have parameter type hint for its parameter $newSkillId but it should be possible to add it based on @param annotation "integer|null".
Loading history...
introduced by
Method \App\Http\Controllers\JobController::makeAssessmentPlanNotification() does not have parameter type hint for its parameter $newSkillLevelId but it should be possible to add it based on @param annotation "integer|null".
Loading history...
723
    {
724
        $notification = new AssessmentPlanNotification();
725
        $notification->job_poster_id = $criteria->job_poster_id;
726
        $notification->type = $type;
727
        $notification->criteria_id = $criteria->id;
728
        $notification->skill_id = $criteria->skill_id;
729
        $notification->criteria_type_id = $criteria->criteria_type_id;
730
        $notification->skill_level_id = $criteria->skill_level_id;
731
        $notification->skill_id_new = $newSkillId;
732
        $notification->skill_level_id_new = $newSkillLevelId;
733
        $notification->acknowledged = false;
734
        return $notification;
735
    }
736
737
    /**
738
     * Get the localized default questions and add them to an array.
739
     *
740
     * @return mixed[]|void
741
     */
742 2
    protected function populateDefaultQuestions()
743
    {
744
        $defaultQuestions = [
745 2
            'en' => array_values(Lang::get('manager/job_create', [], 'en')['questions']),
746 2
            'fr' => array_values(Lang::get('manager/job_create', [], 'fr')['questions']),
747
        ];
748
749 2
        if (count($defaultQuestions['en']) !== count($defaultQuestions['fr'])) {
750
            Log::warning('There must be the same number of French and English default questions for a Job Poster.');
751
            return;
752
        }
753
754 2
        $jobQuestions = [];
755
756 2
        for ($i = 0; $i < count($defaultQuestions['en']); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
757 2
            $jobQuestion = new JobPosterQuestion();
758 2
            $jobQuestion->fill(
759
                [
760
                    'en' => [
761 2
                        'question' => $defaultQuestions['en'][$i],
762
                    ],
763
                    'fr' => [
764 2
                        'question' => $defaultQuestions['fr'][$i],
765
                    ]
766
                ]
767
            );
768 2
            $jobQuestions[] = $jobQuestion;
769
        }
770
771 2
        return $jobQuestions;
772
    }
773
}
774