Completed
Push — bug/accordion ( 6550f4...474aef )
by Grant
12:54 queued 07:32
created

JobController::fillAndSaveJobPoster()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 37
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 30
dl 0
loc 37
rs 9.44
c 0
b 0
f 0
ccs 29
cts 29
cp 1
cc 2
nc 1
nop 2
crap 2
1
<?php
2
0 ignored issues
show
Coding Style introduced by
Missing file doc comment
Loading history...
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\Http\RedirectResponse;
9
use Illuminate\Http\Request;
10
use Illuminate\Http\Response;
11
use Illuminate\View\View;
12
use App\Http\Controllers\Controller;
13
14
use Carbon\Carbon;
15
16
use App\Models\JobPoster;
17
use App\Models\JobPosterQuestion;
18
use App\Models\Lookup\JobTerm;
19
use App\Models\Lookup\Province;
20
use App\Models\Lookup\SecurityClearance;
21
use App\Models\Lookup\LanguageRequirement;
22
use App\Models\Lookup\CitizenshipDeclaration;
23
use App\Models\Lookup\Department;
24
use App\Models\Lookup\SkillLevel;
25
use App\Models\Lookup\CriteriaType;
26
use App\Models\Lookup\VeteranStatus;
27
use App\Models\JobApplication;
28
use App\Models\Criteria;
29
use App\Models\Skill;
30
use App\Models\JobPosterKeyTask;
31
32
use App\Services\Validation\JobPosterValidator;
33
use Jenssegers\Date\Date;
34
35
class JobController extends Controller
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class JobController
Loading history...
36
{
37
    /**
38
     * Display a listing of JobPosters.
39
     *
40
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
41
     */
42
    public function index()
43
    {
44
        $now = Carbon::now();
45
46
        //Find published jobs that are currently open for applications
47
        $jobs = JobPoster::where('open_date_time', '<=', $now)
48
            ->where('close_date_time', '>=', $now)
49
            ->where('published', true)
50
            ->get();
51
        $jobs->load('manager.work_environment');
52
        return view('applicant/job_index', [
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
53
            'job_index' => Lang::get('applicant/job_index'),
54
            'jobs' => $jobs
55
        ]);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
56
    }
57
58
    /**
59
     * Display a listing of a manager's JobPosters.
60
     *
61
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
62
     */
63 2
    public function managerIndex()
64
    {
65 2
        $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...
66
67 2
        $veteran_applications = [];
68 2
        $citizen_applications = [];
69 2
        $other_applications = [];
70
71 2
        foreach ($manager->job_posters as $job) {
72 2
            $job->submitted_applications->load(['veteran_status', 'citizenship_declaration']);
73
            $veteran_applications[$job->id] = $job->submitted_applications->filter(function ($application) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
74
                return $application->veteran_status->name !== "none" &&
75
                    $application->citizenship_declaration->name === "citizen";
76 2
            });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
77
            $citizen_applications[$job->id] = $job->submitted_applications->filter(function ($application) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
78
                return $application->veteran_status->name === "none" &&
79
                    $application->citizenship_declaration->name === "citizen";
80 2
            });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
81
            $other_applications[$job->id] = $job->submitted_applications->filter(function ($application) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
82
                return $application->citizenship_declaration->name !== "citizen";
83 2
            });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
84
        }
85
86 2
        return view('manager/job_index', [
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
87 2
            "manager_job_index" => [
88
                "title" => "My Job Posts"
89
            ],
90 2
            'jobs' => $manager->job_posters,
91 2
            'veteran_applications' => $veteran_applications,
92 2
            'citizen_applications' => $citizen_applications,
93 2
            'other_applications' => $other_applications,
94
        ]);
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
95
    }
96
97
    /**
98
     * Display the specified job poster.
99
     *
100
     * @param \Illuminate\Http\Request $request   Incoming request object.
101
     * @param \App\Models\JobPoster    $jobPoster Job Poster object.
102
     *
103
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
104
     */
105 6
    public function show(Request $request, JobPoster $jobPoster)
