Completed
Push — allow-managers-to-edit-job-pos... ( e10d0a...708fd6 )
by
unknown
19:48 queued 08:28
created

JobController::fillAndSaveJobPosterQuestions()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
eloc 15
dl 0
loc 26
ccs 0
cts 14
cp 0
rs 9.7666
c 0
b 0
f 0
cc 4
nc 6
nop 3
crap 20
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\Http\RedirectResponse;
8
use Illuminate\Http\Request;
9
use Illuminate\Http\Response;
10
use Illuminate\View\View;
11
use App\Http\Controllers\Controller;
12
use Carbon\Carbon;
13
use App\Models\JobPoster;
14
use App\Models\Lookup\JobTerm;
15
use App\Models\Lookup\Province;
16
use App\Models\Lookup\SecurityClearance;
17
use App\Models\Lookup\LanguageRequirement;
18
use App\Models\Lookup\CitizenshipDeclaration;
19
use App\Models\Lookup\Department;
20
use App\Models\Lookup\SkillLevel;
21
use App\Models\Lookup\CriteriaType;
22
use App\Models\Lookup\VeteranStatus;
23
use App\Models\JobApplication;
24
use App\Models\Criteria;
25
use App\Models\Skill;
26
use App\Models\JobPosterQuestion;
27
use App\Models\JobPosterKeyTask;
28
use App\Services\Validation\JobPosterValidator;
29
use Jenssegers\Date\Date;
30
31
class JobController extends Controller
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class JobController
Loading history...
32
{
33
    /**
34
     * Display a listing of JobPosters.
35
     *
36
     * @return \Illuminate\Http\Response
37
     */
38
    public function index()
39
    {
40
        $now = Carbon::now();
41
        //Find published jobs that are currently open for applications
42
        $jobs = JobPoster::where('open_date_time', '<=', $now)
43
            ->where('close_date_time', '>=', $now)
44
            ->where('published', true)
45
            ->get();
46
        $jobs->load('manager.work_environment');
47
        return view('applicant/job_index', ['job_index' => Lang::get('applicant/job_index'),
1 ignored issue
show
Bug Best Practice introduced by
The expression return view('applicant/j...ex'), 'jobs' => $jobs)) returns the type Illuminate\View\View which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
48
            'jobs' => $jobs]);
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...
49
    }
50
51
    /**
52
     * Display a listing of a manager's JobPosters.
53
     *
54
     * @return \Illuminate\Http\Response
55
     */
56 2
    public function managerIndex()
57
    {
58 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...
59
60 2
        $veteran_applications = [];
61 2
        $citizen_applications = [];
62 2
        $other_applications = [];
63
64 2
        foreach($manager->job_posters as $job) {
0 ignored issues
show
Coding Style introduced by
Expected "foreach (...) {\n"; found "foreach(...) {\n"
Loading history...
65
            $job->submitted_applications->load(['veteran_status', 'citizenship_declaration']);
66
            $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...
67
                return $application->veteran_status->name !== "none" &&
68
                        $application->citizenship_declaration->name === "citizen";
69
            });
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...
70
            $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...
71
                return $application->veteran_status->name === "none" &&
72
                        $application->citizenship_declaration->name === "citizen";
73
            });
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...
74
            $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...
75
                return $application->citizenship_declaration->name !== "citizen";
76
            });
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
        }
78
79 2
        return view('manager/job_index', [
1 ignored issue
show
Bug Best Practice introduced by
The expression return view('manager/job...> $other_applications)) returns the type Illuminate\View\View which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
80 2
            "manager_job_index" => [
81
                "title" => "My Job Posts"
82
            ],
83 2
            'jobs' => $manager->job_posters,
84 2
            'veteran_applications' => $veteran_applications,
85 2
            'citizen_applications' => $citizen_applications,
86 2
            'other_applications' => $other_applications,
87
        ]);
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...
88
    }
