EventService::getRepetitionTextString()   B
last analyzed

Complexity

Conditions 7
Paths 6

Size

Total Lines 59
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 7.4951

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 38
nc 6
nop 2
dl 0
loc 59
ccs 29
cts 37
cp 0.7838
crap 7.4951
rs 8.3786
c 1
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace App\Services;
4
5
use App\Helpers\DateHelpers;
6
use App\Helpers\Helper;
7
use App\Helpers\ImageHelpers;
8
use App\Http\Requests\EventStoreRequest;
9
use App\Models\Event;
10
use App\Models\EventRepetition;
11
use App\Repositories\EventRepository;
12
use App\Repositories\EventRepositoryInterface;
13
use Carbon\Carbon;
14
use DateTime;
15
use Illuminate\Support\Collection;
16
use Illuminate\Support\Facades\Cache;
17
use Illuminate\Support\Facades\Log;
18
19
class EventService
20
{
21
    private EventRepositoryInterface $eventRepository;
22
    private EventRepetitionService $eventRepetitionService;
23
    private NotificationService $notificationService;
24
25
    /**
26
     * EventService constructor.
27
     *
28
     * @param  EventRepositoryInterface  $eventRepository
29 22
     * @param  EventRepetitionService  $eventRepetitionService
30
     * @param  NotificationService  $notificationService
31
     */
32
    public function __construct(
33 22
        EventRepositoryInterface $eventRepository,
34 22
        EventRepetitionService $eventRepetitionService,
35 22
        NotificationService $notificationService
36
    ) {
37
        $this->eventRepository = $eventRepository;
38
        $this->eventRepetitionService = $eventRepetitionService;
39
        $this->notificationService = $notificationService;
40
    }
41
42
    /**
43
     * Create a event
44
     *
45
     * @param \App\Http\Requests\EventStoreRequest $request
46
     *
47 4
     * @return \App\Models\Event
48
     * @throws \Spatie\ModelStatus\Exceptions\InvalidStatus
49 4
     */
50 4
    public function createEvent(EventStoreRequest $request): Event
51
    {
52 4
        $event = $this->eventRepository->store($request->all());
53
        ImageHelpers::storeImages($event, $request, 'introimage');
54 4
55
        $this->eventRepetitionService->updateEventRepetitions($request->all(), $event->id);
56 4
57
        $this->cleanActiveEventsCaches();
58
59
        return $event;
60
    }
61
62
    /**
63
     * Update the Event
64
     *
65
     * @param \App\Http\Requests\EventStoreRequest $request
66
     * @param int $eventId
67
     *
68
     * @return \App\Models\Event
69
     */
70 1
71
    public function updateEvent(EventStoreRequest $request, int $eventId): Event
72 1
    {
73
        $event = $this->eventRepository->update($request->all(), $eventId);
74 1
75 1
        ImageHelpers::storeImages($event, $request, 'introimage');
76
        ImageHelpers::deleteImages($event, $request, 'introimage');
77 1
78
        $this->eventRepetitionService->updateEventRepetitions($request->all(), $eventId);
79 1
        $this->cleanActiveEventsCaches();
80
81
        return $event;
82
    }
83
84
    /**
85
     * Return the event from the database
86
     *
87
     * @param int $eventId
88
     *
89 1
     * @return \App\Models\Event
90
     */
91 1
    public function getById(int $eventId): Event
92
    {
93
        return $this->eventRepository->getById($eventId);
94
    }
95
96
    /**
97
     * Return the event from the database by SLUG
98
     *
99
     * @param  string  $eventSlug
100
     * @return Event
101
     */
102 1
    public function getBySlug(string $eventSlug): Event
103
    {
104 1
        return $this->eventRepository->getBySlug($eventSlug);
105
    }
106
107
    /**
108
     * Get all the Events.
109
     *
110
     * @param int|null $recordsPerPage
111
     * @param array|null $searchParameters
112 1
     *
113
     * @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Contracts\Pagination\LengthAwarePaginator
114 1
     */
115 1
    public function getEvents(int $recordsPerPage = null, array $searchParameters = null)
116
    {
117
        return $this->eventRepository->getAll($recordsPerPage, $searchParameters);
118
    }
119
120
    /**
121
     * Delete the event from the database
122 1
     *
123
     * @param int $eventId
124 1
     */
125
    public function deleteEvent(int $eventId): void
126
    {
127
        $this->eventRepository->delete($eventId);
128
        $this->cleanActiveEventsCaches();
129
    }
130
131
    /**
132
     * Get the number of event created in the last 30 days.
133
     *
134
     * @return int
135
     */
136
    public function getNumberEventsCreatedLastThirtyDays(): int
137
    {
138
        return Event::whereDate('created_at', '>', date('Y-m-d', strtotime('-30 days')))->count();
139 1
    }
140
141 1
    /**
142 1
     * Return an array with the event data related to:
143 1
     * - date and time start
144
     * - date and time end
145
     * - repeat until
146
     * - multiple dates
147
     *
148 1
     * @param Event $event
149 1
     * @param EventRepetition $eventFirstRepetition
150 1
     *
151 1
     * @return array
152 1
     */
153 1
    public function getEventDateTimeParameters(Event $event, EventRepetition $eventFirstRepetition): array
154
    {
155 1
        $dateTime = [];
156 1
        $dateTime['dateStart'] = (isset($eventFirstRepetition->start_repeat)) ? date('d/m/Y', strtotime($eventFirstRepetition->start_repeat)) : '';
157
        $dateTime['dateEnd'] = (isset($eventFirstRepetition->end_repeat)) ? date('d/m/Y', strtotime($eventFirstRepetition->end_repeat)) : '';
158 1
159
        //$dateTime['timeStart'] = (isset($eventFirstRepetition->start_repeat)) ? date('g:i A', strtotime($eventFirstRepetition->start_repeat)) : '';
160
        //$dateTime['timeEnd'] = (isset($eventFirstRepetition->end_repeat)) ? date('g:i A', strtotime($eventFirstRepetition->end_repeat)) : '';
161
162
        $dateTime['timeStartHours'] = (isset($eventFirstRepetition->start_repeat)) ? date('g', strtotime($eventFirstRepetition->start_repeat)) : '';
163
        $dateTime['timeStartMinutes'] = (isset($eventFirstRepetition->start_repeat)) ? date('i', strtotime($eventFirstRepetition->start_repeat)) : '';
164
        $dateTime['timeStartAmpm'] = (isset($eventFirstRepetition->start_repeat)) ? date('A', strtotime($eventFirstRepetition->start_repeat)) : '';
165
        $dateTime['timeEndHours'] = (isset($eventFirstRepetition->end_repeat)) ? date('g', strtotime($eventFirstRepetition->end_repeat)) : '';
166
        $dateTime['timeEndMinutes'] = (isset($eventFirstRepetition->end_repeat)) ? date('i', strtotime($eventFirstRepetition->end_repeat)) : '';
167
        $dateTime['timeEndAmpm'] = (isset($eventFirstRepetition->end_repeat)) ? date('A', strtotime($eventFirstRepetition->end_repeat)) : '';
168
169
        $dateTime['repeatUntil'] = is_null($event->repeat_until) ? null : date('d/m/Y', strtotime($event->repeat_until));
170 1
        $dateTime['multipleDates'] = $event->multiple_dates;
171
172 1
        return $dateTime;
173 1
    }
174 1
175 1
    /**
176
     * Return the HTML of the monthly select dropdown - inspired by - https://www.theindychannel.com/calendar
177
     * - Used by the AJAX in the event repeat view -
178
     * - The HTML contain a <select></select> with four <options></options>.
179 1
     *
180 1
     * @param string $date
181
     *
182 1
     * @return string
183 1
     */
184
    public function getMonthlySelectOptions(string $date): string
185 1
    {
186 1
        $monthlySelectOptions = [];
187 1
        $date = implode('-', array_reverse(explode('/', $date)));  // Our YYYY-MM-DD date string
188
        $unixTimestamp = strtotime($date);  // Convert the date string into a unix timestamp.
189
        $dayOfWeekString = date('l', $unixTimestamp); // Monday | Tuesday | Wednesday | ..
190
191
        // Add option: Same day number.
192 1
        // eg. "the 28th day of the month"
193 1
        $dateArray = explode('-', $date);
194
        $dayNumber = ltrim($dateArray[2], '0'); // remove the 0 in front of a day number eg. 02/10/2018
195 1
196 1
        $format = __('ordinalDays.the_' . ($dayNumber) . '_x_of_the_month');
197
        $repeatText = sprintf($format, 'day');
0 ignored issues
show
Bug introduced by
It seems like $format can also be of type array and array; however, parameter $format of sprintf() does only seem to accept string, 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

197
        $repeatText = sprintf(/** @scrutinizer ignore-type */ $format, 'day');
Loading history...
198 1
199 1
        array_push($monthlySelectOptions, [
200 1
            'value' => '0|' . $dayNumber,
201
            'text' => $repeatText,
202
        ]);
203
204
        // Add option: Same weekday/week of the month.
205 1
        // eg. the "1st Monday" 1|1|1 (first week, monday)
206
        $dayOfWeekValue = date('N', $unixTimestamp); // 1 (for Monday) through 7 (for Sunday)
207 1
        $weekOfTheMonth = DateHelpers::monthWeekNumber($date, $dayOfWeekValue); // 1 | 2 | 3 | 4 | 5
208 1
209
        $format = __('ordinalDays.the_' . ($weekOfTheMonth) . '_x_of_the_month');
210 1
        $repeatText = sprintf($format, $dayOfWeekString);
211 1
212 1
        array_push($monthlySelectOptions, [
213
            'value' => '1|' . $weekOfTheMonth . '|' . $dayOfWeekValue,
214
            'text' => $repeatText,
215
        ]);
216
217 1
        // Add option: Same day of the month (from the end).
218
        // eg. "the 3rd to last day of the month" (0 if last day, 1 if 2nd to last day, , 2 if 3rd to last day)
219 1
        $dayOfMonthFromTheEnd = DateHelpers::dayOfMonthFromTheEnd($unixTimestamp); // 1 | 2 | 3 | 4 | 5
220
221
        $format = __('ordinalDays.the_'.($dayOfMonthFromTheEnd + 1).'_to_last_x_of_the_month');
222 1
        $repeatText = sprintf($format, 'day');
223
224
        array_push($monthlySelectOptions, [
225 1
            'value' => '2|'.$dayOfMonthFromTheEnd,
226 1
            'text' => $repeatText,
227
        ]);
228 1
229 1
        // Add option: Same weekday/week of the month (from the end).
230 1
        // eg. the last Friday - (0 if last Friday, 1 if the 2nd to last Friday, 2 if the 3nd to last Friday)
231
        $monthWeekNumberFromTheEnd = DateHelpers::monthWeekNumberFromTheEnd($unixTimestamp); // 1 | 2 | 3 | 4 | 5
232
233
        if ($monthWeekNumberFromTheEnd == 1) {
234 1
            $weekValue = 0;
235 1
        } else {
236 1
            $weekValue = $monthWeekNumberFromTheEnd - 1;
237 1
        }
238
239 1
        $format = __('ordinalDays.the_' . ($monthWeekNumberFromTheEnd) . '_to_last_x_of_the_month');
240
        $repeatText = sprintf($format, $dayOfWeekString);
241 1
242
        array_push($monthlySelectOptions, [
243
            'value' => '3|' . $weekValue . '|' . $dayOfWeekValue,
244
            'text' => $repeatText,
245
        ]);
246
247
        // GENERATE the HTML to return
248
        $selectTitle = __('general.select_repeat_monthly_kind');
249
        $onMonthlyKindSelect = "<select name='on_monthly_kind' id='on_monthly_kind' class='selectpicker' title='".$selectTitle."'>";
0 ignored issues
show
Bug introduced by
Are you sure $selectTitle of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

249
        $onMonthlyKindSelect = "<select name='on_monthly_kind' id='on_monthly_kind' class='selectpicker' title='"./** @scrutinizer ignore-type */ $selectTitle."'>";
Loading history...
250
        foreach ($monthlySelectOptions as $key => $monthlySelectOption) {
251
            $onMonthlyKindSelect .= "<option value='".$monthlySelectOption['value']."'>".$monthlySelectOption['text'].'</option>';
252 4
        }
253
        $onMonthlyKindSelect .= '</select>';
254 4
255
        return $onMonthlyKindSelect;
256 4
    }
257 4
258 1
    /**
259 3
     * Return a string that describe repetition kind in the event show view.
260 1
     *
261
     * @param \App\Models\Event $event
262
     * @param \App\Models\EventRepetition $firstRpDates
263 1
     *
264
     * @return string $ret
265 1
     * @throws \Exception
266 1
     */
267 1
    public static function getRepetitionTextString(Event $event, EventRepetition $firstRpDates): string
268
    {
269
        $ret = '';
270 1
271
        switch ($event->repeat_type) {
272
            case '1': // noRepeat
273 1
                $dateStart = date('d/m/Y', strtotime($firstRpDates->start_repeat));
274 1
                $dateEnd = date('d/m/Y', strtotime($firstRpDates->end_repeat));
275 1
276 2
                if ($dateStart == $dateEnd) {
277 1
                    $ret = $dateStart;
278 1
                } else {
279
                    $ret = "From {$dateStart} to {$dateEnd}";
280
                }
281 1
                break;
282 1
            case '2': // repeatWeekly
283 1
                $repeatUntil = new DateTime($event->repeat_until);
284 1
285 1
                // Get the name of the weekly day when the event repeat, if two days, return like "Thursday and Sunday"
286 1
                $repetitonWeekdayNumbersArray = explode(',', $event->repeat_weekly_on);
287
288
                $repetitonWeekdayNamesArray = [];
289 1
                foreach ($repetitonWeekdayNumbersArray as $key => $repetitonWeekdayNumber) {
290 1
                    $repetitonWeekdayNamesArray[] = DateHelpers::decodeRepeatWeeklyOn($repetitonWeekdayNumber);
291 1
                }
292
                // create from an array a string with all the values divided by " and "
293 1
                $nameOfTheRepetitionWeekDays = implode(' and ', $repetitonWeekdayNamesArray);
294 1
295
                //$ret = 'The event happens every '.$nameOfTheRepetitionWeekDays.' until '.$repeatUntil->format('d/m/Y');
296 1
                $format = __('event.the_event_happens_every_x_until_x');
297 1
                $ret .= sprintf($format, $nameOfTheRepetitionWeekDays, $repeatUntil->format('d/m/Y'));
0 ignored issues
show
Bug introduced by
It seems like $format can also be of type array and array; however, parameter $format of sprintf() does only seem to accept string, 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

297
                $ret .= sprintf(/** @scrutinizer ignore-type */ $format, $nameOfTheRepetitionWeekDays, $repeatUntil->format('d/m/Y'));
Loading history...
298 1
                break;
299 1
            case '3': //repeatMonthly
300
                $repeatUntil = new DateTime($event->repeat_until);
301
                $repetitionFrequency = self::decodeOnMonthlyKind($event->on_monthly_kind);
302 4
303
                //$ret = 'The event happens '.$repetitionFrequency.' until '.$repeatUntil->format('d/m/Y');
304
                $format = __('event.the_event_happens_x_until_x');
305
                $ret .= sprintf($format, $repetitionFrequency, $repeatUntil->format('d/m/Y'));
306
                break;
307
            case '4': //repeatMultipleDays
308
                $dateStart = date('d/m/Y', strtotime($firstRpDates->start_repeat));
309
                $singleDaysRepeatDatas = explode(',', $event->multiple_dates);
310
311 1
                // Sort the datas
312
                usort($singleDaysRepeatDatas, function ($a, $b) {
313 1
                    $a = Carbon::createFromFormat('d/m/Y', $a);
314
                    $b = Carbon::createFromFormat('d/m/Y', $b);
315 1
316 1
                    return strtotime($a) - strtotime($b);
0 ignored issues
show
Bug introduced by
It seems like $a can also be of type false; however, parameter $datetime of strtotime() does only seem to accept string, 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

316
                    return strtotime(/** @scrutinizer ignore-type */ $a) - strtotime($b);
Loading history...
317 1
                });
318
319
                $ret .= __('event.the_event_happens_on_this_dates');
320
                $ret .= $dateStart . ', ';
321
                $ret .= Helper::getStringFromArraySeparatedByComma($singleDaysRepeatDatas);
322
                break;
323
        }
324
325
        return $ret;
326
    }
327
328
    /**
329 1
     * Return a string that describe the report misuse reason.
330
     *
331
     * @param  int $reason
332
     * @return string $ret
333
     */
334
    public static function getReportMisuseReasonDescription(int $reason): string
335
    {
336
        $ret = '';
337
        switch ($reason) {
338
            case '1':
339 5
                $ret = 'Not about Contact Improvisation';
340
                break;
341 5
            case '2':
342 5
                $ret = 'Contains wrong information';
343
                break;
344 5
            case '3':
345 5
                $ret = 'It is not translated in english';
346 5
                break;
347 5
            case '4':
348 5
                $ret = 'Other (specify in the message)';
349 5
                break;
350 5
        }
351 5
352
        return $ret;
353
    }
354
355 5
    /**
356 5
     * Decode the event on_monthly_kind field - used in event.show.
357 1
     * Return a string like "the 4th to last Thursday of the month".
358 1
     *
359 1
     * @param  string $onMonthlyKindCode
360 1
     * @return string
361 4
     */
362 2
    public static function decodeOnMonthlyKind(string $onMonthlyKindCode): string
363 2
    {
364 2
        $ret = '';
365 2
        $onMonthlyKindCodeArray = explode('|', $onMonthlyKindCode);
366 2
        $weekDays = [
367 2
            '',
368 1
            __('general.monday'),
369 1
            __('general.tuesday'),
370 1
            __('general.wednesday'),
371 1
            __('general.thursday'),
372 1
            __('general.friday'),
373 1
            __('general.saturday'),
374 1
            __('general.sunday'),
375 1
        ];
376 1
377 1
        switch ($onMonthlyKindCodeArray[0]) {
378
            case '0':  // 0|7 eg. the 7th day of the month
379
                $dayNumber = $onMonthlyKindCodeArray[1];
380 5
                $format = __("ordinalDays.the_{$dayNumber}_x_of_the_month");
381
                $ret = sprintf($format, __('general.day'));
0 ignored issues
show
Bug introduced by
It seems like __('general.day') can also be of type array and array; however, parameter $values of sprintf() does only seem to accept double|integer|string, 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

381
                $ret = sprintf($format, /** @scrutinizer ignore-type */ __('general.day'));
Loading history...
Bug introduced by
It seems like $format can also be of type array and array; however, parameter $format of sprintf() does only seem to accept string, 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

381
                $ret = sprintf(/** @scrutinizer ignore-type */ $format, __('general.day'));
Loading history...
382
                break;
383
            case '1':  // 1|2|4 eg. the 2nd Thursday of the month
384
                $dayNumber = $onMonthlyKindCodeArray[1];
385
                $weekDay = $weekDays[$onMonthlyKindCodeArray[2]]; // Monday, Tuesday, Wednesday
386
                $format = __("ordinalDays.the_{$dayNumber}_x_of_the_month");
387
                $ret = sprintf($format, $weekDay);
388
                break;
389
            case '2': // 2|20 eg. the 21st to last day of the month
390
                $dayNumber = (int) $onMonthlyKindCodeArray[1] + 1;
391
                $format = __("ordinalDays.the_{$dayNumber}_to_last_x_of_the_month");
392
                $ret = sprintf($format, __('general.day'));
393
                break;
394
            case '3': // 3|3|4 eg. the 4th to last Thursday of the month
395
                $dayNumber = (int) $onMonthlyKindCodeArray[1] + 1;
396
                $weekDay = $weekDays[$onMonthlyKindCodeArray[2]]; // Monday, Tuesday, Wednesday
397
                $format = __("ordinalDays.the_{$dayNumber}_to_last_x_of_the_month");
398
                $ret = sprintf($format, $weekDay);
399
                break;
400
        }
401
402
        return $ret;
403
    }
404
405
    /**
406
     * Return the list of the expiring repetitive events (the 7th day from now).
407
     * When the cache parameter is true, get them from the cache.
408
     *
409
     * The cache tag get invalidated once a day and also on event save, update and delete.
410
     * Using the function cleanActiveEventsCaches()
411
     * To empty the cache you can run a 'php artisan cache:clear'
412
     *
413
     * @param bool $cached
414
     *
415
     * @return Collection
416
     */
417
    public function getRepetitiveEventsExpiringInOneWeek(bool $cached): Collection
418
    {
419
        if (!$cached) {
420
            return $this->eventRepository->getRepetitiveExpiringInOneWeek();
0 ignored issues
show
Bug introduced by
The method getRepetitiveExpiringInOneWeek() does not exist on App\Repositories\EventRepositoryInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to App\Repositories\EventRepositoryInterface. ( Ignorable by Annotation )

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

420
            return $this->eventRepository->/** @scrutinizer ignore-call */ getRepetitiveExpiringInOneWeek();
Loading history...
421
        }
422
423
        $cacheTag = 'active_events';
424
        $seconds = 86400; // One day
425
        return Cache::remember($cacheTag, $seconds, function () {
426
            return $this->eventRepository->getRepetitiveExpiringInOneWeek();
427
        });
428
    }
429
430
    /**
431
     * Send an email to the users which repetitive events are expiring.
432
     *
433
     * @return string
434
     */
435
    public function sendEmailToExpiringEventsOrganizers(): string
436
    {
437
        $data = [];
438
        $data['emailFrom'] = env('ADMIN_MAIL');
439
        $data['senderName'] = 'CI Global Calendar Administrator';
440
441
        $expiringRepetitiveEvents = self::getRepetitiveEventsExpiringInOneWeek(true);
0 ignored issues
show
Bug Best Practice introduced by
The method App\Services\EventServic...entsExpiringInOneWeek() is not static, but was called statically. ( Ignorable by Annotation )

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

441
        /** @scrutinizer ignore-call */ 
442
        $expiringRepetitiveEvents = self::getRepetitiveEventsExpiringInOneWeek(true);
Loading history...
442
        foreach ($expiringRepetitiveEvents as $key => $event) {
443
            $this->notificationService->sendEmailExpiringEvent($data, $event);
444
        }
445
446
        $message = $expiringRepetitiveEvents->isEmpty() ?
447
            'No events were expiring'
448
            : count($expiringRepetitiveEvents) . ' events were expiring, mails sent to the organizers.';
449
450
        Log::notice($message);
451
        return $message;
452
    }
453
454
    /**
455
     * Invalidate the cache tags related to active events.
456
     *
457
     * @return void
458
     */
459
    public function cleanActiveEventsCaches(): void
460
    {
461
        Cache::forget('active_events');
462
        //Cache::forget('active_events_map_markers_json');
463
        //Cache::forget('active_events_map_markers_db_data');
464
    }
465
466
467
468
}
469