106
    {
107 6
        $user = Auth::user();
108
109
        //TODO: Improve workplace photos, and reference them in template direction from WorkEnvironment model
110 6
        $workplacePhotos = [];
111 6
        foreach ($jobPoster->manager->work_environment->workplace_photo_captions as $photoCaption) {
112
            $workplacePhotos[] = [
113
                'description' => $photoCaption->description,
114
                'url' => '/images/user.png'
115
            ];
116
        }
117
118
        //TODO: replace route('manager.show',manager.id) in templates with link using slug
119
120
        $criteria = [
121 6
            'essential' => $jobPoster->criteria->filter(
122
                function ($value, $key) {
123 4
                    return $value->criteria_type->name == 'essential';
124 6
                }
125
            ),
126 6
            'asset' => $jobPoster->criteria->filter(
127
                function ($value, $key) {
128 4
                    return $value->criteria_type->name == 'asset';
129 6
                }
130
            ),
131
        ];
132
133 6
        $jobLang = Lang::get('applicant/job_post');
134
135 6
        $applyButton = [];
136
137 6
        if (isset($user)) {
138 4
            if (!$jobPoster->published && $this->authorize('update', $jobPoster)) {
139
                $applyButton = [
140 2
                    'href' => route('manager.jobs.edit', $jobPoster->id),
141 2
                    'title' => $jobLang['apply']['edit_link_title'],
142 2
                    'text' => $jobLang['apply']['edit_link_label'],
143
                ];
144
            } else {
145
                $applyButton = [
146 2
                    'href' => route('job.application.edit.1', $jobPoster->id),
147 2
                    'title' => $jobLang['apply']['apply_link_title'],
148 4
                    'text' => $jobLang['apply']['apply_link_label'],
149
                ];
150
            }
151
        } else {
152
            $applyButton = [
153 2
                'href' => route('job.application.edit.1', $jobPoster->id),
154 2
                'title' => $jobLang['apply']['login_link_title'],
155 2
                'text' => $jobLang['apply']['login_link_label'],
156
            ];
157
        }
158
159 6
        return view(
160 6
            'applicant/job_post',
161
            [
162 6
                'job_post' => $jobLang,
163 6
                'manager' => $jobPoster->manager,
164 6
                'manager_profile_photo_url' => '/images/user.png', //TODO get real photo
165 6
                'team_culture' => $jobPoster->manager->team_culture,
166 6
                'work_environment' => $jobPoster->manager->work_environment,
167 6
                'workplace_photos' => $workplacePhotos,
168 6
                'job' => $jobPoster,
169 6
                'criteria' => $criteria,
170 6
                'apply_button' => $applyButton,
171 6
                'skill_template' => Lang::get('common/skills'),
172
            ]
173
        );
174
    }
175
176
    /**
177
     * Display the form for creating a new Job Poster
178
     *
179
     * @param \Illuminate\Http\Request $request Incoming request object.
180
     *
181
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory Job Create view
182
     */
183 2
    public function create(Request $request)
184
    {
185 2
        return $this->populateCreateView($request);
186
    }
187
188
    /**
189
     * Display the form for editing an existing Job Poster
190
     *
191
     * @param \Illuminate\Http\Request $request   Incoming request object.
192
     * @param \App\Models\JobPoster    $jobPoster Job Poster object.
193
     *
194
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory Job Create view
195
     */
196 2
    public function edit(Request $request, JobPoster $jobPoster)
197
    {
198 2
        return $this->populateCreateView($request, $jobPoster);
199
    }
200
201
    /**
202
     * Get the manager from the request object and check if creating or editing
203
     *
204
     * @param \Illuminate\Http\Request $request   Incoming request object.
205
     * @param \App\Models\JobPoster    $jobPoster Optional Job Poster object.
206
     *
207
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory Job Create view
208
     */
209 4
    public function populateCreateView(Request $request, JobPoster $jobPoster = null)