89
90
    /**
91
     * Display the specified job poster.
92
     *
93
     * @param \Illuminate\Http\Request $request   Incoming request object.
94
     * @param \App\Models\JobPoster    $jobPoster Job Poster object.
95
     *
96
     * @return \Illuminate\View\View
97
     */
98
    public function show(Request $request, JobPoster $jobPoster) : View
99
    {
100
        //TODO: Improve workplace photos, and reference them in template direction from WorkEnvironment model
101
        $workplacePhotos = [];
102
        foreach ($jobPoster->manager->work_environment->workplace_photo_captions as $photoCaption) {
103
            $workplacePhotos[] = [
104
                'description' => $photoCaption->description,
105
                'url' => '/images/user.png'
106
            ];
107
        }
108
109
        //TODO: replace route('manager.show',manager.id) in templates with link using slug
110
111
        $criteria = [
112
            'essential' => $jobPoster->criteria->filter(
113
                function ($value, $key) {
114
                    return $value->criteria_type->name == 'essential';
115
                }
116
            ),
117
            'asset' => $jobPoster->criteria->filter(
118
                function ($value, $key) {
119
                    return $value->criteria_type->name == 'asset';
120
                }
121
            ),
122
        ];
123
124
        return view(
125
            'applicant/job_post',
126
            [
127
                'job_post' => Lang::get('applicant/job_post'),
128
                'manager' => $jobPoster->manager,
129
                'manager_profile_photo_url' => '/images/user.png', //TODO get real photo
130
                'team_culture' => $jobPoster->manager->team_culture,
131
                'work_environment' => $jobPoster->manager->work_environment,
132
                'workplace_photos' => $workplacePhotos,
133
                'job' => $jobPoster,
134
                'criteria' => $criteria,
135
                'skill_template' => Lang::get('common/skills'),
136
            ]
137
        );
138
    }
139
140
    /**
141
     * Display the form for creating a new Job Poster
142
     *
143
     * @param \Illuminate\Http\Request $request Incoming request object.
144
     *
145
     * @return \Illuminate\View\View Job Create view
146
     */
147
    public function create(Request $request) : View
148
    {
149
        return $this->populateCreateView($request);
150
    }
151
152
    /**
153
     * Display the form for editing an existing Job Poster
154
     *
155
     * @param \Illuminate\Http\Request $request   Incoming request object.
156
     * @param \App\Models\JobPoster    $jobPoster Job Poster object.
157
     *
158
     * @return \Illuminate\View\View Job Create view
159
     */
160
    public function edit(Request $request, JobPoster $jobPoster) : View
161
    {
162
        return $this->populateCreateView($request, $jobPoster);
163
    }
164
165
    /**
166
     * Get the manager from the request object and check if creating or editing
167
     *
168
     * @param \Illuminate\Http\Request $request   Incoming request object.
169
     * @param \App\Models\JobPoster    $jobPoster Optional Job Poster object.
170
     *
171
     * @return \Illuminate\View\View Job Create view
172
     */
173
    public function populateCreateView(Request $request, JobPoster $jobPoster = null) : View
174
    {
175
        $manager = $request->user() ? $request->user()->manager : null;
176
        if (isset($jobPoster)) {
177
            $job = $jobPoster;
178
            $route = ['manager.jobs.store', $jobPoster];
179
            $jobHeading = 'manager/job_edit';
180
        } else {
181
            $job = [];
182
            $route = ['manager.jobs.store'];
183
            $jobHeading = 'manager/job_create';
184
        }
185
186
        return view(
187
            'manager/job_create',
188
            [
189
                'job_heading' => Lang::get($jobHeading),
190
                'manager' => $manager,
191
                'provinces' => Province::all(),
192
                'departments' => Department::all(),
193
                'language_requirments' => LanguageRequirement::all(),
194
                'security_clearances' => SecurityClearance::all(),
195
                'job' => $job,
196
                '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

196
                'form_action_url' => route(/** @scrutinizer ignore-type */ /** @scrutinizer ignore-type */ ...$route), // phpcs:ignore
Loading history...
197
                'skills' => Skill::all(),
198
                'skill_levels' => SkillLevel::all(),
199
                'skill_template' => Lang::get('common/skills'),
200
            ]
201
        );
202
    }
