Passed
Push — feature/hr-portal ( 75893b...20cd57 )
by Tristan
09:26
created

JobController::hrIndex()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
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\Http\Request;
9
use App\Http\Controllers\Controller;
10
use Carbon\Carbon;
11
use App\Models\JobPoster;
12
use App\Models\JobPosterQuestion;
13
use App\Models\Manager;
14
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
15
use App\Services\Validation\JobPosterValidator;
16
17
class JobController extends Controller
18
{
19
    /**
20
     * Display a listing of JobPosters.
21
     *
22
     * @return \Illuminate\Http\Response
23
     */
24
    public function index()
25
    {
26
        $now = Carbon::now();
27
28
        // Find published jobs that are currently open for applications.
29
        // Eager load required relationships: Department, Province, JobTerm.
30
        // Eager load the count of submitted applications, to prevent the relationship
31
        // from being actually loaded and firing off events.
32
        $jobs = JobPoster::where('open_date_time', '<=', $now)
33
            ->where('close_date_time', '>=', $now)
34
            ->where('published', true)
35
            ->with([
36
                'department',
37
                'province',
38
                'job_term',
39
            ])
40
            ->withCount([
41
                'submitted_applications',
42
            ])
43
            ->get();
44
        return view('applicant/job_index', [
45
            'job_index' => Lang::get('applicant/job_index'),
46
            'jobs' => $jobs
47
        ]);
48
    }
49
50
    /**
51
     * Display a listing of a manager's JobPosters.
52
     *
53
     * @return \Illuminate\Http\Response
54
     */
55
    public function managerIndex()
56
    {
57
        $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...
58
59
        $jobs = JobPoster::where('manager_id', $manager->id)
60
            ->with('classification')
61
            ->withCount('submitted_applications')
62
            ->get();
63
64
        foreach ($jobs as &$job) {
65
            $chosen_lang = $job->chosen_lang;
66
67
            // Show chosen lang title if current title is empty.
68
            if (empty($job->title)) {
69
                $job->title = $job->translate($chosen_lang)->title;
70
                $job->trans_required = true;
0 ignored issues
show
Bug introduced by
The property trans_required does not seem to exist on App\Models\JobPoster. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
71
            }
72
73
            // Always preview and edit in the chosen language.
74
            $job->preview_link = LaravelLocalization::getLocalizedURL($chosen_lang, route('manager.jobs.show', $job));
0 ignored issues
show
Bug introduced by
The property preview_link does not seem to exist on App\Models\JobPoster. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
75
            $job->edit_link = LaravelLocalization::getLocalizedURL($chosen_lang, route('manager.jobs.edit', $job));
0 ignored issues
show
Bug introduced by
The property edit_link does not seem to exist on App\Models\JobPoster. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
76
        }
77
78
79
        return view('manager/job_index', [
80
            // Localization Strings.
81
            'jobs_l10n' => Lang::get('manager/job_index'),
82
            // Data.
83
            'jobs' => $jobs,
84
        ]);
85
    }
86
87
    /**
88
     * Display a listing of a hr adviser's JobPosters.
89
     *
90
     * @return \Illuminate\Http\Response
91
     */
92
    public function hrIndex()
93
    {
94
        return view('hr_advisor/job_index', []);
95
    }
96
97
98
99
100
    /**
101
     * Delete a draft Job Poster.
102
     *
103
     * @param  \Illuminate\Http\Request $request   Incoming request object.
104
     * @param  \App\Models\JobPoster    $jobPoster Job Poster object.
105
     * @return \Illuminate\Http\Response
1 ignored issue
show
Coding Style introduced by
Function return type is not void, but function has no return statement
Loading history...
106
     */
107
    public function destroy(Request $request, JobPoster $jobPoster)
108
    {
109
        $jobPoster->delete();
110
    }
111
112
    /**
113
     * Display the specified job poster.
114
     *
115
     * @param  \Illuminate\Http\Request $request   Incoming request object.
116
     * @param  \App\Models\JobPoster    $jobPoster Job Poster object.
117
     * @return \Illuminate\Http\Response
118
     */
119
    public function show(Request $request, JobPoster $jobPoster)
120
    {
121
        $jobPoster->load([
122
            'department',
123
            'criteria.skill.skill_type',
124
            'manager.team_culture',
125
            'manager.work_environment'
126
        ]);
127
128
        $user = Auth::user();
0 ignored issues
show
Unused Code introduced by
The assignment to $user is dead and can be removed.
Loading history...
129
130
        // TODO: Improve workplace photos, and reference them in template direction from WorkEnvironment model.
131
        $workplacePhotos = [];
132
        foreach ($jobPoster->manager->work_environment->workplace_photo_captions as $photoCaption) {
133
            $workplacePhotos[] = [
134
                'description' => $photoCaption->description,
135
                'url' => '/images/user.png'
136
            ];
137
        }
138
139
        // TODO: replace route('manager.show',manager.id) in templates with link using slug.
140
        $criteria = [
141
            'essential' => $jobPoster->criteria->filter(
142
                function ($value, $key) {
143
                    return $value->criteria_type->name == 'essential';
144
                }
145
            ),
146
            'asset' => $jobPoster->criteria->filter(
147
                function ($value, $key) {
148
                    return $value->criteria_type->name == 'asset';
149
                }
150
            ),
151
        ];
152
153
        $jobLang = Lang::get('applicant/job_post');
154
155
        $applyButton = [];
156
        if (!$jobPoster->published && $this->authorize('update', $jobPoster)) {
157
            $applyButton = [
158
                'href' => route('manager.jobs.edit', $jobPoster->id),
159
                'title' => $jobLang['apply']['edit_link_title'],
160
                'text' => $jobLang['apply']['edit_link_label'],
161
            ];
162
        } elseif (Auth::check() && $jobPoster->isOpen()) {
163
            $applyButton = [
164
                'href' => route('job.application.edit.1', $jobPoster->id),
165
                'title' => $jobLang['apply']['apply_link_title'],
166
                'text' => $jobLang['apply']['apply_link_label'],
167
            ];
168
        } elseif (Auth::guest() && $jobPoster->isOpen()) {
169
            $applyButton = [
170
                'href' => route('job.application.edit.1', $jobPoster->id),
171
                'title' => $jobLang['apply']['login_link_title'],
172
                'text' => $jobLang['apply']['login_link_label'],
173
            ];
174
        } else {
175
            $applyButton = [
176
                'href' => null,
177
                'title' => null,
178
                'text' => $jobLang['apply']['job_closed_label'],
179
            ];
180
        }
181
182
        $jpb_release_date = strtotime('2019-08-21 16:18:17');
183
        $job_created_at = strtotime($jobPoster->created_at);
184
185
        // If the job poster is created after the release of the JPB.
186
        // Then, render with updated poster template.
187
        // Else, render with old poster template.
188
        if ($job_created_at > $jpb_release_date) {
189
            // Updated job poster (JPB).
190
            return view(
191
                'applicant/jpb_job_post',
192
                [
193
                    'job_post' => $jobLang,
194
                    'skill_template' => Lang::get('common/skills'),
195
                    'job' => $jobPoster,
196
                    'manager' => $jobPoster->manager,
197
                    'criteria' => $criteria,
198
                    'apply_button' => $applyButton,
199
                ]
200
            );
201
        } else {
202
            // Old job poster.
203
            return view(
204
                'applicant/job_post',
205
                [
206
                    'job_post' => $jobLang,
207
                    'manager' => $jobPoster->manager,
208
                    'manager_profile_photo_url' => '/images/user.png', // TODO get real photo.
209
                    'team_culture' => $jobPoster->manager->team_culture,
210
                    'work_environment' => $jobPoster->manager->work_environment,
211
                    'workplace_photos' => $workplacePhotos,
212
                    'job' => $jobPoster,
213
                    'criteria' => $criteria,
214
                    'apply_button' => $applyButton,
215
                    'skill_template' => Lang::get('common/skills'),
216
                ]
217
            );
218
        }
219
    }
220
221
    /**
222
     * Display the form for editing an existing Job Poster
223
     * Only allows editing fields that don't appear on the react-built Job Poster Builder.
224
     *
225
     * @param  \Illuminate\Http\Request $request   Incoming request object.
226
     * @param  \App\Models\JobPoster    $jobPoster Job Poster object.
227
     * @return \Illuminate\Http\Response
228
     */
229
    public function edit(Request $request, JobPoster $jobPoster)
230
    {
231
        $manager = $jobPoster->manager;
232
233
        if ($jobPoster->job_poster_questions === null || $jobPoster->job_poster_questions->count() === 0) {
234
            $jobPoster->job_poster_questions()->saveMany($this->populateDefaultQuestions());
235
            $jobPoster->refresh();
236
        }
237
238
        return view(
239
            'manager/job_create',
240
            [
241
                // Localization Strings.
242
                'job_l10n' => Lang::get('manager/job_edit'),
243
                // Data.
244
                'manager' => $manager,
245
                'job' => $jobPoster,
246
                'form_action_url' => route('admin.jobs.update', $jobPoster),
247
            ]
248
        );
249
    }
250
251
    /**
252
     * Create a blank job poster for the specified manager
253
     *
254
     * @param  \App\Models\Manager $manager Incoming Manager object.
255
     * @return \Illuminate\Http\Response Job Create view
256
     */
257
    public function createAsManager(Manager $manager)
258
    {
259
        $jobPoster = new JobPoster();
260
        $jobPoster->manager_id = $manager->id;
261
262
        // Save manager-specific info to the job poster - equivalent to the intro step of the JPB
263
        $divisionEn = $manager->translate('en') !== null ? $manager->translate('en')->division : null;
264
        $divisionFr = $manager->translate('fr') !== null ? $manager->translate('fr')->division : null;
265
        $jobPoster->fill([
266
            'department_id' => $manager->department_id,
267
            'en' => ['division' => $divisionEn],
268
            'fr' => ['division' => $divisionFr],
269
        ]);
270
271
        $jobPoster->save();
272
273
        return redirect()->route('manager.jobs.edit', $jobPoster->id);
274
    }
275
276
    /**
277
     * Update a resource in storage
278
     * NOTE: Only saves fields that are not on the react-built Job Poster Builder
279
     *
280
     * @param  \Illuminate\Http\Request $request   Incoming request object.
281
     * @param  \App\Models\JobPoster    $jobPoster Optional Job Poster object.
282
     * @return \Illuminate\Http\Response
283
     */
284
    public function store(Request $request, JobPoster $jobPoster)
285
    {
286
        // Don't allow edits for published Job Posters
287
        // Also check auth while we're at it.
288
        $this->authorize('update', $jobPoster);
289
        JobPosterValidator::validateUnpublished($jobPoster);
290
291
        $input = $request->input();
292
293
        if ($jobPoster->manager_id == null) {
294
            $jobPoster->manager_id = $request->user()->manager->id;
295
            $jobPoster->save();
296
        }
297
298
        $this->fillAndSaveJobPosterQuestions($input, $jobPoster, true);
299
300
        return redirect(route('manager.jobs.show', $jobPoster->id));
301
    }
302
303
    /**
304
     * Fill Job Poster's questions and save
305
     *
306
     * @param  mixed[]               $input     Field values.
307
     * @param  \App\Models\JobPoster $jobPoster Job Poster object.
308
     * @param  boolean               $replace   Remove existing relationships.
309
     * @return void
310
     */
311
    protected function fillAndSaveJobPosterQuestions(array $input, JobPoster $jobPoster, bool $replace) : void
312
    {
313
        if ($replace) {
314
            $jobPoster->job_poster_questions()->delete();
315
        }
316
317
        if (!array_key_exists('question', $input) || !is_array($input['question'])) {
318
            return;
319
        }
320
321
        foreach ($input['question'] as $question) {
322
            $jobQuestion = new JobPosterQuestion();
323
            $jobQuestion->job_poster_id = $jobPoster->id;
324
            $jobQuestion->fill(
325
                [
326
                    'en' => [
327
                        'question' => $question['question']['en'],
328
                        'description' => $question['description']['en']
329
                    ],
330
                    'fr' => [
331
                        'question' => $question['question']['fr'],
332
                        'description' => $question['description']['fr']
333
                    ]
334
                ]
335
            );
336
            $jobPoster->save();
337
            $jobQuestion->save();
338
        }
339
    }
340
341
    /**
342
     * Get the localized default questions and add them to an array.
343
     *
344
     * @return mixed[]|void
345
     */
346
    protected function populateDefaultQuestions()
347
    {
348
        $defaultQuestions = [
349
            'en' => array_values(Lang::get('manager/job_create', [], 'en')['questions']),
350
            'fr' => array_values(Lang::get('manager/job_create', [], 'fr')['questions']),
351
        ];
352
353
        if (count($defaultQuestions['en']) !== count($defaultQuestions['fr'])) {
354
            Log::warning('There must be the same number of French and English default questions for a Job Poster.');
355
            return;
356
        }
357
358
        $jobQuestions = [];
359
360
        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...
361
            $jobQuestion = new JobPosterQuestion();
362
            $jobQuestion->fill(
363
                [
364
                    'en' => [
365
                        'question' => $defaultQuestions['en'][$i],
366
                    ],
367
                    'fr' => [
368
                        'question' => $defaultQuestions['fr'][$i],
369
                    ]
370
                ]
371
            );
372
            $jobQuestions[] = $jobQuestion;
373
        }
374
375
        return $jobQuestions;
376
    }
377
}
378