210
    {
211 4
        $manager = $request->user() ? $request->user()->manager : null;
212 4
        if (isset($jobPoster)) {
213 2
            $job = $jobPoster;
214 2
            $route = ['manager.jobs.store', $jobPoster];
215 2
            $jobHeading = 'manager/job_edit';
216
        } else {
217 2
            $job = [];
218 2
            $defaultQuestions = $this->populateDefaultQuestions();
219 2
            if (!empty($defaultQuestions)) {
220 2
                $job['job_poster_questions'] = $defaultQuestions;
221
            }
222 2
            $route = ['manager.jobs.store'];
223 2
            $jobHeading = 'manager/job_create';
224
        }
225
226 4
        $skillLangs = Lang::get('common/skills');
227
228 4
        $softSkills = Skill::whereHas(
229 4
            'skill_type',
230
            function ($query) : void {
231 4
                $query->where('name', '=', 'soft');
232 4
            }
233 4
        )->get()
234 4
            ->mapWithKeys(
235
                function ($skill) use ($skillLangs) {
236
                    return [
237 4
                        $skill->id => $skillLangs['skills'][$skill->name]['name']
238
                    ];
239 4
                }
240
            )
241 4
            ->all();
242
243 4
        $hardSkills = Skill::whereHas(
244 4
            'skill_type',
245
            function ($query) : void {
246 4
                $query->where('name', '=', 'hard');
247 4
            }
248 4
        )->get()
249 4
            ->mapWithKeys(
250
                function ($skill) use ($skillLangs) {
251
                    return [
252 4
                        $skill->id => $skillLangs['skills'][$skill->name]['name']
253
                    ];
254 4
                }
255
            )
256 4
            ->all();
257
258 4
        asort($softSkills, SORT_LOCALE_STRING);
259 4
        asort($hardSkills, SORT_LOCALE_STRING);
260
261
        $skills = [
262
            'essential' => [
263 4
                'hard' => $hardSkills,
264 4
                'soft' => $softSkills
265
            ],
266
            'asset' => [
267 4
                'hard' => $hardSkills,
268 4
                'soft' => $softSkills
269
            ]
270
        ];
271
272 4
        $skillLevelCollection = SkillLevel::all();
273
274 4
        $skillLevels = array();
275
276 4
        $skillLevels['hard'] = $skillLevelCollection->mapWithKeys(
277
            function ($skillLevel) use ($skillLangs) {
278 4
                return [$skillLevel->id => $skillLangs['skill_levels']['hard'][$skillLevel->name]];
279 4
            }
280 4
        )->all();
281
282 4
        $skillLevels['soft'] = $skillLevelCollection->mapWithKeys(
283
            function ($skillLevel) use ($skillLangs) {
284 4
                return [$skillLevel->id => $skillLangs['skill_levels']['soft'][$skillLevel->name]];
285 4
            }
286 4
        )->all();
287
288 4
        return view(
289 4
            'manager/job_create',
290
            [
291 4
                'job_heading' => Lang::get($jobHeading),
292 4
                'manager' => $manager,
293 4
                'provinces' => Province::all(),
294 4
                'departments' => Department::all(),
295 4
                'language_requirments' => LanguageRequirement::all(),
296 4
                'security_clearances' => SecurityClearance::all(),
297 4
                'job' => $job,
298 4
                '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

298
                'form_action_url' => route(/** @scrutinizer ignore-type */ /** @scrutinizer ignore-type */ ...$route), // phpcs:ignore
Loading history...
299 4
                'skills' => $skills,
300 4
                'skill_levels' => $skillLevels,
301 4
                'skill_template' => $skillLangs,
302
            ]
303
        );
304
    }
305
306
    /**
307
     * Create a new resource in storage
308
     *
309
     * @param \Illuminate\Http\Request $request   Incoming request object.
310
     * @param \App\Models\JobPoster    $jobPoster Optional Job Poster object.
311
     *
312
     * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse A redirect to the Job Index
313
     */
314 2
    public function store(Request $request, JobPoster $jobPoster = null)
315
    {
316
        // Don't allow edits for published Job Posters
317
        // Also check auth while we're at it
318 2
        if (isset($jobPoster)) {
319
            $this->authorize('update', $jobPoster);
320
            JobPosterValidator::validateUnpublished($jobPoster);
321
        } else {
322 2
            $this->authorize('create', JobPoster::class);
323
        }
324
325 2
        $input = $request->input();
326
327 2
        $job = (isset($jobPoster) ? $jobPoster : new JobPoster());
328
329 2
        $job->manager_id = $request->user()->manager->id;
330 2
        $job->published = ($input['submit'] == 'publish');
331
332 2
        $this->fillAndSaveJobPoster($input, $job);
333
334 2
        $this->fillAndSaveJobPosterTasks($input, $job, isset($jobPoster));
335
336 2
        $this->fillAndSaveJobPosterQuestions($input, $job, isset($jobPoster));
337
338 2
        $this->fillAndSaveJobPosterCriteria($input, $job, isset($jobPoster));
339
340 2
        $route = $job->published ? route('manager.jobs.index') : route('manager.jobs.show', $job->id);
341
342 2
        return redirect($route);
343
    }