203
204
    /**
205
     * Create a new resource in storage
206
     *
207
     * @param \Illuminate\Http\Request $request   Incoming request object.
208
     * @param \App\Models\JobPoster    $jobPoster Optional Job Poster object.
209
     *
210
     * @return \Illuminate\Http\RedirectResponse A redirect to the Job Index
211
     */
212
    public function store(Request $request, JobPoster $jobPoster = null) : RedirectResponse
213
    {
214
        // Don't allow edits for published Job Posters
215
        if (isset($jobPoster)) {
216
            JobPosterValidator::validateUnpublished($jobPoster);
217
        }
218
219
        $input = $request->input();
220
221
        $job = (isset($jobPoster) ? $jobPoster : new JobPoster());
222
223
        $job->manager_id = $request->user()->manager->id;
224
        $job->published = ($input['submit'] == 'publish');
225
226
        $this->fillAndSaveJobPoster($input, $job);
227
228
        $this->fillAndSaveJobPosterTasks($input, $job, isset($jobPoster));
229
230
        $this->fillAndSaveJobPosterQuestions($input, $job, isset($jobPoster));
231
232
        $this->fillAndSaveJobPosterCriteria($input, $job, isset($jobPoster));
233
234
        return redirect(route('manager.jobs.index'));
235
    }
236
237
    /**
238
     * Fill Job Poster model's properties and save
239
     *
240
     * @param mixed[]               $input     Field values.
241
     * @param \App\Models\JobPoster $jobPoster Job Poster object.
242
     *
243
     * @return void
244
     */
245
    protected function fillAndSaveJobPoster(array $input, JobPoster $jobPoster) : void
246
    {
247
        $jobPoster->fill(
248
            [
249
                'job_term_id' => JobTerm::where('name', 'month')->firstOrFail()->id,
250
                'term_qty' => $input['term_qty'],
251
                'open_date_time' => new Date($input['open_date'] . $input['open_time']),
252
                'close_date_time' => new Date($input['close_date'] . $input['close_time']),
253
                'start_date_time' => new Date($input['start_date_time']),
254
                'department_id' => $input['department'],
255
                'province_id' => $input['province'],
256
                'salary_min' => $input['salary_min'],
257
                'salary_max' => $input['salary_max'],
258
                'noc' => $input['noc'],
259
                'classification' => $input['classification'],
260
                'security_clearance_id' => $input['security_clearance'],
261
                'language_requirement_id' => $input['language_requirement'],
262
                'remote_work_allowed' => (isset($input['remote_work_allowed']) ? $input['remote_work_allowed'] : false),
263
                'en' => [
264
                    'city' => $input['city'],
265
                    'title' => $input['title']['en'],
266
                    'impact' => $input['impact']['en'],
267
                    'branch' => $input['branch']['en'],
268
                    'division' => $input['division']['en'],
269
                    'education' => $input['education']['en'],
270
                ],
271
                'fr' => [
272
                    'city' => $input['city'],
273
                    'title' => $input['title']['fr'],
274
                    'impact' => $input['impact']['fr'],
275
                    'branch' => $input['branch']['fr'],
276
                    'division' => $input['division']['fr'],
277
                    'education' => $input['education']['fr'],
278
                ],
279
            ]
280
        );
281
        $jobPoster->save();
282
    }
283
284
    /**
285
     * Fill Job Poster's tasks and save
286
     *
287
     * @param mixed[]               $input     Field values.
288
     * @param \App\Models\JobPoster $jobPoster Job Poster object.
289
     * @param boolean               $replace   Remove existing relationships.
290
     *
291
     * @return void
292
     */
293
    protected function fillAndSaveJobPosterTasks(array $input, JobPoster $jobPoster, bool $replace) : void
