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

JobPoster   A

Complexity

Total Complexity 38

Size/Duplication

Total Lines 344
Duplicated Lines 0 %

Test Coverage

Coverage 91.94%

Importance

Changes 0
Metric Value
wmc 38
eloc 138
dl 0
loc 344
ccs 57
cts 62
cp 0.9194
rs 9.36
c 0
b 0
f 0

22 Methods

Rating   Name   Duplication   Size   Complexity  
A job_poster_translations() 0 3 1
A province() 0 3 1
A job_applications() 0 3 1
A language_requirement() 0 3 1
A job_term() 0 3 1
A department() 0 3 1
A manager() 0 3 1
A criteria() 0 3 1
A job_poster_questions() 0 3 1
A security_clearance() 0 3 1
A job_poster_key_tasks() 0 3 1
A submitted_applications() 0 4 1
A setPublishedAttribute() 0 8 5
A submitted_applications_count() 0 3 1
A timeRemaining() 0 26 4
A isClosed() 0 5 3
A applyBy() 0 14 2
A isOpen() 0 5 3
A displayStatus() 0 3 2
A status() 0 14 4
A resolveRouteBinding() 0 3 1
A toApiArray() 0 22 1
1
<?php
2
3
/**
4
 * Created by Reliese Model.
5
 * Date: Thu, 12 Jul 2018 22:39:27 +0000.
6
 */
7
8
namespace App\Models;
9
10
use App\Events\JobSaved;
11
use App\Models\JobApplication;
12
use Illuminate\Notifications\Notifiable;
13
use Illuminate\Support\Facades\App;
14
use Illuminate\Support\Facades\Lang;
15
use Jenssegers\Date\Date;
16
use \Backpack\CRUD\CrudTrait;
17
18
/**
19
 * Class JobPoster
20
 *
21
 * @property int $id
22
 * @property int $job_term_id
23
 * @property int $term_qty
24
 * @property \Jenssegers\Date\Date $open_date_time
25
 * @property \Jenssegers\Date\Date $close_date_time
26
 * @property \Jenssegers\Date\Date $start_date_time
27
 * @property \Jenssegers\Date\Date $review_requested_at
28
 * @property \Jessengers\Date\Date $published_at
29
 * @property int $department_id
30
 * @property int $province_id
31
 * @property int $salary_min
32
 * @property int $salary_max
33
 * @property int $noc
34
 * @property string $classification
35
 * @property int $security_clearance_id
36
 * @property int $language_requirement_id
37
 * @property boolean $remote_work_allowed
38
 * @property int $manager_id
39
 * @property boolean $published
40
 * @property \Jenssegers\Date\Date $created_at
41
 * @property \Jenssegers\Date\Date $updated_at
42
 *
43
 * @property int $submitted_applications_count
44
 *
45
 * @property \App\Models\Lookup\Department $department
46
 * @property \App\Models\Lookup\JobTerm $job_term
47
 * @property \App\Models\Lookup\LanguageRequirement $language_requirement
48
 * @property \App\Models\Manager $manager
49
 * @property \App\Models\Lookup\Province $province
50
 * @property \App\Models\Lookup\SecurityClearance $security_clearance
51
 * @property \Illuminate\Database\Eloquent\Collection $criteria
52
 * @property \Illuminate\Database\Eloquent\Collection $job_applications
53
 * @property \Illuminate\Database\Eloquent\Collection $job_poster_key_tasks
54
 * @property \Illuminate\Database\Eloquent\Collection $job_poster_questions
55
 * @property \Illuminate\Database\Eloquent\Collection $job_poster_translations
56
 * @property \Illuminate\Database\Eloquent\Collection $submitted_applications
57
 *
58
 * Localized Properties:
59
 * @property string $city
60
 * @property string $title
61
 * @property string $impact
62
 * @property string $branch
63
 * @property string $division
64
 * @property string $education
65
 *
66
 * Methods
67
 * @method boolean isOpen()
68
 * @method string timeRemaining()
69
 * @method string toApiArray()
70
 */