344
345
    /**
346
     * Fill Job Poster model's properties and save
347
     *
348
     * @param mixed[]               $input     Field values.
349
     * @param \App\Models\JobPoster $jobPoster Job Poster object.
350
     *
351
     * @return void
352
     */
353 2
    protected function fillAndSaveJobPoster(array $input, JobPoster $jobPoster) : void
354
    {
355 2
        $jobPoster->fill(
356
            [
357 2
                'job_term_id' => JobTerm::where('name', 'month')->firstOrFail()->id,
358 2
                'term_qty' => $input['term_qty'],
359 2
                'open_date_time' => new Date($input['open_date'] . $input['open_time']),
360 2
                'close_date_time' => new Date($input['close_date'] . $input['close_time']),
361 2
                'start_date_time' => new Date($input['start_date_time']),
362 2
                'department_id' => $input['department'],
363 2
                'province_id' => $input['province'],
364 2
                'salary_min' => $input['salary_min'],
365 2
                'salary_max' => $input['salary_max'],
366 2
                'noc' => $input['noc'],
367 2
                'classification' => $input['classification'],
368 2
                'security_clearance_id' => $input['security_clearance'],
369 2
                'language_requirement_id' => $input['language_requirement'],
370 2
                'remote_work_allowed' => (isset($input['remote_work_allowed']) ? $input['remote_work_allowed'] : false),
371
                'en' => [
372 2
                    'city' => $input['city'],
373 2
                    'title' => $input['title']['en'],
374 2
                    'impact' => $input['impact']['en'],
375 2
                    'branch' => $input['branch']['en'],
376 2
                    'division' => $input['division']['en'],
377 2
                    'education' => $input['education']['en'],
378
                ],
379
                'fr' => [
380 2
                    'city' => $input['city'],
381 2
                    'title' => $input['title']['fr'],
382 2
                    'impact' => $input['impact']['fr'],
383 2
                    'branch' => $input['branch']['fr'],
384 2
                    'division' => $input['division']['fr'],
385 2
                    'education' => $input['education']['fr'],
386
                ],
387
            ]
388
        );
389 2
        $jobPoster->save();
390 2
    }
391
392
    /**
393
     * Fill Job Poster's tasks and save
394
     *
395
     * @param mixed[]               $input     Field values.
396
     * @param \App\Models\JobPoster $jobPoster Job Poster object.
397
     * @param boolean               $replace   Remove existing relationships.
398
     *
399
     * @return void
400
     */
401 2
    protected function fillAndSaveJobPosterTasks(array $input, JobPoster $jobPoster, bool $replace) : void
402
    {
403 2
        if ($replace) {
404
            $jobPoster->job_poster_key_tasks()->delete();
405
        }
406
407 2
        if (!array_key_exists('task', $input) || !is_array($input['task'])) {
408 2
            return;
409
        }
410
411
        foreach ($input['task'] as $task) {
412
            $jobPosterTask = new JobPosterKeyTask();
413
            $jobPosterTask->job_poster_id = $jobPoster->id;
414
            $jobPosterTask->fill(
415
                [
416
                    'en' => [
417
                        'description' => $task['en']
418
                    ],
419
                    'fr' => [
420
                        'description' => $task['fr']
421
                    ]
422
                ]
423
            );
424
            $jobPosterTask->save();
425
        }
426
    }
427
428
    /**
429
     * Fill Job Poster's questions and save
430
     *
431
     * @param mixed[]               $input     Field values.
432
     * @param \App\Models\JobPoster $jobPoster Job Poster object.
433
     * @param boolean               $replace   Remove existing relationships.
434
     *
435
     * @return void
436
     */
437 2
    protected function fillAndSaveJobPosterQuestions(array $input, JobPoster $jobPoster, bool $replace) : void