294
    {
295
        if ($replace) {
296
            $jobPoster->job_poster_key_tasks()->delete();
297
        }
298
299
        if (!is_array($input['task'])) {
300
            return;
301
        }
302
303
        foreach ($input['task'] as $task) {
304
            $jobPosterTask = new JobPosterKeyTask();
305
            $jobPosterTask->job_poster_id = $jobPoster->id;
306
            $jobPosterTask->fill(
307
                [
308
                    'en' => [
309
                        'description' => $task['en']
310
                    ],
311
                    'fr' => [
312
                        'description' => $task['fr']
313
                    ]
314
                ]
315
            );
316
            $jobPosterTask->save();
317
        }
318
    }
319
320
    /**
321
     * Fill Job Poster's questions and save
322
     *
323
     * @param mixed[]               $input     Field values.
324
     * @param \App\Models\JobPoster $jobPoster Job Poster object.
325
     * @param boolean               $replace   Remove existing relationships.
326
     *
327
     * @return void
328
     */
329
    protected function fillAndSaveJobPosterQuestions(array $input, JobPoster $jobPoster, bool $replace) : void
330
    {
331
        if ($replace) {
332
            $jobPoster->job_poster_questions()->delete();
333
        }
334
335
        if (!is_array($input['question'])) {
336
            return;
337
        }
338
339
        foreach ($input['question'] as $question) {
340
            $jobQuestion = new JobPosterQuestion();
341
            $jobQuestion->job_poster_id = $jobPoster->id;
342
            $jobQuestion->fill(
343
                [
344
                    'en' => [
345
                        'question' => $question['question']['en'],
346
                        'description' => $question['description']['en']
347
                    ],
348
                    'fr' => [
349
                        'question' => $question['question']['fr'],
350
                        'description' => $question['description']['fr']
351
                    ]
352
                ]
353
            );
354
            $jobQuestion->save();
355
        }
356
    }
357
358
    /**
359
     * Fill Job Poster's criteria and save
360
     *
361
     * @param mixed[]               $input     Field values.
362
     * @param \App\Models\JobPoster $jobPoster Job Poster object.
363
     * @param boolean               $replace   Remove existing relationships.
364
     *
365
     * @return void
366
     */
367
    protected function fillAndSaveJobPosterCriteria(array $input, JobPoster $jobPoster, bool $replace) : void
368
    {
369
        if ($replace) {
370
            $jobPoster->criteria()->delete();
371
        }
372
373
        if (!is_array($input['criteria'])) {
374
            return;
375
        }
376
377
        $criteria = $input['criteria'];
378
379
        $combinedCriteria = [];
380
        if (isset($criteria['old'])) {
381
            $combinedCriteria = array_replace_recursive($combinedCriteria, $criteria['old']);
382
        }
383
        if (isset($criteria['new'])) {
384
            $combinedCriteria = array_replace_recursive($combinedCriteria, $criteria['new']);
385
        }
386
387
        if (! empty($combinedCriteria)) {
388
            foreach ($combinedCriteria as $criteriaType => $criteriaTypeInput) {
389
                foreach ($criteriaTypeInput as $skillType => $skillTypeInput) {
390
                    foreach ($skillTypeInput as $criteriaInput) {
391
                        $criteria = new Criteria();
392
                        $criteria->job_poster_id = $jobPoster->id;
393
                        $criteria->fill(
394
                            [
395
                                'criteria_type_id' => CriteriaType::where('name', $criteriaType)->firstOrFail()->id,
396
                                'skill_id' => $criteriaInput['skill_id'],
397
                                'skill_level_id' => $criteriaInput['skill_level_id'],
398
                                'en' => [
399
                                    'description' => $criteriaInput['description']['en'],
400
                                ],
401
                                'fr' => [
402
                                    'description' => $criteriaInput['description']['fr'],
403
                                ],
404
                            ]
405
                        );
406
                        $criteria->save();
407
                    }
408
                }
409
            }
410
        }
411
    }
412
}
413