71
class JobPoster extends BaseModel
72
{
73
    use CrudTrait;
0 ignored issues
show
introduced by
The trait Backpack\CRUD\CrudTrait requires some properties which are not provided by App\Models\JobPoster: $Type, $fakeColumns
Loading history...
74
    use \Dimsav\Translatable\Translatable;
0 ignored issues
show
introduced by
The trait Dimsav\Translatable\Translatable requires some properties which are not provided by App\Models\JobPoster: $translations, $useTranslationFallback, $translationModel, $localeKey, $translationForeignKey
Loading history...
75
    use Notifiable;
0 ignored issues
show
introduced by
The trait Illuminate\Notifications\Notifiable requires some properties which are not provided by App\Models\JobPoster: $email, $phone_number
Loading history...
76
77
    const DATE_FORMAT = [
78
        'en' => 'M jS, Y',
79
        'fr' => 'd M Y',
80
    ];
81
    const TIME_FORMAT = [
82
        'en' => 'h:i A T',
83
        'fr' => 'H \h i T',
84
    ];
85
    const TIMEZONE = 'America/Toronto';
86
87
    /**
88
     * @var string[] $translatedAttributes
89
     */
90
    public $translatedAttributes = [
91
        'city',
92
        'title',
93
        'impact',
94
        'branch',
95
        'division',
96
        'education'
97
    ];
98
99
    /**
100
     * @var string[] $casts
101
     */
102
    protected $casts = [
103
        'job_term_id' => 'int',
104
        'department_id' => 'int',
105
        'province_id' => 'int',
106
        'salary_min' => 'int',
107
        'salary_max' => 'int',
108
        'noc' => 'int',
109
        'security_clearance_id' => 'int',
110
        'language_requirement_id' => 'int',
111
        'remote_work_allowed' => 'boolean',
112
        'manager_id' => 'int',
113
        'published' => 'boolean'
114
    ];
115
116
    /**
117
     * @var string[] $dates
118
     */
119
    protected $dates = [
120
        'open_date_time',
121
        'close_date_time',
122
        'start_date_time',
123
        'review_requested_at',
124
        'published_at'
125
    ];
126
127
    /**
128
     * @var string[] $fillable
129
     */
130
    protected $fillable = [
131
        'job_term_id',
132
        'term_qty',
133
        'open_date_time',
134
        'close_date_time',
135
        'start_date_time',
136
        'department_id',
137
        'province_id',
138
        'salary_min',
139
        'salary_max',
140
        'noc',
141
        'classification',
142
        'security_clearance_id',
143
        'language_requirement_id',
144
        'remote_work_allowed',
145
        'published'
146
    ];
147
148
    /**
149
     * @var mixed[] $dispatchesEvents
150
     */
151
    protected $dispatchesEvents = [
152
        'saved' => JobSaved::class,
153
    ];
154
155
    // @codeCoverageIgnoreStart
156
157
    public function department() // phpcs:ignore
158
    {
159
        return $this->belongsTo(\App\Models\Lookup\Department::class);
160
    }
161
162
    public function job_term() // phpcs:ignore
163
    {
164
        return $this->belongsTo(\App\Models\Lookup\JobTerm::class);
165
    }
166
167
    public function language_requirement() // phpcs:ignore
168
    {
169
        return $this->belongsTo(\App\Models\Lookup\LanguageRequirement::class);
170
    }
171
172
    public function manager() // phpcs:ignore
173
    {
174
        return $this->belongsTo(\App\Models\Manager::class);
175
    }
176
177
    public function province() // phpcs:ignore
178
    {
179
        return $this->belongsTo(\App\Models\Lookup\Province::class);
180
    }
181
182
    public function security_clearance() // phpcs:ignore
183
    {
184
        return $this->belongsTo(\App\Models\Lookup\SecurityClearance::class);
185
    }
186
187
    public function criteria() // phpcs:ignore
188
    {
189
        return $this->hasMany(\App\Models\Criteria::class);
190
    }
191
192
    public function job_applications() // phpcs:ignore
193
    {
194
        return $this->hasMany(\App\Models\JobApplication::class);
195
    }
196
197
    public function job_poster_key_tasks() // phpcs:ignore
198
    {
199
        return $this->hasMany(\App\Models\JobPosterKeyTask::class);
200
    }
201
202
    public function job_poster_questions() // phpcs:ignore
203
    {
204
        return $this->hasMany(\App\Models\JobPosterQuestion::class);
205
    }
206
207
    public function job_poster_translations() // phpcs:ignore
208
    {
209
        return $this->hasMany(\App\Models\JobPosterTranslation::class);
210
    }
211
212
    // Artificial Relations
213
214
    /**
215
     * Get all of the Job Applications submitted to this
216
     * Job Poster.
217
     *
218
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
219
     */
220
    public function submitted_applications() // phpcs:ignore
221
    {
222
        return $this->hasMany(\App\Models\JobApplication::class)->whereDoesntHave('application_status', function ($query) : void {
223
            $query->where('name', 'draft');
224
        });
225
    }
226
227
    // Overrides
228
229
    /**
230
     * Retrieve the model for a bound value.
231
     * Seems to be a useful workaround for providing submitted_applications_count
232
     * to any bound routes that receive a jobPoster instance without using the
233
     * withCount property on the model itself.
234
     * See https://github.com/laravel/framework/issues/23957 for more info.
235
     *
236
     * @param mixed $value Value used to retrieve the model instance.
237
     *
238
     * @return \Illuminate\Database\Eloquent\Model|null
239
     */
240
    public function resolveRouteBinding($value) // phpcs:ignore
241
    {
242
        return $this->withCount('submitted_applications')->where('id', $value)->first() ?? abort(404);
243
    }
244
245
    // @codeCoverageIgnoreEnd
246
247
    // Accessors
248
249
    // Mutators
250
251
    /**
252
     * Intercept setting the "published" attribute, and set the
253
     * "published_at" timestamp if true.
254
     *
255
     * @param mixed $value Incoming value for the 'published' attribute.
256
     *
257
     * @return void
258
     */
259 32
    public function setPublishedAttribute($value) : void
260
    {
261 32
        if ($value && $this->open_date_time->isPast()) {
262 20
            $this->attributes['published_at'] = new Date();
263 28
        } elseif ($value && $this->open_date_time->isFuture()) {
264 1
            $this->attributes['published_at'] = $this->open_date_time;
265
        }
266 32
        $this->attributes['published'] = $value;
267 32
    }
268
269
    // Methods
270
271 4
    public function submitted_applications_count()
1 ignored issue
show
Coding Style introduced by
Method name "JobPoster::submitted_applications_count" is not in camel caps format
Loading history...
introduced by
Method \App\Models\JobPoster::submitted_applications_count() does not have return type hint nor @return annotation for its return value.
Loading history...
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
272
    {
273 4
        return $this->submitted_applications()->count();
274
    }
275
276
    /**
277
     * Formatted and localized date and time the Job Poster closes.
278
     *
279
     * @return string[]
280
     */
281 1
    public function applyBy() : array
282
    {
283 1
        $localCloseDate = new Date($this->close_date_time); // This initializes the date object in UTC time
284 1
        $localCloseDate->setTimezone(new \DateTimeZone(self::TIMEZONE)); // Then set the time zone for display
285
        $displayDate = [
286 1
            'date' => $localCloseDate->format(self::DATE_FORMAT[App::getLocale()]),
287 1
            'time' => $localCloseDate->format(self::TIME_FORMAT[App::getLocale()])
288
        ];
289
290 1
        if (App::isLocale('fr')) {
291
            $displayDate['time'] = str_replace(['EST', 'EDT'], ['HNE', 'HAE'], $displayDate['time']);
292
        }
293
294 1
        return $displayDate;
295
    }
296
297
    /**
298
     * Return whether the Job is Open or Closed.
299
     * Used by the Admin Portal JobPosterCrudController.
300
     *
301
     * @return string
302
     */
303
    public function displayStatus() : string
304
    {
305
        return $this->isOpen() ? 'Open' : 'Closed';
306
    }
307
308
    /**
309
     * Check if a Job Poster is open for applications.
310
     *
311
     * @return boolean
312
     */
313 6
    public function isOpen() : bool
314
    {
315 6
        return $this->published
316 6
            && $this->open_date_time->isPast()
317 6
            && $this->close_date_time->isFuture();
318
    }
319
320
    /**
321
     * Check if a Job Poster is closed for applications.
322
     *
323
     * @return boolean
324
     */
325 4
    public function isClosed() : bool
326
    {
327 4
        return $this->published
328 4
            && $this->open_date_time->isPast()
329 4
            && $this->close_date_time->isPast();
330
    }
331
332
    /**
333
     * Calculate the remaining time a Job Poster is open.
334
     *
335
     * @return string
336
     */
337 1
    public function timeRemaining() : string
338
    {
339 1
        $interval = $this->close_date_time->diff(Date::now());
340
341 1
        $d = $interval->d;
342 1
        $h = $interval->h;
343 1
        $m = $interval->i;
344 1
        $s = $interval->s;
345
346 1
        if ($d > 0) {
347 1
            $unit = 'day';
348 1
            $count = $d;
349 1
        } elseif ($h > 0) {
350 1
            $unit = 'hour';
351 1
            $count = $h;
352 1
        } elseif ($m > 0) {
353 1
            $unit = 'minute';
354 1
            $count = $m;
355
        } else {
356
            $unit = 'second';
357
            $count = $s;
358
        }
359
360 1
        $key = "common/time.$unit";
361
362 1
        return Lang::choice($key, $count);
363
    }
364
365
    /**
366
     * Return the current status for the Job Poster.
367
     * Possible values are "draft", "submitted", "published" and "closed".
368
     *
369
     * @return string
370
     */
371 3
    public function status() : string
372
    {
373 3
        $status = 'draft';
374 3
        if ($this->isOpen()) {
375 1
            $status = 'published';
376 3
        } elseif ($this->isClosed()) {
377 1
            $status = 'closed';
378 3
        } elseif ($this->review_requested_at !== null) {
379 3
            $status = 'submitted';
380
        } else {
381 1
            $status = 'draft';
382
        }
383
384 3
        return $status;
385
    }
386
387
    /**
388
     * Return the array of values used to represent this object in an api response.
389
     * This array should contain no nested objects (besides translations).
390
     *
391
     * @return mixed[]
392
     */
393 2
    public function toApiArray()
0 ignored issues
show
introduced by
Method \App\Models\JobPoster::toApiArray() does not have return type hint for its return value but it should be possible to add it based on @return annotation "mixed[]".
Loading history...
394
    {
395 2
        $jobWithTranslations = array_merge($this->toArray(), $this->getTranslationsArray());
396 2
        $jobCollection = collect($jobWithTranslations)->only([
397 2
            'id',
398
            'term_qty',
399
            'open_date_time',
400
            'close_date_time',
401
            'start_date_time',
402
            'department_id',
403
            'province_id',
404
            'salary_min',
405
            'salary_max',
406
            'noc',
407
            'classification',
408
            'security_clearance_id',
409
            'language_requirement_id',
410
            'remote_work_allowed',
411
            'en',
412
            'fr',
413 2
        ])->all();
414 2
        return $jobCollection;
415
    }
416
}
417