438
    {
439 2
        if ($replace) {
440
            $jobPoster->job_poster_questions()->delete();
441
        }
442
443 2
        if (!array_key_exists('question', $input) || !is_array($input['question'])) {
444 2
            return;
445
        }
446
447
        foreach ($input['question'] as $question) {
448
            $jobQuestion = new JobPosterQuestion();
449
            $jobQuestion->job_poster_id = $jobPoster->id;
450
            $jobQuestion->fill(
451
                [
452
                    'en' => [
453
                        'question' => $question['question']['en'],
454
                        'description' => $question['description']['en']
455
                    ],
456
                    'fr' => [
457
                        'question' => $question['question']['fr'],
458
                        'description' => $question['description']['fr']
459
                    ]
460
                ]
461
            );
462
            $jobQuestion->save();
463
        }
464
    }
465
466
    /**
467
     * Fill Job Poster's criteria and save
468
     *
469
     * @param mixed[]               $input     Field values.
470
     * @param \App\Models\JobPoster $jobPoster Job Poster object.
471
     * @param boolean               $replace   Remove existing relationships.
472
     *
473
     * @return void
474
     */
475 2
    protected function fillAndSaveJobPosterCriteria(array $input, JobPoster $jobPoster, bool $replace) : void
476
    {
477 2
        if ($replace) {
478
            $jobPoster->criteria()->delete();
479
        }
480
481 2
        if (!array_key_exists('criteria', $input) || !is_array($input['criteria'])) {
482 2
            return;
483
        }
484
485
        $criteria = $input['criteria'];
486
487
        $combinedCriteria = [];
488
        if (isset($criteria['old'])) {
489
            $combinedCriteria = array_replace_recursive($combinedCriteria, $criteria['old']);
490
        }
491
        if (isset($criteria['new'])) {
492
            $combinedCriteria = array_replace_recursive($combinedCriteria, $criteria['new']);
493
        }
494
495
        if (! empty($combinedCriteria)) {
496
            foreach ($combinedCriteria as $criteriaType => $criteriaTypeInput) {
497
                foreach ($criteriaTypeInput as $skillType => $skillTypeInput) {
498
                    foreach ($skillTypeInput as $criteriaInput) {
499
                        $criteria = new Criteria();
500
                        $criteria->job_poster_id = $jobPoster->id;
501
                        $criteria->fill(
502
                            [
503
                                'criteria_type_id' => CriteriaType::where('name', $criteriaType)->firstOrFail()->id,
504
                                'skill_id' => $criteriaInput['skill_id'],
505
                                'skill_level_id' => $criteriaInput['skill_level_id'],
506
                                'en' => [
507
                                    'description' => $criteriaInput['description']['en'],
508
                                ],
509
                                'fr' => [
510
                                    'description' => $criteriaInput['description']['fr'],
511
                                ],
512
                            ]
513
                        );
514
                        $criteria->save();
515
                    }
516
                }
517
            }
518
        }
519
    }
520
521
    /**
522
     * Get the localized default questions and add them to an array.
523
     *
524
     * @return mixed[]|void
525
     */
526 2
    protected function populateDefaultQuestions()
527
    {
528
        $defaultQuestions = [
529 2
            'en' => array_values(Lang::get('manager/job_create', [], 'en')['questions']),
530 2
            'fr' => array_values(Lang::get('manager/job_create', [], 'fr')['questions']),
531
        ];
532
533 2
        if (count($defaultQuestions['en']) !== count($defaultQuestions['fr'])) {
534
            Log::warning('There must be the same number of French and English default questions for a Job Poster.');
535
            return;
536
        }
537
538 2
        $jobQuestions = [];
539
540 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...
541 2
            $jobQuestion = new JobPosterQuestion();
542 2
            $jobQuestion->fill(
543
                [
544
                    'en' => [
545 2
                        'question' => $defaultQuestions['en'][$i],
546
                    ],
547
                    'fr' => [
548 2
                        'question' => $defaultQuestions['fr'][$i],
549
                    ]
550
                ]
551
            );
552
            // Workaround for Default Questions with empty descriptions
553
            // throwing an error during save.
554
            // The id isn't actually used during the fillAndSaveJobPosterQuestions
555
            // method call.
556 2
            $jobQuestion->id = $i + 1;
557 2
            $jobQuestions[] = $jobQuestion;
558
        }
559
560 2
        return $jobQuestions;
561
    }
562
}
563