├── .gitignore
├── .travis.yml
├── README.md
├── composer.json
├── phpmd.xml
├── phpunit.xml
├── src
├── Console
│ └── Commands
│ │ └── GenerateCalendarEvent.php
├── Enums
│ └── RecurringFrequenceType.php
├── Exceptions
│ └── CalendarEventException.php
├── Interfaces
│ ├── CalendarEventInterface.php
│ ├── PlaceInterface.php
│ ├── TemplateCalendarEventInterface.php
│ └── UserInterface.php
├── Models
│ ├── AbstractModel.php
│ ├── CalendarEvent.php
│ └── TemplateCalendarEvent.php
├── ServiceProvider.php
├── Support
│ └── helpers.php
├── Traits
│ ├── CalendarEventPlaceTrait.php
│ └── CalendarEventUserTrait.php
├── config
│ └── calendar-event.php
└── database
│ ├── factories
│ ├── CalendarEventFactory.php
│ └── TemplateCalendarEventFactory.php
│ └── migrations
│ ├── 2017_08_22_082938_create_template_calendar_events_table.php
│ └── 2017_08_22_093248_create_calendar_events_table.php
└── tests
├── TestCase.php
├── Unit
├── Console
│ └── Command
│ │ └── GenerateCalendarEventTest.php
├── Models
│ ├── CalendarEventTest.php
│ └── TemplateCalendarEventTest.php
├── Traits
│ ├── CalendarEventPlaceTraitTest.php
│ └── CalendarEventUserTraitTest.php
└── config
│ └── ConfigTest.php
└── fixtures
├── Models
├── Place.php
└── User.php
└── database
├── factories
├── PlaceFactory.php
└── UserFactory.php
└── migrations
├── 2017_09_08_064317_create_places_table.php
└── 2017_09_08_064448_create_users_table.php
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 |
3 | build
4 | vendor
5 | composer.lock
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 7.1
5 |
6 | before_install:
7 | - travis_retry composer self-update
8 |
9 | install:
10 | - travis_retry composer install --no-interaction --prefer-dist
11 |
12 | script:
13 | - vendor/bin/phpunit --verbose
14 | - vendor/bin/phpmd src text phpmd.xml --exclude src/database
15 |
16 | after_success:
17 | - bash <(curl -s https://codecov.io/bash)
18 |
19 | matrix:
20 | fast_finish: true
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Laravel Calendar Event
2 |
3 | [](https://packagist.org/packages/t1k3/laravel-calendar-event)
4 | [](https://packagist.org/packages/t1k3/laravel-calendar-event)
5 | [](https://packagist.org/packages/t1k3/laravel-calendar-event)
6 | [](https://travis-ci.org/t1k3/laravel-calendar-event)
7 | [](https://codecov.io/gh/t1k3/laravel-calendar-event)
8 | [](https://codeclimate.com/github/t1k3/laravel-calendar-event/maintainability)
9 |
10 | ## Installation
11 | ```bash
12 | composer require t1k3/laravel-calendar-event
13 | ```
14 |
15 | After updating composer, add the ServiceProvider to the providers array in `config/app.php`
16 | ```php
17 | T1k3\LaravelCalendarEvent\ServiceProvider::class,
18 | ```
19 |
20 | You need publish to the config.
21 | ```bash
22 | php artisan vendor:publish --provider="T1k3\LaravelCalendarEvent\ServiceProvider"
23 | ```
24 |
25 | You need to run the migrations for this package.
26 | ```bash
27 | php artisan migrate
28 | ```
29 |
30 | ## Usage
31 |
32 | #### Recurring options
33 | - DAY
34 | - WEEK
35 | - MONTH
36 | - YEAR
37 | - NTHWEEKDAY: nth weekday per month, example 2nd Monday
38 |
39 | #### Create CalendarEvent
40 | If you like to attach `User` and/or `Place` then must have:
41 | * configurate `config/calendar-event.php`
42 | * implements `UserInterface`, `PlaceInterface` on your Models
43 | * you can use `CalendarEventUserTrait`, `CalendarEventPlaceTrait` in Models
44 |
45 | ```php
46 | use T1k3\LaravelCalendarEvent\Interfaces\PlaceInterface;
47 | use T1k3\LaravelCalendarEvent\Traits\CalendarEventPlaceTrait;
48 |
49 | class Place extends Model implements PlaceInterface
50 | {
51 | use CalendarEventPlaceTrait;
52 | }
53 | ```
54 |
55 | ```php
56 | use T1k3\LaravelCalendarEvent\Models\CalendarEvent;
57 | use T1k3\LaravelCalendarEvent\Enums\RecurringFrequenceType;
58 |
59 | $calendarEvent = new CalendarEvent();
60 | $calendarEvent = $calendarEvent->createCalendarEvent([
61 | 'title' => 'Lorem ipsum',
62 | 'start_datetime' => Carbon::parse('2017-08-25 16:00:00'),
63 | 'end_datetime' => Carbon::parse('2017-08-25 17:30:00'),
64 | 'description' => 'Lorem ipsum dolor sit amet',
65 | 'is_recurring' => true,
66 | 'frequence_number_of_recurring' => 1,
67 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
68 | 'is_public' => true,
69 | 'end_of_recurring' => Carbon::parse('2017-09-08')
70 | ], $user = null, $place = null);
71 | ```
72 |
73 | #### Edit and Update CalendarEvent
74 | ```php
75 | $calendarEvent = CalendarEvent::find($id);
76 | $calendarEventUpdated = $calendarEvent->editCalendarEvent([
77 | 'start_datetime' => Carbon::parse('2017-08-26'),
78 | 'is_recurring' => false,
79 | ], $user = null, $place = null);
80 |
81 | // $calendarEventUpdated === null ? dd('NOT_MODIFIED') : dd('MODIFIED', $calendarEventUpdated);
82 | ```
83 |
84 | #### Update CalendarEvent (without data check)
85 | ```php
86 | $calendarEvent = CalendarEvent::find($id);
87 | $calendarEventUpdated = $calendarEvent->updateCalendarEvent([
88 | 'start_datetime' => Carbon::parse('2017-08-26'),
89 | 'is_recurring' => false,
90 | ], $user = null, $place = null);
91 | ```
92 |
93 | #### Delete CalendarEvent
94 | ```php
95 | $calendarEvent = CalendarEvent::find($id);
96 | $isDeleted = $calendarEvent->deleteCalendarEvent($isRecurring = null);
97 | ```
98 |
99 | #### Edit and Update not existing CalendarEvent
100 | ```php
101 | use T1k3\LaravelCalendarEvent\Models\TemplateCalendarEvent;
102 |
103 | $templateCalendarEvent = TemplateCalendarEvent::find($id);
104 | $calendarEventUpdated = $templateCalendarEvent->editCalendarEvent(Carbon::parse('2017-08-30'), [
105 | 'description' => 'Foo Bar'
106 | ], $user = null, $place = null);
107 |
108 | // $calendarEventUpdated === null ? dd('NOT_MODIFIED') : dd('MODIFIED', $calendarEventUpdated);
109 | ```
110 |
111 | #### Update not existing CalendarEvent (without data check)
112 | ```php
113 | use T1k3\LaravelCalendarEvent\Models\TemplateCalendarEvent;
114 |
115 | $templateCalendarEvent = TemplateCalendarEvent::find($id);
116 | $calendarEventUpdated = $templateCalendarEvent->updateCalendarEvent(Carbon::parse('2017-08-30'), [
117 | 'description' => 'Foo Bar'
118 | ], $user = null, $place = null);
119 | ```
120 |
121 | #### Delete not existing CalendarEvent
122 | ```php
123 | $templateCalendarEvent = TemplateCalendarEvent::find($id);
124 | $isDeleted = $templateCalendarEvent->deleteCalendarEvent(Carbon::parse('2017-08-30'), $isRecurring = null);
125 | ```
126 |
127 | #### Get (potential) CalendarEvent(s) of month
128 | If the CalendarEvent is not exist then it is append `is_not_exists` attribute with `true` value
129 | ```php
130 | $calendarEvents = CalendarEvent::showPotentialCalendarEventsOfMonth(Carbon::parse('2017-08'));
131 | ```
132 |
133 | #### Generate next CalendarEvent(s) from Console
134 | Do NOT forget the [Laravel Task Scheduling](https://laravel.com/docs/master/scheduling)
135 | - The command run at hourly in schedule
136 | ```bash
137 | * * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1
138 | # OR manually
139 | php artisan generate:calendar-event
140 | ```
141 |
142 | ### Validation
143 | Do NOT forget the [validation](https://laravel.com/docs/master/validation)
144 | - start_datetime
145 | - end_datetime
146 |
147 | ### How to upgrade Carbon
148 | ```bash
149 | $ docker run -it --rm -v $PWD:/app -w /app epcallan/php7-testing-phpunit:7.2-phpunit7 bash
150 | $ composer install
151 | $ ./vendor/bin/upgrade-carbon
152 | ```
153 |
154 | ### How to Testing
155 | ```bash
156 | $ docker run -it --rm -v $PWD:/app -w /app epcallan/php7-testing-phpunit:7.2-phpunit7 bash
157 | $ composer install
158 | $ ./vendor/bin/phpunit
159 | ```
160 |
161 | ### TODO
162 | - [ ] OCP
163 | - [ ] Name conventions, example: `TemplateCalendarEvent::events()` to `TemplateCalendarEvent::calendarEvents()`
164 | - [ ] [Custom validation rule](https://laravel.com/docs/master/validation#custom-validation-rules) to date/time diff
165 |
166 | ### Special thanks
167 | - [Bit and Pixel](https://bitandpixel.hu)
168 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "t1k3/laravel-calendar-event",
3 | "description": "Laravel Calendar Event",
4 | "keywords": [
5 | "laravel-calendar-event",
6 | "laravel",
7 | "calendar",
8 | "event"
9 | ],
10 | "license": "MIT",
11 | "minimum-stability": "dev",
12 | "prefer-stable": true,
13 | "require": {
14 | "php": ">=7.1.3",
15 | "illuminate/database": "~5",
16 | "illuminate/support": "~5"
17 | },
18 | "require-dev": {
19 | "mockery/mockery": "^1.1",
20 | "orchestra/testbench": "~3.0|~3.6|~3.7|~3.8",
21 | "phpmd/phpmd": "^2.6",
22 | "phpunit/phpunit": "^7.3",
23 | "composer/composer": "^1.9"
24 | },
25 | "autoload": {
26 | "classmap": [
27 | "src/database"
28 | ],
29 | "psr-4": {
30 | "T1k3\\LaravelCalendarEvent\\": "src"
31 | }
32 | },
33 | "autoload-dev": {
34 | "psr-4": {
35 | "T1k3\\LaravelCalendarEvent\\Tests\\": "tests",
36 | "T1k3\\LaravelCalendarEvent\\Tests\\Fixtures\\": "tests/fixtures"
37 | }
38 | },
39 | "extra": {
40 | "laravel": {
41 | "providers": [
42 | "T1k3\\LaravelCalendarEvent\\ServiceProvider"
43 | ]
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/phpmd.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 | Laravel Calendar Event Code Check
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 | tests/Unit
14 |
15 |
16 |
17 |
18 | src
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/Console/Commands/GenerateCalendarEvent.php:
--------------------------------------------------------------------------------
1 | templateCalendarEvent = $templateCalendarEvent;
46 | }
47 |
48 | /**
49 | * Handle
50 | */
51 | public function handle()
52 | {
53 | $date = $this->option('date') ? Carbon::parse($this->option('date')) : Carbon::now();
54 | $templateCalendarEvents = $this->templateCalendarEvent
55 | ->where('is_recurring', true)
56 | ->where(function ($q) use ($date) {
57 | $q->whereNull('end_of_recurring')
58 | ->orWhere('end_of_recurring', '>=', $date);
59 | })
60 | ->get();
61 |
62 | $count = 0;
63 | foreach ($templateCalendarEvents as $templateCalendarEvent) {
64 | $dateNext = null;
65 | $endOfRecurring = (clone $date)->addWeek();
66 | // TODO Refactor: OCP, Strategy
67 | switch ($templateCalendarEvent->frequence_type_of_recurring) {
68 | case RecurringFrequenceType::DAY:
69 | $startDateTime = $templateCalendarEvent->start_datetime;
70 | $endOfRecurring = (clone $date)->hour($startDateTime->hour)->minute($startDateTime->minute)->second($startDateTime->second);
71 | $diff = $templateCalendarEvent->start_datetime->diffInDays($endOfRecurring);
72 | $dateNext = $templateCalendarEvent->start_datetime->addDays($diff);
73 |
74 | if ($templateCalendarEvent->start_datetime->diffInDays($dateNext) % (int)$templateCalendarEvent->frequence_number_of_recurring === 0) {
75 | $dateNext->addDays((int)$templateCalendarEvent->frequence_number_of_recurring - 1);
76 | $endOfRecurring->addDays((int)$templateCalendarEvent->frequence_number_of_recurring - 1);
77 | }
78 | break;
79 | case RecurringFrequenceType::WEEK:
80 | // $endOfRecurring = (clone $date)->addWeek();
81 | $diff = $templateCalendarEvent->start_datetime->diffInWeeks($endOfRecurring);
82 | $dateNext = $templateCalendarEvent->start_datetime->addWeeks($diff);
83 | break;
84 | case RecurringFrequenceType::MONTH:
85 | // $endOfRecurring = (clone $date)->addMonth();
86 | $diff = $templateCalendarEvent->start_datetime->diffInMonths($endOfRecurring);
87 | $dateNext = $templateCalendarEvent->start_datetime->addMonths($diff);
88 | break;
89 | case RecurringFrequenceType::YEAR:
90 | $startDateTime = $templateCalendarEvent->start_datetime;
91 | $endOfRecurring = (clone $date)->addYear()->hour($startDateTime->hour)->minute($startDateTime->minute)->second($startDateTime->second);
92 | $diff = $templateCalendarEvent->start_datetime->diffInYears($endOfRecurring);
93 | $dateNext = $templateCalendarEvent->start_datetime->addYears($diff);
94 | break;
95 | case RecurringFrequenceType::NTHWEEKDAY:
96 | $diff = $date->firstOfMonth()->diffInMonths($templateCalendarEvent->start_datetime);
97 |
98 | $nextMonth = $templateCalendarEvent->start_datetime->addMonths($diff);
99 | $weekdays = getWeekdaysInMonth(
100 | $templateCalendarEvent->start_datetime->format('l'),
101 | $nextMonth
102 | );
103 |
104 | $dateNext = $weekdays[$templateCalendarEvent->start_datetime->weekOfMonth - 1];
105 | }
106 |
107 | if ($dateNext !== null
108 | && ($templateCalendarEvent->end_of_recurring === null
109 | || $dateNext <= $templateCalendarEvent->end_of_recurring
110 | )
111 | && $dateNext >= $date
112 | && $dateNext <= $endOfRecurring
113 | && !$templateCalendarEvent->events()->withTrashed()->where('start_datetime', $dateNext)->first()
114 | ) {
115 | $calendarEvent = $templateCalendarEvent->createCalendarEvent($dateNext);
116 | $count++;
117 |
118 | $this->closure($calendarEvent);
119 |
120 | Log::info(
121 | sprintf('
122 | Generated CalendarEvent from Console:
123 | template_calendar_event_id: %s,
124 | calendar_event_id: %s,
125 | start_datetime: %s,
126 | end_datetime: %s',
127 | $calendarEvent->template_calendar_event_id,
128 | $calendarEvent->id,
129 | $calendarEvent->start_datetime->format('Y-m-d'),
130 | $calendarEvent->end_datetime->format('Y-m-d')
131 | )
132 | );
133 | }
134 | }
135 |
136 | $this->info(sprintf('Generated CalendarEvent from Console | Summary: %s.', $count));
137 | }
138 |
139 | /**
140 | * TODO Name convention: callback()
141 | * Callback for calendar event created
142 | * @param CalendarEventInterface $calendarEvent
143 | * @return CalendarEventInterface
144 | */
145 | protected function closure(CalendarEventInterface $calendarEvent)
146 | {
147 | return $calendarEvent;
148 | }
149 | }
--------------------------------------------------------------------------------
/src/Enums/RecurringFrequenceType.php:
--------------------------------------------------------------------------------
1 | where('is_public', true);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Models/CalendarEvent.php:
--------------------------------------------------------------------------------
1 | 'datetime',
36 | 'end_datetime' => 'datetime',
37 | ];
38 |
39 | /**
40 | * TemplateCalendarEvent
41 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
42 | */
43 | public function template()
44 | {
45 | return $this->belongsTo(TemplateCalendarEvent::class, 'template_calendar_event_id');
46 | }
47 |
48 | /**
49 | * Calendar event (template) data - input is different
50 | * @param array $attributes
51 | * @return bool
52 | */
53 | public function dataIsDifferent(array $attributes): bool
54 | {
55 | if (isset($attributes['start_datetime'])) {
56 | // CalendarEvent data check
57 | if ($this->start_datetime->format('Y-m-d') !== $attributes['start_datetime']->format('Y-m-d')) {
58 | return true;
59 | }
60 | unset($attributes['start_datetime']);
61 | }
62 |
63 | // TemplateCalendarEvent data check | Skip start_datetime from template
64 | return !arrayIsEqualWithDB($attributes, $this->template, ['start_datetime']);
65 | }
66 |
67 | /**
68 | * Create CalendarEvent with Template, User, Place
69 | * @param array $attributes
70 | * @param UserInterface|null $user
71 | * @param PlaceInterface|null $place
72 | * @return \Illuminate\Database\Eloquent\Model
73 | */
74 | public function createCalendarEvent(array $attributes, UserInterface $user = null, PlaceInterface $place = null)
75 | {
76 | DB::transaction(function () use ($attributes, $user, $place, &$calendarEvent) {
77 | $templateCalendarEvent = $this->template()->make($attributes);
78 |
79 | if ($templateCalendarEvent->user() !== null && $user !== null) {
80 | $templateCalendarEvent->user()->associate($user);
81 | }
82 | if ($templateCalendarEvent->place() !== null && $place !== null) {
83 | $templateCalendarEvent->place()->associate($place);
84 | }
85 |
86 | $templateCalendarEvent->save();
87 |
88 | $calendarEvent = $this->make($attributes);
89 | $calendarEvent->template()->associate($templateCalendarEvent);
90 | $calendarEvent->save();
91 | });
92 |
93 | return $calendarEvent;
94 | }
95 |
96 | /**
97 | * Update CalendarEvent
98 | * @param array $attributes
99 | * @param UserInterface|null $user
100 | * @param PlaceInterface|null $place
101 | * @return mixed
102 | */
103 | public function updateCalendarEvent(array $attributes, UserInterface $user = null, PlaceInterface $place = null)
104 | {
105 | DB::transaction(function () use ($attributes, $user, $place, &$calendarEventNew) {
106 | $calendarEventNew = $this->createCalendarEvent(
107 | array_merge(
108 | $this->template->toArray(),
109 | [
110 | 'start_datetime' => $this->start_datetime,
111 | 'end_datetime' => $this->end_datetime,
112 | ],
113 | $attributes
114 | ),
115 | $user,
116 | $place
117 | );
118 |
119 | $templateCalendarEvent = $calendarEventNew->template->parent()->associate($this->template);
120 | $templateCalendarEvent->save();
121 |
122 | if ($this->template->is_recurring && $calendarEventNew->template->is_recurring) {
123 | $this->template->update([
124 | 'end_of_recurring' => $this->start_datetime,
125 | ]);
126 | } else {
127 | $calendarEventNew->template->update([
128 | 'end_of_recurring' => null,
129 | ]);
130 | }
131 | // $this->delete();
132 | $this->deleteCalendarEvent($this->template->is_recurring && $templateCalendarEvent->is_recurring);
133 | });
134 |
135 | return $calendarEventNew;
136 | }
137 |
138 | /**
139 | * Edit\Update calendar event with data check
140 | * @param array $attributes
141 | * @param UserInterface|null $user
142 | * @param PlaceInterface|null $place
143 | * @return null|CalendarEvent
144 | */
145 | public function editCalendarEvent(array $attributes, UserInterface $user = null, PlaceInterface $place = null)
146 | {
147 | if ($this->dataIsDifferent($attributes)
148 | || ($user ? $user->id : null) != $this->template->user_id
149 | || ($place ? $place->id : null) != $this->template->place_id
150 | ) {
151 | return $this->updateCalendarEvent($attributes, $user, $place);
152 | }
153 | return null;
154 | }
155 |
156 | /**
157 | * Delete calendar event
158 | * @param bool|null $isRecurring
159 | * @return bool|null
160 | */
161 | public function deleteCalendarEvent(bool $isRecurring = null)
162 | {
163 | DB::transaction(function () use ($isRecurring, &$isDeleted) {
164 | if ($isRecurring === null) {
165 | $isRecurring = $this->template->is_recurring;
166 | }
167 |
168 | if ($this->template->is_recurring && $isRecurring) {
169 | $this->template->update(['end_of_recurring' => $this->start_datetime]);
170 |
171 | $nextCalendarEvents = $this->template->events()->where('start_datetime', '>', $this->start_datetime)->get();
172 | foreach ($nextCalendarEvents as $nextCalendarEvent) {
173 | $nextCalendarEvent->delete();
174 | }
175 |
176 | if ($this->template->start_datetime == $this->start_datetime) {
177 | $this->template->delete();
178 | }
179 | }
180 |
181 | if (!$this->template->is_recurring) {
182 | $this->template->delete();
183 | }
184 |
185 | $isDeleted = $this->delete();
186 | });
187 | return $isDeleted;
188 | }
189 |
190 | /**
191 | * Show (potential) CalendarEvent of the month
192 | * @param \DateTimeInterface $date
193 | * @return Collection|static
194 | */
195 | public static function showPotentialCalendarEventsOfMonth(\DateTimeInterface $date)
196 | {
197 | $endOfRecurring = $date->lastOfMonth()->hour(23)->minute(59)->second(59);
198 | $month = str_pad($endOfRecurring->month, 2, '0', STR_PAD_LEFT);
199 | $templateCalendarEvents = self::getMonthlyEvents($endOfRecurring);
200 |
201 | $calendarEvents = collect();
202 | foreach ($templateCalendarEvents as $templateCalendarEvent) {
203 | $calendarEvents = $calendarEvents->merge(
204 | $templateCalendarEvent->events()->whereMonth('start_datetime', $month)->get()
205 | );
206 |
207 | $calendarEventTmpLast = $templateCalendarEvent->events()->orderBy('start_datetime', 'desc')->first();
208 | $dateNext = self::getNextDateFromTemplate($templateCalendarEvent, $calendarEventTmpLast, $date);
209 |
210 | while ($dateNext !== null && $dateNext->year == $date->year && $dateNext->month <= (int)$month) {
211 | $diffInDays = $templateCalendarEvent->start_datetime->diffInDays($templateCalendarEvent->end_datetime);
212 | $dateNextEnd = clone($dateNext);
213 | $dateNextEnd = $dateNextEnd->addDays($diffInDays);
214 |
215 | $calendarEventNotExists = (new CalendarEvent())->make([
216 | 'start_datetime' => $dateNext,
217 | 'end_datetime' => $dateNextEnd,
218 | ]);
219 | $calendarEventNotExists->is_not_exists = true;
220 | $calendarEventNotExists->template()->associate($templateCalendarEvent);
221 |
222 | if ($calendarEventNotExists->start_datetime->month === (int)$month && !$templateCalendarEvent->events()->where('start_datetime', $dateNext)->first()) {
223 | $calendarEvents = $calendarEvents->merge(collect([$calendarEventNotExists]));
224 | }
225 |
226 | $dateNext = $templateCalendarEvent->getNextCalendarEventStartDateTime($calendarEventNotExists->start_datetime);
227 | }
228 | }
229 |
230 | return $calendarEvents;
231 | }
232 |
233 | private static function getNextDateFromTemplate(TemplateCalendarEvent $templateCalendarEvent, CalendarEvent $calendarEventTmpLast, \DateTimeInterface $date)
234 | {
235 | $dateNext = null;
236 | // TODO Refactor: OCP, Strategy
237 | if ($calendarEventTmpLast) {
238 | switch ($templateCalendarEvent->frequence_type_of_recurring) {
239 | case RecurringFrequenceType::DAY:
240 | $diff = $calendarEventTmpLast->template->frequence_number_of_recurring;
241 | $dateNext = $calendarEventTmpLast->start_datetime->addDays($diff);
242 | break;
243 | case RecurringFrequenceType::WEEK:
244 | $diff = $date->firstOfMonth()->diffInWeeks($calendarEventTmpLast->start_datetime);
245 | $dateNext = $calendarEventTmpLast->start_datetime->addWeeks($diff);
246 | break;
247 | case RecurringFrequenceType::MONTH:
248 | $diff = $date->firstOfMonth()->diffInMonths($calendarEventTmpLast->start_datetime);
249 | $dateNext = $calendarEventTmpLast->start_datetime->addMonths($diff);
250 | break;
251 | case RecurringFrequenceType::YEAR:
252 | $diff = $date->firstOfMonth()->diffInYears($calendarEventTmpLast->start_datetime);
253 | $dateNext = $calendarEventTmpLast->start_datetime->addYears($diff);
254 | break;
255 | case RecurringFrequenceType::NTHWEEKDAY:
256 | $diff = $date->firstOfMonth()->diffInMonths($calendarEventTmpLast->start_datetime);
257 | $nextMonth = $calendarEventTmpLast->start_datetime->addMonths($diff);
258 |
259 | $weekdays = getWeekdaysInMonth(
260 | $calendarEventTmpLast->start_datetime->format('l'),
261 | $nextMonth
262 | );
263 | $dateNext = $weekdays[$calendarEventTmpLast->start_datetime->weekOfMonth - 1];
264 | break;
265 | }
266 | }
267 |
268 | return $dateNext;
269 | }
270 |
271 | private static function getMonthlyEvents(\DateTimeInterface $endOfRecurring): Collection
272 | {
273 | $month = str_pad($endOfRecurring->month, 2, '0', STR_PAD_LEFT);
274 |
275 | return TemplateCalendarEvent
276 | ::where(function ($q) use ($month) {
277 | $q->where('is_recurring', false)
278 | ->whereMonth('start_datetime', $month);
279 | })
280 | ->orWhere(function ($q) use ($endOfRecurring) {
281 | $q->where('is_recurring', true)
282 | ->whereNull('end_of_recurring')
283 | ->where('start_datetime', '<=', $endOfRecurring);
284 | })
285 | ->orWhere(function ($q) use ($endOfRecurring) {
286 | $q->where('is_recurring', true)
287 | ->where('end_of_recurring', '>=', $endOfRecurring)
288 | ->where('start_datetime', '<=', $endOfRecurring);
289 | })
290 | ->orWhere(function ($q) use ($endOfRecurring, $month) {
291 | $q->where('is_recurring', true)
292 | ->whereYear('end_of_recurring', $endOfRecurring->year)
293 | ->whereMonth('end_of_recurring', $month)
294 | ->where('start_datetime', '<=', $endOfRecurring);
295 | })
296 | ->with('events')
297 | ->get();
298 | }
299 | }
300 |
--------------------------------------------------------------------------------
/src/Models/TemplateCalendarEvent.php:
--------------------------------------------------------------------------------
1 | 'boolean',
44 | 'is_public' => 'boolean',
45 | 'start_datetime' => 'datetime',
46 | 'end_datetime' => 'datetime',
47 | 'end_of_recurring' => 'datetime',
48 | ];
49 |
50 | /**
51 | * TemplateCalendarEvent parent
52 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
53 | */
54 | public function parent()
55 | {
56 | return $this->belongsTo(TemplateCalendarEvent::class, 'parent_id');
57 | }
58 |
59 | /**
60 | * CalendarEvent
61 | * @return \Illuminate\Database\Eloquent\Relations\HasMany
62 | */
63 | public function events()
64 | {
65 | return $this->hasMany(CalendarEvent::class, 'template_calendar_event_id');
66 | }
67 |
68 | /**
69 | * @param $query
70 | * @return Builder
71 | */
72 | public function scopeRecurring($query)
73 | {
74 | return $query->where('is_recurring', true);
75 | }
76 |
77 | /**
78 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo|null
79 | */
80 | public function user()
81 | {
82 | // TODO If the config is null then you can not use ->user (LogicException), just ->user()
83 | $class = config('calendar-event.user.model');
84 | return $class ? $this->belongsTo($class) : null;
85 | }
86 |
87 | /**
88 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo|null
89 | */
90 | public function place()
91 | {
92 | // TODO If the config is null then you can not use ->place (LogicException), just ->place()
93 | $class = config('calendar-event.place.model');
94 | return $class ? $this->belongsTo($class) : null;
95 | }
96 |
97 | /**
98 | * Create Calendar Event for TemplateCalendarEvent
99 | * @param \DateTimeInterface $startDateTime
100 | * @return \Illuminate\Database\Eloquent\Model
101 | */
102 | public function createCalendarEvent(\DateTimeInterface $startDate)
103 | {
104 | $diffInSeconds = $this->start_datetime->diffInSeconds($this->end_datetime);
105 | $endDate = clone($startDate);
106 | $endDate = $endDate->addSeconds($diffInSeconds);
107 | $calendarEvent = $this->events()->make([
108 | 'start_datetime' => $startDate,
109 | 'end_datetime' => Carbon::parse( $endDate->format('Y-m-d') . ' ' . $this->end_datetime->format('H:i:s') ),
110 | ]);
111 |
112 | $calendarEvent->template()->associate($this);
113 | $calendarEvent->save();
114 |
115 | return $calendarEvent;
116 | }
117 |
118 | /**
119 | * Create or get calendar event
120 | * @param \DateTimeInterface $startDateTime
121 | * @return \Illuminate\Database\Eloquent\Model|null|static
122 | */
123 | public function createOrGetCalendarEvent(\DateTimeInterface $startDateTime)
124 | {
125 | $calendarEvent = $this->events()->where('start_datetime', $startDateTime)->first();
126 | if (!$calendarEvent) {
127 | $calendarEvent = $this->createCalendarEvent($startDateTime);
128 | }
129 |
130 | return $calendarEvent;
131 | }
132 |
133 | /**
134 | * Edit calendar event | Exist or not | Check data
135 | * @param \DateTimeInterface $startDateTime
136 | * @param array $attributes
137 | * @param UserInterface|null $user
138 | * @param PlaceInterface|null $place
139 | * @return null|CalendarEvent
140 | */
141 | public function editCalendarEvent(\DateTimeInterface $startDateTime, array $attributes, UserInterface $user = null, PlaceInterface $place = null)
142 | {
143 | $calendarEvent = $this->createOrGetCalendarEvent($startDateTime);
144 | return $calendarEvent->editCalendarEvent($attributes, $user, $place);
145 | }
146 |
147 | /**
148 | * Edit calendar event | Exist or not | Do not check data
149 | * @param \DateTimeInterface $startDateTime
150 | * @param array $attributes
151 | * @param UserInterface|null $user
152 | * @param PlaceInterface|null $place
153 | * @return mixed
154 | */
155 | public function updateCalendarEvent(\DateTimeInterface $startDateTime, array $attributes, UserInterface $user = null, PlaceInterface $place = null)
156 | {
157 | $calendarEvent = $this->createOrGetCalendarEvent($startDateTime);
158 | return $calendarEvent->updateCalendarEvent($attributes, $user, $place);
159 | }
160 |
161 | /**
162 | * Delete calendar event | Exist or not
163 | * @param \DateTimeInterface $startDateTime
164 | * @param bool|null $isRecurring
165 | * @return bool|null
166 | */
167 | public function deleteCalendarEvent(\DateTimeInterface $startDateTime, bool $isRecurring = null)
168 | {
169 | if ($isRecurring === null) $isRecurring = $this->is_recurring;
170 |
171 | $calendarEvent = $this->events()->where('start_datetime', $startDateTime)->first();
172 | if (!$calendarEvent) {
173 | $calendarEvent = $this->createCalendarEvent($startDateTime);
174 | }
175 |
176 | return $calendarEvent->deleteCalendarEvent($isRecurring);
177 | }
178 |
179 | /**
180 | * Generate next calendar event to template
181 | * @param \DateTimeInterface $now
182 | * @return \Illuminate\Database\Eloquent\Model|null
183 | */
184 | public function generateNextCalendarEvent(\DateTimeInterface $now)
185 | {
186 | if (!$this->is_recurring
187 | || ($this->end_of_recurring !== null
188 | && $this->end_of_recurring <= $now)
189 | ) {
190 | return null;
191 | }
192 |
193 | $calendarEvent = $this->events()->withTrashed()->orderBy('start_datetime', 'desc')->first();
194 | $startDateTime = $this->getNextCalendarEventStartDateTime($calendarEvent->start_datetime);
195 | if ($startDateTime === null) {
196 | return null;
197 | }
198 |
199 | return $this->createCalendarEvent($startDateTime);
200 | }
201 |
202 | /**
203 | * Get next calendar event start date
204 | * @param \DateTimeInterface $startDateTime
205 | * @return \DateTimeInterface|null
206 | */
207 | public function getNextCalendarEventStartDateTime(\DateTimeInterface $startDateTime)
208 | {
209 | if (!$this->is_recurring) {
210 | return null;
211 | }
212 |
213 | // TODO Refactor: OCP, Strategy
214 | switch ($this->frequence_type_of_recurring) {
215 | case RecurringFrequenceType::DAY:
216 | $startDateTime->addDays($this->frequence_number_of_recurring);
217 | break;
218 | case RecurringFrequenceType::WEEK:
219 | $startDateTime->addWeeks($this->frequence_number_of_recurring);
220 | break;
221 | case RecurringFrequenceType::MONTH:
222 | $startDateTime->addMonths($this->frequence_number_of_recurring);
223 | break;
224 | case RecurringFrequenceType::YEAR:
225 | $startDateTime->addYears($this->frequence_number_of_recurring);
226 | break;
227 | case RecurringFrequenceType::NTHWEEKDAY:
228 | $nextMonth = $startDateTime->copy()->addMonths($this->frequence_number_of_recurring);
229 | $weekdays = getWeekdaysInMonth(
230 | $startDateTime->format('l'),
231 | $nextMonth
232 | );
233 | $startDateTime = $weekdays[$startDateTime->weekOfMonth - 1];
234 | }
235 |
236 | if (($this->end_of_recurring !== null
237 | && $this->end_of_recurring < $startDateTime)
238 | // || $this->events()->withTrashed()->where('start_datetime', $startDateTime)->whereNotNull('deleted_at')->first()
239 | ) {
240 | return null;
241 | }
242 |
243 | return $startDateTime;
244 | }
245 | }
246 |
--------------------------------------------------------------------------------
/src/ServiceProvider.php:
--------------------------------------------------------------------------------
1 | loadMigrationsFrom(__DIR__ . '/database/migrations');
23 | // $this->publishes([
24 | // __DIR__ . '/database/migrations' => database_path('migrations'),
25 | // ], 'migrations');
26 |
27 | $this->publishes([
28 | __DIR__ . '/config' => config_path(),
29 | ], 'config');
30 |
31 | $this->app->booted(function () {
32 | $schedule = $this->app->make(Schedule::class);
33 | $schedule->command('generate:calendar-event')->hourly();
34 | });
35 | }
36 |
37 | /**
38 | * Register any application services.
39 | *
40 | * @return void
41 | */
42 | public function register()
43 | {
44 | $this->commands(GenerateCalendarEvent::class);
45 |
46 | // Package helpers
47 | if (file_exists($file = __DIR__ . '/Support/helpers.php')) require_once $file;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Support/helpers.php:
--------------------------------------------------------------------------------
1 | getFillable();
15 | foreach ($columns as $column) {
16 | if (in_array($column, $skippable)) continue;
17 |
18 | if (isset($array[$column])) {
19 | if ($array[$column] instanceof \Carbon\Carbon && !($model->{$column} instanceof \Carbon\Carbon)) {
20 | $model->{$column} = \Carbon\Carbon::parse($model->{$column});
21 | }
22 |
23 | if ($model->{$column} != $array[$column]) {
24 | return false;
25 | }
26 | } elseif ($model->{$column} !== null) {
27 | return false;
28 | }
29 |
30 | }
31 | return true;
32 | }
33 | }
34 |
35 | if (!function_exists('getWeekdaysInMonth')) {
36 | /**
37 | * @param string $weekday
38 | * @param date $date
39 | * @return collection
40 | */
41 | function getWeekdaysInMonth($weekday, $date)
42 | {
43 | $next = $date->copy()->addMonths(1);
44 | return collect(new \DatePeriod(
45 |
46 | Carbon::parse("first $weekday of $date"),
47 | CarbonInterval::week(),
48 | Carbon::parse("first $weekday of $next")
49 | ));
50 | }
51 | }
--------------------------------------------------------------------------------
/src/Traits/CalendarEventPlaceTrait.php:
--------------------------------------------------------------------------------
1 | hasManyThrough(
22 | CalendarEvent::class, TemplateCalendarEvent::class,
23 | 'place_id', 'template_calendar_event_id', 'id'
24 | );
25 | }
26 | }
--------------------------------------------------------------------------------
/src/Traits/CalendarEventUserTrait.php:
--------------------------------------------------------------------------------
1 | hasManyThrough(
22 | CalendarEvent::class, TemplateCalendarEvent::class,
23 | 'user_id', 'template_calendar_event_id', 'id'
24 | );
25 | }
26 | }
--------------------------------------------------------------------------------
/src/config/calendar-event.php:
--------------------------------------------------------------------------------
1 | [
5 | 'model' => null,
6 | ],
7 | 'place' => [
8 | 'model' => null,
9 | ],
10 | ];
--------------------------------------------------------------------------------
/src/database/factories/CalendarEventFactory.php:
--------------------------------------------------------------------------------
1 | make(\Illuminate\Database\Eloquent\Factory::class);
8 |
9 | /** @var \Illuminate\Database\Eloquent\Factory $factory */
10 | $factory->define(CalendarEvent::class, function (Faker $faker) {
11 | return [
12 | 'start_datetime' => Carbon::now()->addWeek()->format('Y-m-d'),
13 | 'end_datetime' => Carbon::now()->addWeek()->format('Y-m-d'),
14 | ];
15 | });
16 |
--------------------------------------------------------------------------------
/src/database/factories/TemplateCalendarEventFactory.php:
--------------------------------------------------------------------------------
1 | make(\Illuminate\Database\Eloquent\Factory::class);
8 |
9 | /** @var \Illuminate\Database\Eloquent\Factory $factory */
10 | $factory->define(TemplateCalendarEvent::class, function (Faker $faker) {
11 | return [
12 | 'title' => str_random(16),
13 | 'start_datetime' => Carbon::now()->addWeek(),
14 | 'end_datetime' => Carbon::now()->addWeek(),
15 | 'description' => str_random(32),
16 | 'is_recurring' => false,
17 | // 'frequence_number_of_recurring' => 1,
18 | // 'frequence_type_of_recurring' => 'week',
19 | 'is_public' => true,
20 | ];
21 | });
22 |
--------------------------------------------------------------------------------
/src/database/migrations/2017_08_22_082938_create_template_calendar_events_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
21 | $table->integer('parent_id')->unsigned()->nullable();
22 | $table->string('title')->nullable();
23 |
24 | $table->dateTime('start_datetime');
25 | $table->dateTime('end_datetime');
26 |
27 | $table->text('description')->nullable();
28 | $table->boolean('is_recurring')->default(false);
29 | $table->dateTime('end_of_recurring')->nullable();
30 | $table->integer('frequence_number_of_recurring')->nullable();
31 | $table->string('frequence_type_of_recurring', 32)->nullable();
32 | $table->boolean('is_public')->default(false);
33 | $table->timestamps();
34 | $table->softDeletes();
35 |
36 | $table->foreign('parent_id')
37 | ->references('id')->on('template_calendar_events')
38 | ->onDelete('cascade');
39 |
40 | $table->integer('user_id')->unsigned()->nullable();
41 | $table->integer('place_id')->unsigned()->nullable();
42 | });
43 | }
44 |
45 | /**
46 | * Reverse the migrations.
47 | *
48 | * @return void
49 | */
50 | public function down()
51 | {
52 | Schema::dropIfExists('template_calendar_events');
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/database/migrations/2017_08_22_093248_create_calendar_events_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
21 | $table->integer('template_calendar_event_id')->unsigned();
22 |
23 | $table->dateTime('start_datetime');
24 | $table->dateTime('end_datetime');
25 |
26 | $table->timestamps();
27 | $table->softDeletes();
28 |
29 | $table->foreign('template_calendar_event_id')
30 | ->references('id')->on('template_calendar_events')
31 | ->onDelete('cascade');
32 | });
33 | }
34 |
35 | /**
36 | * Reverse the migrations.
37 | *
38 | * @return void
39 | */
40 | public function down()
41 | {
42 | Schema::dropIfExists('calendar_events');
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | setUpFactory();
33 | $this->setUpDatabase();
34 |
35 | $this->withoutMockingConsoleOutput();
36 | }
37 |
38 | /**
39 | * Teardown
40 | */
41 | public function tearDown(): void
42 | {
43 | $this->consoleOutput = '';
44 | $this->artisan('migrate:reset');
45 |
46 | parent::tearDown();
47 | }
48 |
49 | /**
50 | * @param Application $app
51 | * @return array
52 | */
53 | protected function getPackageProviders($app)
54 | {
55 | return [
56 | LaravelCalendarEventServiceProvider::class,
57 | // \Orchestra\Database\ConsoleServiceProvider::class,
58 | ];
59 | }
60 |
61 | /**
62 | * Resolve application Console Kernel implementation.
63 | *
64 | * @param Application $app
65 | */
66 | public function resolveApplicationConsoleKernel($app)
67 | {
68 | $app->singleton(Kernel::class, \Orchestra\Testbench\Console\Kernel::class);
69 | }
70 |
71 | /**
72 | * @return mixed
73 | */
74 | public function getConsoleOutput()
75 | {
76 | return $this->consoleOutput ?: $this->consoleOutput = $this->app[Kernel::class]->output();
77 | }
78 |
79 | /**
80 | * Define environment setup
81 | *
82 | * @param Application $app
83 | */
84 | protected function getEnvironmentSetUp($app)
85 | {
86 | $app['config']->set('calendar-event.user.model', null);
87 | $app['config']->set('calendar-event.place.model', null);
88 |
89 | $app['config']->set('database.default', 'testing');
90 | $app['config']->set('database.connections.testing', [
91 | 'driver' => 'sqlite',
92 | 'database' => ':memory:',
93 | ]);
94 | }
95 |
96 | /**
97 | * Configure the factory
98 | */
99 | private function setUpFactory()
100 | {
101 | $this->withFactories(__DIR__ . '/../src/database/factories');
102 | $this->withFactories(__DIR__ . '/fixtures/database/factories');
103 | }
104 |
105 | /**
106 | * Configure the database
107 | * SQLite
108 | */
109 | private function setUpDatabase()
110 | {
111 | $this->artisan('migrate', ['--database' => 'testing']);
112 | $this->artisan('migrate', [
113 | '--database' => 'testing',
114 | // '--realpath' => realpath(__DIR__ . '/fixtures/database/migrations'),
115 | '--path' => '../../../../tests/fixtures/database/migrations',
116 | ]);
117 |
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/tests/Unit/Console/Command/GenerateCalendarEventTest.php:
--------------------------------------------------------------------------------
1 | templateCalendarEvent = new TemplateCalendarEvent();
36 | $this->calendarEvent = new CalendarEvent();
37 | }
38 |
39 | /**
40 | * @test
41 | */
42 | public function handle_notRecurring_notGenerated()
43 | {
44 | $now = '2017-08-28';
45 | $this->calendarEvent->createCalendarEvent([
46 | 'start_datetime' => '2017-08-29 08:00:00',
47 | 'end_datetime' => '2017-08-29 10:00:00',
48 | 'description' => str_random(32),
49 | 'is_recurring' => false,
50 | 'is_public' => true,
51 | ]);
52 |
53 | $this->artisan('generate:calendar-event', ['--date' => $now]);
54 | $this->assertContains('Generated CalendarEvent from Console | Summary: 0', $this->getConsoleOutput());
55 | $this->assertEquals(1, $this->calendarEvent->all()->count());
56 | }
57 |
58 | /**
59 | * @test
60 | */
61 | public function handle_recurring_endOfRecurring_notGenerated()
62 | {
63 | $now = '2017-08-09';
64 | $calendarEvent = $this->calendarEvent->createCalendarEvent([
65 | 'start_datetime' => '2017-08-01 10:00:00',
66 | 'end_datetime' => '2017-08-01 12:00:00',
67 | 'description' => str_random(32),
68 | 'is_recurring' => true,
69 | 'frequence_number_of_recurring' => 1,
70 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
71 | 'is_public' => true,
72 | 'end_of_recurring' => '2017-08-14',
73 | ]);
74 | $calendarEvent->template->generateNextCalendarEvent(Carbon::parse($now)); // '2017-08-08'
75 | $this->artisan('generate:calendar-event', ['--date' => $now]);
76 |
77 | $this->assertContains('Generated CalendarEvent from Console | Summary: 0', $this->getConsoleOutput());
78 | $this->assertEquals(2, $this->calendarEvent->all()->count());
79 | }
80 |
81 | public function dataProvider_for_handle_recurring_generated()
82 | {
83 | return [
84 | [
85 | [ // input
86 | 'start_datetime' => '2017-08-01 10:00:00',
87 | 'end_datetime' => '2017-08-01 12:00:00',
88 | 'description' => str_random(32),
89 | 'is_recurring' => true,
90 | 'frequence_number_of_recurring' => 2,
91 | 'frequence_type_of_recurring' => RecurringFrequenceType::DAY,
92 | 'is_public' => true,
93 | ],
94 | Carbon::parse('2017-08-16'), // now
95 | Carbon::parse('2017-08-16 10:00:00'), // start datetime
96 | Carbon::parse('2017-08-16 12:00:00'), // end datetime
97 | ],
98 | [
99 | [
100 | 'start_datetime' => '2017-08-01 10:00:00',
101 | 'end_datetime' => '2017-08-01 12:00:00',
102 | 'description' => str_random(32),
103 | 'is_recurring' => true,
104 | 'frequence_number_of_recurring' => 2,
105 | 'frequence_type_of_recurring' => RecurringFrequenceType::DAY,
106 | 'is_public' => true,
107 | ],
108 | Carbon::parse('2017-08-17'),
109 | Carbon::parse('2017-08-18 10:00:00'),
110 | Carbon::parse('2017-08-18 12:00:00'),
111 | ],
112 | [
113 | [
114 | 'start_datetime' => '2017-08-02 10:00:00',
115 | 'end_datetime' => '2017-08-02 12:00:00',
116 | 'description' => str_random(32),
117 | 'is_recurring' => true,
118 | 'frequence_number_of_recurring' => 3,
119 | 'frequence_type_of_recurring' => RecurringFrequenceType::DAY,
120 | 'is_public' => true,
121 | ],
122 | Carbon::parse('2017-08-17'),
123 | Carbon::parse('2017-08-19 10:00:00'),
124 | Carbon::parse('2017-08-19 12:00:00'),
125 | ],
126 | [
127 | [
128 | 'start_datetime' => '2017-08-01 10:00:00',
129 | 'end_datetime' => '2017-08-01 12:00:00',
130 | 'description' => str_random(32),
131 | 'is_recurring' => true,
132 | 'frequence_number_of_recurring' => 1,
133 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
134 | 'is_public' => true,
135 | ],
136 | Carbon::parse('2017-08-16'),
137 | Carbon::parse('2017-08-22 10:00:00'),
138 | Carbon::parse('2017-08-22 12:00:00'),
139 | ],
140 | [
141 | [
142 | 'start_datetime' => '2017-08-02 10:00:00',
143 | 'end_datetime' => '2017-08-04 12:00:00',
144 | 'description' => str_random(32),
145 | 'is_recurring' => true,
146 | 'frequence_number_of_recurring' => 2,
147 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
148 | 'is_public' => true,
149 | ],
150 | Carbon::parse('2017-08-17'),
151 | Carbon::parse('2017-08-23 10:00:00'),
152 | Carbon::parse('2017-08-25 12:00:00'),
153 | ],
154 | [
155 | [
156 | 'start_datetime' => '2017-08-01 10:00:00',
157 | 'end_datetime' => '2017-08-02 12:20:00',
158 | 'description' => str_random(32),
159 | 'is_recurring' => true,
160 | 'frequence_number_of_recurring' => 1,
161 | 'frequence_type_of_recurring' => RecurringFrequenceType::MONTH,
162 | 'is_public' => true,
163 | ],
164 | Carbon::parse('2017-08-26'),
165 | Carbon::parse('2017-09-01 10:00:00'),
166 | Carbon::parse('2017-09-02 12:20:00'),
167 | ],
168 | [
169 | [
170 | 'start_datetime' => '2016-08-27 11:00:00',
171 | 'end_datetime' => '2016-08-28 01:00:00',
172 | 'description' => str_random(32),
173 | 'is_recurring' => true,
174 | 'frequence_number_of_recurring' => 1,
175 | 'frequence_type_of_recurring' => RecurringFrequenceType::YEAR,
176 | 'is_public' => true,
177 | ],
178 | Carbon::parse('2017-08-26'), // @TODO
179 | Carbon::parse('2017-08-27 11:00:00'),
180 | Carbon::parse('2017-08-28 01:00:00'),
181 | ],
182 | [
183 | [
184 | 'start_datetime' => '2019-07-17 19:30:00',
185 | 'end_datetime' => '2019-07-17 20:00:00',
186 | 'description' => str_random(32),
187 | 'is_recurring' => true,
188 | 'frequence_number_of_recurring' => 1,
189 | 'frequence_type_of_recurring' => RecurringFrequenceType::NTHWEEKDAY,
190 | 'is_public' => true,
191 | ],
192 | Carbon::parse('2019-07-15'),
193 | Carbon::parse('2019-07-17 19:30:00'),
194 | Carbon::parse('2019-07-17 20:00:00'),
195 | ],
196 | [
197 | [
198 | 'start_datetime' => '2019-08-21 19:30:00',
199 | 'end_datetime' => '2019-08-21 20:00:00',
200 | 'description' => str_random(32),
201 | 'is_recurring' => true,
202 | 'frequence_number_of_recurring' => 1,
203 | 'frequence_type_of_recurring' => RecurringFrequenceType::NTHWEEKDAY,
204 | 'is_public' => true,
205 | ],
206 | Carbon::parse('2019-08-19'),
207 | Carbon::parse('2019-08-21 19:30:00'),
208 | Carbon::parse('2019-08-21 20:00:00'),
209 | ],
210 | [
211 | [
212 | 'start_datetime' => '2019-09-18 19:30:00',
213 | 'end_datetime' => '2019-09-18 20:00:00',
214 | 'description' => str_random(32),
215 | 'is_recurring' => true,
216 | 'frequence_number_of_recurring' => 1,
217 | 'frequence_type_of_recurring' => RecurringFrequenceType::NTHWEEKDAY,
218 | 'is_public' => true,
219 | ],
220 | Carbon::parse('2019-09-16'),
221 | Carbon::parse('2019-09-18 19:30:00'),
222 | Carbon::parse('2019-09-18 20:00:00'),
223 | ],
224 | ];
225 | }
226 |
227 | /**
228 | * @test
229 | * @dataProvider dataProvider_for_handle_recurring_generated
230 | * @param $input
231 | * @param $now
232 | * @param $startDateTime
233 | * @param $endDateTime
234 | */
235 | public function handle_recurring_generated($input, $now, $startDateTime, $endDateTime)
236 | {
237 | $calendarEvent = $this->calendarEvent->createCalendarEvent($input);
238 |
239 | $this->artisan('generate:calendar-event', ['--date' => $now]);
240 | $this->artisan('generate:calendar-event', ['--date' => $now]);
241 |
242 | $calendarEventLast = $calendarEvent->template->events()->orderBy('start_datetime', 'desc')->first();
243 |
244 | $this->assertContains('Generated CalendarEvent from Console | Summary:', $this->getConsoleOutput());
245 | $this->assertEquals($startDateTime, $calendarEventLast->start_datetime);
246 | $this->assertEquals($endDateTime, $calendarEventLast->end_datetime);
247 | $this->assertDatabaseHas('calendar_events', ['start_datetime' => $startDateTime, 'end_datetime' => $endDateTime]);
248 | }
249 |
250 | /**
251 | * @test
252 | */
253 | public function handle_recurring_generated_year_by_seconds()
254 | {
255 | $now = Carbon::parse('2017-08-26');
256 | $startDateTime = Carbon::parse('2016-08-27 11:59:59');
257 | $endDateTime = Carbon::parse('2016-08-28 00:00:01');
258 |
259 | $calendarEvent = $this->calendarEvent->createCalendarEvent([
260 | 'start_datetime' => $startDateTime,
261 | 'end_datetime' => $endDateTime,
262 | 'description' => str_random(32),
263 | 'is_recurring' => true,
264 | 'frequence_number_of_recurring' => 1,
265 | 'frequence_type_of_recurring' => RecurringFrequenceType::YEAR,
266 | 'is_public' => true,
267 | ]);
268 |
269 | $this->artisan('generate:calendar-event', ['--date' => $now]);
270 | $this->artisan('generate:calendar-event', ['--date' => $now]);
271 |
272 | $calendarEventLast = $calendarEvent->template->events()->orderBy('start_datetime', 'desc')->first();
273 |
274 | $startDateTime->addYear();
275 | $endDateTime->addYear();
276 |
277 | $this->assertContains('Generated CalendarEvent from Console | Summary:', $this->getConsoleOutput());
278 | $this->assertEquals($startDateTime, $calendarEventLast->start_datetime);
279 | $this->assertEquals($endDateTime, $calendarEventLast->end_datetime);
280 | $this->assertDatabaseHas('calendar_events', ['start_datetime' => $startDateTime, 'end_datetime' => $endDateTime]);
281 | }
282 |
283 | /**
284 | * @test
285 | */
286 | public function handle_recurring_editedNotRecurring_notGenerated()
287 | {
288 | $now = Carbon::parse('2017-08-14');
289 | $calendarEvent = $this->calendarEvent->createCalendarEvent([
290 | 'title' => 'Lorem ipsum',
291 | 'start_datetime' => Carbon::parse('2017-08-01 10:00:00'),
292 | 'end_datetime' => Carbon::parse('2017-08-01 12:00:00'),
293 | 'description' => str_random(32),
294 | 'is_recurring' => true,
295 | 'frequence_number_of_recurring' => 1,
296 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
297 | 'is_public' => true,
298 | ]);
299 | $calendarEventNextTmp = $calendarEvent->template->generateNextCalendarEvent(new \DateTime($now)); // '2017-08-08'
300 | $calendarEventNextTmp = $calendarEvent->template->generateNextCalendarEvent(Carbon::parse($now)); // '2017-08-15'
301 | $calendarEventNextTmpUpdated = $calendarEventNextTmp->editCalendarEvent([
302 | 'start_datetime' => Carbon::parse('2017-08-09 10:00:00'),
303 | 'is_recurring' => false,
304 | ]);
305 |
306 | $this->artisan('generate:calendar-event', ['--date' => $now]);
307 | $this->artisan('generate:calendar-event', ['--date' => $now]);
308 |
309 | $calendarEventLast = $calendarEvent->template->events()->orderBy('start_datetime', 'desc')->first();
310 |
311 | // The next is 2017-08-15 but is deleted
312 | $this->assertContains('Generated CalendarEvent from Console | Summary: 0', $this->getConsoleOutput());
313 | $this->assertEquals('2017-08-08', $calendarEventLast->start_datetime->format('Y-m-d'));
314 | }
315 |
316 | /**
317 | * @test
318 | */
319 | public function handle_recurring_editedNotRecurring_generated()
320 | {
321 | $now = Carbon::parse('2017-08-16');
322 | $calendarEvent = $this->calendarEvent->createCalendarEvent([
323 | 'title' => 'Lorem ipsum',
324 | 'start_datetime' => Carbon::parse('2017-08-01 10:00:00'),
325 | 'end_datetime' => Carbon::parse('2017-08-01 12:00:00'),
326 | 'description' => str_random(32),
327 | 'is_recurring' => true,
328 | 'frequence_number_of_recurring' => 1,
329 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
330 | 'is_public' => true,
331 | ]);
332 | $calendarEventNextTmp = $calendarEvent->template->generateNextCalendarEvent(new \DateTime($now)); // '2017-08-08'
333 | $calendarEventNextTmp = $calendarEvent->template->generateNextCalendarEvent(Carbon::parse($now)); // '2017-08-15'
334 | $calendarEventNextTmpUpdated = $calendarEventNextTmp->editCalendarEvent([
335 | 'start_datetime' => Carbon::parse('2017-08-09 10:00:00'),
336 | 'is_recurring' => false,
337 | ]);
338 |
339 | $this->artisan('generate:calendar-event', ['--date' => $now]);
340 | $this->artisan('generate:calendar-event', ['--date' => $now]);
341 |
342 | $calendarEventLast = $calendarEvent->template->events()->orderBy('start_datetime', 'desc')->first();
343 |
344 | $this->assertContains('Generated CalendarEvent from Console | Summary:', $this->getConsoleOutput());
345 | $this->assertEquals('2017-08-22', $calendarEventLast->start_datetime->format('Y-m-d'));
346 |
347 | $this->assertDatabaseHas('calendar_events', ['start_datetime' => Carbon::parse('2017-08-22 10:00:00')]);
348 | }
349 | }
--------------------------------------------------------------------------------
/tests/Unit/Models/CalendarEventTest.php:
--------------------------------------------------------------------------------
1 | calendarEvent = new CalendarEvent();
32 | }
33 |
34 | /**
35 | * @test
36 | */
37 | public function createInstanceFromClass()
38 | {
39 | $this->assertInstanceOf(CalendarEvent::class, $this->calendarEvent);
40 | }
41 |
42 | /**
43 | * @test
44 | */
45 | public function getFillable()
46 | {
47 | $expectedFillables = [
48 | 'start_datetime',
49 | 'end_datetime',
50 | ];
51 | $this->assertArraySubset($expectedFillables, $this->calendarEvent->getFillable());
52 | }
53 |
54 | /**
55 | * @test
56 | */
57 | public function template()
58 | {
59 | $templateCalendarEvent = factory(TemplateCalendarEvent::class)->create();
60 |
61 | $calendarEvent = factory(CalendarEvent::class)->make();
62 | $calendarEvent->template()->associate($templateCalendarEvent);
63 | $calendarEvent->save();
64 |
65 | $this->assertInstanceOf(TemplateCalendarEvent::class, $calendarEvent->template);
66 | }
67 |
68 | /**
69 | * Data provider for create calendar event
70 | * @return array
71 | */
72 | public function dataProvider_for_createCalendarEvent()
73 | {
74 | return [
75 | 'not_recurring' => [
76 | [
77 | 'title' => str_random(16),
78 | 'start_datetime' => Carbon::parse('2017-08-25 10:00:00'),
79 | 'end_datetime' => Carbon::parse('2017-08-25 12:00:00'),
80 | 'description' => str_random(32),
81 | 'is_recurring' => false,
82 | 'is_public' => true,
83 | ],
84 | ],
85 | 'recurring' => [
86 | [
87 | 'title' => str_random(16),
88 | 'start_datetime' => Carbon::parse('2017-08-25 10:00:00'),
89 | 'end_datetime' => Carbon::parse('2017-08-25 12:00:00'),
90 | 'description' => str_random(32),
91 | 'is_recurring' => true,
92 | 'frequence_number_of_recurring' => 1,
93 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
94 | 'is_public' => true,
95 | ],
96 | ],
97 | ];
98 | }
99 |
100 | /**
101 | * Create event, not recurring
102 | * @test
103 | * @dataProvider dataProvider_for_createCalendarEvent
104 | * @param array $input
105 | */
106 | public function createCalendarEvent(array $input)
107 | {
108 | $calendarEvent = $this->calendarEvent->createCalendarEvent($input);
109 |
110 | $this->assertInstanceOf(CalendarEvent::class, $calendarEvent);
111 | $this->assertEquals($input['start_datetime']->format('Y-m-d'), $calendarEvent->start_datetime->format('Y-m-d'));
112 | $this->assertInstanceOf(TemplateCalendarEvent::class, $calendarEvent->template);
113 |
114 | $this->assertDatabaseHas('template_calendar_events', $input);
115 | }
116 |
117 | /**
118 | * @test
119 | * @dataProvider dataProvider_for_createCalendarEvent
120 | * @param array $input
121 | */
122 | public function createCalendarEvent_user_place(array $input)
123 | {
124 | $this->app['config']->set('calendar-event.user.model', User::class);
125 | $this->app['config']->set('calendar-event.place.model', Place::class);
126 |
127 | $user = factory(config('calendar-event.user.model'))->create();
128 | $place = factory(config('calendar-event.place.model'))->create();
129 | $calendarEvent = $this->calendarEvent->createCalendarEvent($input, $user, $place);
130 |
131 | $this->assertInstanceOf(CalendarEvent::class, $calendarEvent);
132 | $this->assertEquals($input['start_datetime']->format('Y-m-d'), $calendarEvent->start_datetime->format('Y-m-d'));
133 | $this->assertEquals($user, $calendarEvent->template->user);
134 | $this->assertEquals($place, $calendarEvent->template->place);
135 | $this->assertInstanceOf(TemplateCalendarEvent::class, $calendarEvent->template);
136 |
137 | $this->assertInstanceOf(CalendarEvent::class, $user->calendarEvents()->first());
138 | $this->assertInstanceOf(CalendarEvent::class, $place->calendarEvents()->first());
139 |
140 | $this->assertDatabaseHas('template_calendar_events', $input);
141 | $this->assertDatabaseHas('users', $user->toArray());
142 | $this->assertDatabaseHas('places', $place->toArray());
143 | }
144 |
145 | /**
146 | * Edit event but not modified
147 | * @test
148 | */
149 | public function editCalendarEvent_notModified()
150 | {
151 | $inputCreate = [
152 | 'title' => str_random(16),
153 | 'start_datetime' => Carbon::parse('2017-08-01 11:00:00'),
154 | 'end_datetime' => Carbon::parse('2017-08-01 12:00:00'),
155 | 'description' => str_random(32),
156 | 'is_recurring' => false,
157 | 'is_public' => true,
158 |
159 | ];
160 | $calendarEvent = $this->calendarEvent->createCalendarEvent($inputCreate);
161 | $calendarEventUpdated = $calendarEvent->editCalendarEvent($inputCreate);
162 |
163 | $this->assertNull($calendarEventUpdated);
164 | }
165 |
166 | /**
167 | * Edit event and modified, calendar event data
168 | * @test
169 | */
170 | public function editCalendarEvent_recurring_modifiedCalendarEventData_recurring()
171 | {
172 | $inputCreate = [
173 | 'title' => str_random(16),
174 | 'start_datetime' => Carbon::parse('2017-08-01 11:00'),
175 | 'end_datetime' => Carbon::parse('2017-08-01 12:00'),
176 | 'description' => str_random(32),
177 | 'is_recurring' => true,
178 | 'frequence_number_of_recurring' => 1,
179 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
180 | 'is_public' => true,
181 | 'end_of_recurring' => Carbon::parse('2017-08-22'),
182 | ];
183 | $inputUpdate = [
184 | 'start_datetime' => Carbon::parse('2017-08-03'),
185 | ];
186 |
187 | $calendarEvent = $this->calendarEvent->createCalendarEvent($inputCreate);
188 | $calendarEventNext = $calendarEvent->template->generateNextCalendarEvent(Carbon::parse('2017-08-06'));
189 | $calendarEventUpdated = $calendarEventNext->editCalendarEvent($inputUpdate);
190 |
191 | $this->assertNull($calendarEvent->deleted_at);
192 | $this->assertNotNull($calendarEventNext->deleted_at);
193 | $this->assertEquals($calendarEventNext->start_datetime->format('Y-m-d'), $calendarEventNext->template->end_of_recurring->format('Y-m-d'));
194 |
195 | $this->assertInstanceOf(CalendarEvent::class, $calendarEventUpdated);
196 | $this->assertEquals($inputUpdate['start_datetime']->format('Y-m-d'), $calendarEventUpdated->start_datetime->format('Y-m-d'));
197 | $this->assertEquals($inputCreate['end_of_recurring']->format('Y-m-d'), $calendarEventUpdated->template->end_of_recurring->format('Y-m-d'));
198 |
199 | $this->assertInstanceOf(TemplateCalendarEvent::class, $calendarEventUpdated->template);
200 | $this->assertEquals($calendarEvent->id, $calendarEventUpdated->template->parent_id);
201 |
202 | $this->assertDatabaseHas('template_calendar_events', $inputUpdate);
203 | $this->assertDatabaseHas('calendar_events', $inputUpdate);
204 | }
205 |
206 | /**
207 | * Edit event and modified, calendar event data
208 | * @test
209 | */
210 | public function editCalendarEvent_recurring_modifiedCalendarEventData_recurring_nextCalendarEventIsDeleted()
211 | {
212 | $inputCreate = [
213 | 'title' => str_random(16),
214 | 'start_datetime' => Carbon::parse('2017-08-01 11:00:00'),
215 | 'end_datetime' => Carbon::parse('2017-08-01 12:00:00'),
216 | 'description' => str_random(32),
217 | 'is_recurring' => true,
218 | 'frequence_number_of_recurring' => 1,
219 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
220 | 'is_public' => true,
221 | 'end_of_recurring' => Carbon::parse('2017-08-22'),
222 | ];
223 | $inputUpdate = [
224 | 'start_datetime' => Carbon::parse('2017-08-03'),
225 | ];
226 |
227 | $calendarEvent = $this->calendarEvent->createCalendarEvent($inputCreate);
228 | $calendarEventNext = $calendarEvent->template->generateNextCalendarEvent(Carbon::parse('2017-08-06'));
229 | $calendarEventUpdated = $calendarEvent->editCalendarEvent($inputUpdate);
230 |
231 | $this->assertNotNull($calendarEvent->deleted_at);
232 | $this->assertNotNull($calendarEventNext->fresh()->deleted_at);
233 | $this->assertEquals($calendarEvent->start_datetime->format('Y-m-d'), $calendarEventNext->template->end_of_recurring->format('Y-m-d'));
234 |
235 | $this->assertInstanceOf(CalendarEvent::class, $calendarEventUpdated);
236 | $this->assertEquals($inputUpdate['start_datetime']->format('Y-m-d'), $calendarEventUpdated->start_datetime->format('Y-m-d'));
237 | $this->assertEquals($inputCreate['end_of_recurring']->format('Y-m-d'), $calendarEventUpdated->template->end_of_recurring->format('Y-m-d'));
238 |
239 | $this->assertInstanceOf(TemplateCalendarEvent::class, $calendarEventUpdated->template);
240 | $this->assertEquals($calendarEvent->id, $calendarEventUpdated->template->parent_id);
241 |
242 | $this->assertDatabaseHas('template_calendar_events', $inputUpdate);
243 | $this->assertDatabaseHas('calendar_events', $inputUpdate);
244 | }
245 |
246 | /**
247 | * Edit event and modified, calendar event data
248 | * @test
249 | */
250 | public function editCalendarEvent_recurring_modifiedCalendarEventData_notRecurring()
251 | {
252 | $inputCreate = [
253 | 'title' => str_random(16),
254 | 'start_datetime' => Carbon::parse('2017-08-25 16:00:00'),
255 | 'end_datetime' => Carbon::parse('2017-08-25 17:00:00'),
256 | 'description' => str_random(32),
257 | 'is_recurring' => true,
258 | 'frequence_number_of_recurring' => 1,
259 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
260 | 'is_public' => true,
261 | 'end_of_recurring' => Carbon::parse('2017-09-08'),
262 | ];
263 | $inputUpdate = [
264 | 'start_datetime' => Carbon::parse('2017-08-27'),
265 | 'is_recurring' => false,
266 | ];
267 |
268 | $calendarEvent = $this->calendarEvent->createCalendarEvent($inputCreate);
269 | $calendarEventNext = $calendarEvent->template->generateNextCalendarEvent(Carbon::parse('2017-08-27'));
270 | $calendarEventUpdated = $calendarEventNext->editCalendarEvent($inputUpdate);
271 |
272 | $this->assertNull($calendarEvent->deleted_at);
273 | $this->assertNotNull($calendarEventNext->deleted_at);
274 | $this->assertEquals($inputCreate['end_of_recurring']->format('Y-m-d'), $calendarEventNext->template->end_of_recurring->format('Y-m-d'));
275 |
276 | $this->assertInstanceOf(CalendarEvent::class, $calendarEventUpdated);
277 | $this->assertEquals($inputUpdate['start_datetime']->format('Y-m-d'), $calendarEventUpdated->start_datetime->format('Y-m-d'));
278 | $this->assertNull($calendarEventUpdated->template->end_of_recurring);
279 |
280 | $this->assertInstanceOf(TemplateCalendarEvent::class, $calendarEventUpdated->template);
281 | $this->assertEquals($calendarEvent->id, $calendarEventUpdated->template->parent_id);
282 |
283 | $this->assertDatabaseHas('template_calendar_events', $inputUpdate);
284 | $this->assertDatabaseHas('calendar_events', ['start_datetime' => $inputUpdate['start_datetime']]);
285 | }
286 |
287 | /**
288 | * Edit event and modified, calendar event data
289 | * @test
290 | */
291 | public function editCalendarEvent_notRecurring_modifiedToRecurring()
292 | {
293 | $inputCreate = [
294 | 'title' => str_random(16),
295 | 'start_datetime' => Carbon::parse('2017-08-25 08:00:00'),
296 | 'end_datetime' => Carbon::parse('2017-08-25 14:00:00'),
297 | 'description' => str_random(32),
298 | 'is_recurring' => false,
299 | 'is_public' => true,
300 | ];
301 | $inputUpdate = [
302 | 'is_recurring' => true,
303 | ];
304 |
305 | $calendarEvent = $this->calendarEvent->createCalendarEvent($inputCreate);
306 | $calendarEventUpdated = $calendarEvent->editCalendarEvent($inputUpdate);
307 |
308 | $this->assertNotNull($calendarEvent->deleted_at);
309 | $this->assertNull($calendarEvent->template->end_of_recurring);
310 |
311 | $this->assertInstanceOf(CalendarEvent::class, $calendarEventUpdated);
312 |
313 | $this->assertInstanceOf(TemplateCalendarEvent::class, $calendarEventUpdated->template);
314 | $this->assertEquals($inputUpdate['is_recurring'], $calendarEventUpdated->template->is_recurring);
315 | $this->assertEquals($calendarEvent->id, $calendarEventUpdated->template->parent_id);
316 |
317 | $this->assertDatabaseHas('template_calendar_events', array_merge($inputCreate, $inputUpdate));
318 | }
319 |
320 | /**
321 | * @test
322 | */
323 | public function updateCalendarEvent()
324 | {
325 | $inputCreate = [
326 | 'title' => str_random(16),
327 | 'start_datetime' => Carbon::parse('2017-08-25 08:00:00'),
328 | 'end_datetime' => Carbon::parse('2017-08-25 14:00:00'),
329 | 'description' => str_random(32),
330 | 'is_recurring' => false,
331 | 'is_public' => true,
332 | ];
333 |
334 | $calendarEvent = $this->calendarEvent->createCalendarEvent($inputCreate);
335 | $calendarEventUpdated = $calendarEvent->updateCalendarEvent($inputCreate);
336 |
337 | $this->assertDatabaseHas('template_calendar_events', $inputCreate + ['id' => $calendarEventUpdated->template->id]);
338 | $this->assertDatabaseHas('calendar_events', ['id' => $calendarEventUpdated->id]);
339 | $this->assertNotEquals($calendarEvent->id, $calendarEventUpdated->id);
340 | $this->assertEquals($calendarEvent->template->id, $calendarEventUpdated->template->parent_id);
341 | }
342 |
343 | /**
344 | * NOT data provider
345 | * @return array
346 | */
347 | public function data_for_eventOfMonth()
348 | {
349 | return [
350 | 'dates' => [
351 | '2017-08-12', '2017-08-26',
352 | '2017-08-02',
353 | '2017-08-03', '2017-08-10', '2017-08-17', '2017-08-24', '2017-08-31',
354 | '2017-08-04', '2017-08-18',
355 | '2017-08-06',
356 | '2017-08-07',
357 | ],
358 | 'inputs' => [
359 | [
360 | 'title' => str_random(16),
361 | 'start_datetime' => Carbon::parse('2016-10-01 11:30:00'),
362 | 'end_datetime' => Carbon::parse('2016-10-01 12:30:00'),
363 | 'description' => str_random(32),
364 | 'is_recurring' => true,
365 | 'frequence_number_of_recurring' => 1,
366 | 'frequence_type_of_recurring' => RecurringFrequenceType::YEAR,
367 | 'is_public' => true,
368 | ],
369 | [
370 | 'title' => str_random(16),
371 | 'start_datetime' => Carbon::parse('2017-07-13 14:45:00'),
372 | 'end_datetime' => Carbon::parse('2017-07-13 15:45:00'),
373 | 'description' => str_random(32),
374 | 'is_recurring' => true,
375 | 'frequence_number_of_recurring' => 2,
376 | 'frequence_type_of_recurring' => RecurringFrequenceType::MONTH,
377 | 'end_of_recurring' => Carbon::parse('2017-12-15'),
378 | 'is_public' => true,
379 | ],
380 | [
381 | 'title' => str_random(16),
382 | 'start_datetime' => Carbon::parse('2017-07-14 11:45:00'),
383 | 'end_datetime' => Carbon::parse('2017-07-14 12:45:00'),
384 | 'description' => str_random(32),
385 | 'is_recurring' => false,
386 | 'is_public' => true,
387 | ],
388 | [
389 | // 2017-08-12, 2017-08-26
390 | 'title' => str_random(16),
391 | 'start_datetime' => Carbon::parse('2017-07-15 14:45:00'),
392 | 'end_datetime' => Carbon::parse('2017-07-15 15:45:00'),
393 | 'description' => str_random(32),
394 | 'is_recurring' => true,
395 | 'frequence_number_of_recurring' => 2,
396 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
397 | 'is_public' => true,
398 | ],
399 | [
400 | // 2017-08-07
401 | 'title' => str_random(16),
402 | 'start_datetime' => Carbon::parse('2017-07-17 14:45:00'),
403 | 'end_datetime' => Carbon::parse('2017-07-17 15:45:00'),
404 | 'description' => str_random(32),
405 | 'is_recurring' => true,
406 | 'frequence_number_of_recurring' => 1,
407 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
408 | 'end_of_recurring' => Carbon::parse('2017-08-08'),
409 | 'is_public' => true,
410 | ],
411 | [
412 | // 2017-08-02
413 | 'title' => str_random(16),
414 | 'start_datetime' => Carbon::parse('2017-08-02 9:00:00'),
415 | 'end_datetime' => Carbon::parse('2017-08-02 10:00:00'),
416 | 'description' => str_random(32),
417 | 'is_recurring' => false,
418 | 'is_public' => true,
419 | ],
420 | [
421 | // 2017-08-03, 2017-08-10, 2017-08-17, 2017-08-24, 2017-08-31
422 | 'title' => str_random(16),
423 | 'start_datetime' => Carbon::parse('2017-08-03 10:00:00'),
424 | 'end_datetime' => Carbon::parse('2017-08-03 14:00:00'),
425 | 'description' => str_random(32),
426 | 'is_recurring' => true,
427 | 'frequence_number_of_recurring' => 1,
428 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
429 | 'is_public' => true,
430 | ],
431 | [
432 | // 2017-08-04, 2017-08-18
433 | 'title' => str_random(16),
434 | 'start_datetime' => Carbon::parse('2017-08-04 10:00:00'),
435 | 'end_datetime' => Carbon::parse('2017-08-04 14:00:00'),
436 | 'description' => str_random(32),
437 | 'is_recurring' => true,
438 | 'frequence_number_of_recurring' => 2,
439 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
440 | 'is_public' => true,
441 | 'end_of_recurring' => Carbon::parse('2017-09-25'),
442 | ],
443 | [
444 | // 2017-08-06
445 | 'title' => str_random(16),
446 | 'start_datetime' => Carbon::parse('2017-07-06 10:00:00'),
447 | 'end_datetime' => Carbon::parse('2017-07-06 14:00:00'),
448 | 'description' => str_random(32),
449 | 'is_recurring' => true,
450 | 'frequence_number_of_recurring' => 1,
451 | 'frequence_type_of_recurring' => RecurringFrequenceType::MONTH,
452 | 'is_public' => true,
453 | ],
454 | [
455 | 'title' => str_random(16),
456 | 'start_datetime' => Carbon::parse('2017-09-01 10:00:00'),
457 | 'end_datetime' => Carbon::parse('2017-09-01 14:00:00'),
458 | 'description' => str_random(32),
459 | 'is_recurring' => true,
460 | 'frequence_number_of_recurring' => 1,
461 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
462 | 'is_public' => true,
463 | 'end_of_recurring' => Carbon::parse('2017-09-22'),
464 | ],
465 | ],
466 | ];
467 | }
468 |
469 | /**
470 | * @test
471 | */
472 | public function test_eventsOfMonth()
473 | {
474 | $data = $this->data_for_eventOfMonth();
475 | extract($data); // $inputs, $dates
476 |
477 | foreach ($inputs as $input) {
478 | $this->calendarEvent->createCalendarEvent($input);
479 | }
480 | $calendarEvents = CalendarEvent::showPotentialCalendarEventsOfMonth(Carbon::parse('2017-08'));
481 |
482 | $this->assertInstanceOf(CalendarEvent::class, $calendarEvents[0]);
483 | $this->assertEquals(count($dates), $calendarEvents->count());
484 | foreach ($calendarEvents as $calendarEvent) {
485 | $isExist = in_array($calendarEvent->start_datetime->format('Y-m-d'), $dates);
486 | $this->assertTrue($isExist);
487 | }
488 | }
489 |
490 | public function dataProvider_for_eventsOfMonth_after_merge_date_time()
491 | {
492 | for ($i = 1; $i <= 31; $i++) {
493 | $array[] = [$i];
494 | }
495 |
496 | return $array;
497 | }
498 |
499 | /**
500 | * @test
501 | * @dataProvider dataProvider_for_eventsOfMonth_after_merge_date_time
502 | * @param int $day
503 | */
504 | public function getEventsOfMonth_after_merge_date_time(int $day)
505 | {
506 | $startDateTime = Carbon::parse('2019-07-' . $day . ' 18:00:00');
507 | $this->calendarEvent->createCalendarEvent([
508 | 'title' => str_random(16),
509 | 'start_datetime' => $startDateTime,
510 | 'end_datetime' => clone($startDateTime)->addHours(2),
511 | 'description' => str_random(32),
512 | 'is_recurring' => true,
513 | 'frequence_number_of_recurring' => 1,
514 | 'frequence_type_of_recurring' => RecurringFrequenceType::DAY,
515 | 'is_public' => true,
516 | 'end_of_recurring' => null,
517 | ]);
518 |
519 | $calendarEvents = CalendarEvent::showPotentialCalendarEventsOfMonth(Carbon::parse('2019-07'));
520 | $this->assertEquals(32 - $day, $calendarEvents->count());
521 | }
522 |
523 | /**
524 | * @test
525 | * @dataProvider dataProvider_for_eventsOfMonth_after_merge_date_time
526 | * @param int $day
527 | */
528 | public function getEventsOfMonth_after_merge_date_time_nextMonth(int $day)
529 | {
530 | $startDateTime = Carbon::parse('2019-07-' . $day . ' 18:00:00');
531 | $this->calendarEvent->createCalendarEvent([
532 | 'title' => str_random(16),
533 | 'start_datetime' => $startDateTime,
534 | 'end_datetime' => (clone($startDateTime))->addHours(2),
535 | 'description' => str_random(32),
536 | 'is_recurring' => true,
537 | 'frequence_number_of_recurring' => 1,
538 | 'frequence_type_of_recurring' => RecurringFrequenceType::DAY,
539 | 'is_public' => true,
540 | 'end_of_recurring' => null,
541 | ]);
542 |
543 | $calendarEvents = CalendarEvent::showPotentialCalendarEventsOfMonth(Carbon::parse('2019-08'));
544 | $this->assertEquals(31, $calendarEvents->count());
545 | }
546 |
547 | /**
548 | * @test
549 | */
550 | public function getEventsOfMonth_after_merge_date_time_Type_week()
551 | {
552 | $startDateTime = Carbon::parse('2019-07-03 18:00:00');
553 | $this->calendarEvent->createCalendarEvent([
554 | 'title' => str_random(16),
555 | 'start_datetime' => $startDateTime,
556 | 'end_datetime' => (clone($startDateTime))->addHours(2),
557 | 'description' => str_random(32),
558 | 'is_recurring' => true,
559 | 'frequence_number_of_recurring' => 1,
560 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
561 | 'is_public' => true,
562 | 'end_of_recurring' => null,
563 | ]);
564 |
565 | $calendarEvents = CalendarEvent::showPotentialCalendarEventsOfMonth(Carbon::parse('2019-07'));
566 | $this->assertEquals(5, $calendarEvents->count());
567 | }
568 |
569 | /**
570 | * @test
571 | */
572 | public function getEventsOfMonth_after_merge_date_time_Type_month()
573 | {
574 | $startDateTime = Carbon::parse('2019-07-18 20:45:00');
575 | $this->calendarEvent->createCalendarEvent([
576 | 'title' => str_random(16),
577 | 'start_datetime' => $startDateTime,
578 | 'end_datetime' => (clone($startDateTime))->addHours(2),
579 | 'description' => str_random(32),
580 | 'is_recurring' => true,
581 | 'frequence_number_of_recurring' => 1,
582 | 'frequence_type_of_recurring' => RecurringFrequenceType::MONTH,
583 | 'is_public' => true,
584 | 'end_of_recurring' => null,
585 | ]);
586 |
587 | $calendarEvents = CalendarEvent::showPotentialCalendarEventsOfMonth(Carbon::parse('2019-07'));
588 | $this->assertEquals(1, $calendarEvents->count());
589 | $this->assertEquals('2019-07-18 20:45:00', $calendarEvents->first()->start_datetime->format('Y-m-d H:i:s'));
590 | }
591 |
592 | /**
593 | * @test
594 | */
595 | public function getEventsOfMonth_after_merge_date_time_Type_year()
596 | {
597 | $startDateTime = Carbon::parse('2019-07-18 20:00:00');
598 | $this->calendarEvent->createCalendarEvent([
599 | 'title' => str_random(16),
600 | 'start_datetime' => $startDateTime,
601 | 'end_datetime' => (clone($startDateTime))->addHours(2),
602 | 'description' => str_random(32),
603 | 'is_recurring' => true,
604 | 'frequence_number_of_recurring' => 1,
605 | 'frequence_type_of_recurring' => RecurringFrequenceType::YEAR,
606 | 'is_public' => true,
607 | 'end_of_recurring' => null,
608 | ]);
609 |
610 | $calendarEvents = CalendarEvent::showPotentialCalendarEventsOfMonth(Carbon::parse('2019-07'));
611 | $this->assertEquals(1, $calendarEvents->count());
612 | $this->assertEquals('2019-07-18 20:00:00', $calendarEvents->first()->start_datetime->format('Y-m-d H:i:s'));
613 | }
614 |
615 | /**
616 | * @test
617 | */
618 | public function getEventsOfMonth_for_nthweekRecurring()
619 | {
620 | $this->calendarEvent->createCalendarEvent([
621 | 'start_datetime' => '2019-06-19 19:30:00',
622 | 'end_datetime' => '2019-06-19 20:00:00',
623 | 'description' => str_random(32),
624 | 'is_recurring' => true,
625 | 'frequence_number_of_recurring' => 1,
626 | 'frequence_type_of_recurring' => RecurringFrequenceType::NTHWEEKDAY,
627 | 'is_public' => true,
628 | 'end_of_recurring' => null,
629 | ]);
630 |
631 |
632 | $calendarEvents = CalendarEvent::showPotentialCalendarEventsOfMonth(Carbon::parse('2019-07'));
633 | $this->assertEquals(1, $calendarEvents->count());
634 | $this->assertEquals('2019-07-17', $calendarEvents->first()->start_datetime->format('Y-m-d'));
635 |
636 | $calendarEvents = CalendarEvent::showPotentialCalendarEventsOfMonth(Carbon::parse('2019-08'));
637 | $this->assertEquals(1, $calendarEvents->count());
638 | $this->assertEquals('2019-08-21', $calendarEvents->first()->start_datetime->format('Y-m-d'));
639 |
640 | $calendarEvents = CalendarEvent::showPotentialCalendarEventsOfMonth(Carbon::parse('2019-09'));
641 | $this->assertEquals(1, $calendarEvents->count());
642 | $this->assertEquals('2019-09-18', $calendarEvents->first()->start_datetime->format('Y-m-d'));
643 | }
644 |
645 | /**
646 | * @test
647 | */
648 | public function eventsOfMonth_empty()
649 | {
650 | $calendarEvents = CalendarEvent::showPotentialCalendarEventsOfMonth(Carbon::parse('2017-08'));
651 | $this->assertEquals(0, $calendarEvents->count());
652 | }
653 |
654 | /**
655 | * @test
656 | */
657 | public function deleteCalendarEvent_notRecurring_recurring()
658 | {
659 | $inputCreate = [
660 | 'title' => str_random(16),
661 | 'start_datetime' => Carbon::parse('2017-08-25 16:00:00'),
662 | 'end_datetime' => Carbon::parse('2017-08-25 17:00:00'),
663 | 'description' => str_random(32),
664 | 'is_recurring' => false,
665 | 'is_public' => true,
666 | ];
667 | $calendarEvent = $this->calendarEvent->createCalendarEvent($inputCreate);
668 |
669 | $calendarEvent->deleteCalendarEvent(true);
670 |
671 | $this->assertNotNull($calendarEvent->deleted_at);
672 | $this->assertNotNull($calendarEvent->template->deleted_at);
673 | $this->assertNull($calendarEvent->template->end_of_recurring);
674 | }
675 |
676 | /**
677 | * @test
678 | */
679 | public function deleteCalendarEvent_recurring_recurring_generatedEvent()
680 | {
681 | $inputCreate = [
682 | 'title' => str_random(16),
683 | 'start_datetime' => Carbon::parse('2017-08-25 16:00:00'),
684 | 'end_datetime' => Carbon::parse('2017-08-25 17:00:00'),
685 | 'description' => str_random(32),
686 | 'is_recurring' => true,
687 | 'frequence_number_of_recurring' => 1,
688 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
689 | 'is_public' => true,
690 | ];
691 | $calendarEvent = $this->calendarEvent->createCalendarEvent($inputCreate);
692 | $calendarEventNext = $calendarEvent->template->generateNextCalendarEvent(Carbon::parse('2017-08-27'));
693 |
694 | $calendarEvent->deleteCalendarEvent(true);
695 |
696 | $this->assertNotNull($calendarEvent->deleted_at);
697 | $this->assertNotNull($calendarEventNext->fresh()->deleted_at);
698 | $this->assertNotNull($calendarEvent->template->deleted_at);
699 | $this->assertEquals($calendarEvent->start_datetime->format('Y-m-d'), $calendarEvent->template->end_of_recurring->format('Y-m-d'));
700 | }
701 |
702 | /**
703 | * @test
704 | */
705 | public function deleteCalendarEvent_recurring_notRecurring()
706 | {
707 | $inputCreate = [
708 | 'title' => str_random(16),
709 | 'start_datetime' => Carbon::parse('2017-08-25 16:00:00'),
710 | 'end_datetime' => Carbon::parse('2017-08-25 17:00:00'),
711 | 'description' => str_random(32),
712 | 'is_recurring' => true,
713 | 'frequence_number_of_recurring' => 1,
714 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
715 | 'is_public' => true,
716 | ];
717 | $calendarEvent = $this->calendarEvent->createCalendarEvent($inputCreate);
718 | $calendarEvent->deleteCalendarEvent(false);
719 |
720 | $this->assertNotNull($calendarEvent->deleted_at);
721 | $this->assertNull($calendarEvent->template->end_of_recurring);
722 | }
723 |
724 | /**
725 | * @test
726 | */
727 | public function deleteCalendarEvent_recurring_recurring_deleted()
728 | {
729 | $inputCreate = [
730 | 'title' => str_random(16),
731 | 'start_datetime' => Carbon::parse('2017-08-25 16:00:00'),
732 | 'end_datetime' => Carbon::parse('2017-08-25 17:00:00'),
733 | 'description' => str_random(32),
734 | 'is_recurring' => true,
735 | 'frequence_number_of_recurring' => 1,
736 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
737 | 'is_public' => true,
738 | ];
739 | $calendarEvent = $this->calendarEvent->createCalendarEvent($inputCreate);
740 | $calendarEvent->deleteCalendarEvent(true);
741 |
742 | $this->assertNotNull($calendarEvent->deleted_at);
743 | $this->assertNotNull($calendarEvent->template->deleted_at);
744 | $this->assertEquals($calendarEvent->start_datetime->format('Y-m-d'), $calendarEvent->template->end_of_recurring->format('Y-m-d'));
745 | }
746 |
747 | /**
748 | * @test
749 | */
750 | public function deleteCalendarEvent_recurring_recurring_deleted_withoutInput()
751 | {
752 | $inputCreate = [
753 | 'title' => str_random(16),
754 | 'start_datetime' => Carbon::parse('2017-08-25 16:00:00'),
755 | 'end_datetime' => Carbon::parse('2017-08-25 17:00:00'),
756 | 'description' => str_random(32),
757 | 'is_recurring' => true,
758 | 'frequence_number_of_recurring' => 1,
759 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
760 | 'is_public' => true,
761 | ];
762 | $calendarEvent = $this->calendarEvent->createCalendarEvent($inputCreate);
763 | $calendarEvent->deleteCalendarEvent();
764 |
765 | $this->assertNotNull($calendarEvent->deleted_at);
766 | $this->assertNotNull($calendarEvent->template->deleted_at);
767 | $this->assertEquals($calendarEvent->start_datetime->format('Y-m-d'), $calendarEvent->template->end_of_recurring->format('Y-m-d'));
768 | }
769 |
770 | /**
771 | * @test
772 | */
773 | public function deleteCalendarEvent_recurring_recurring_notDeleted()
774 | {
775 | $inputCreate = [
776 | 'title' => str_random(16),
777 | 'start_datetime' => Carbon::parse('2017-08-25 16:00:00'),
778 | 'end_datetime' => Carbon::parse('2017-08-25 17:00:00'),
779 | 'description' => str_random(32),
780 | 'is_recurring' => true,
781 | 'frequence_number_of_recurring' => 1,
782 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
783 | 'is_public' => true,
784 | ];
785 | $calendarEvent = $this->calendarEvent->createCalendarEvent($inputCreate);
786 | $calendarEventNext = $calendarEvent->template->generateNextCalendarEvent(Carbon::now());
787 | $calendarEventNext->deleteCalendarEvent(true);
788 |
789 | $this->assertNull($calendarEvent->deleted_at);
790 | $this->assertNotNull($calendarEventNext->deleted_at);
791 | $this->assertNull($calendarEvent->template->deleted_at);
792 | $this->assertEquals($calendarEventNext->start_datetime->format('Y-m-d'), $calendarEvent->template->end_of_recurring->format('Y-m-d'));
793 | }
794 | }
795 |
--------------------------------------------------------------------------------
/tests/Unit/Models/TemplateCalendarEventTest.php:
--------------------------------------------------------------------------------
1 | templateCalendarEvent = new TemplateCalendarEvent();
38 | $this->calendarEvent = new CalendarEvent();
39 | }
40 |
41 | /**
42 | * Check instance
43 | * @test
44 | */
45 | public function createInstanceFromClass()
46 | {
47 | $this->assertInstanceOf(TemplateCalendarEvent::class, $this->templateCalendarEvent);
48 | }
49 |
50 | /**
51 | * Check fillables
52 | * @test
53 | */
54 | public function getFillable()
55 | {
56 | $expectedFillables = [
57 | 'title',
58 | 'start_datetime',
59 | 'end_datetime',
60 | 'description',
61 | 'is_recurring',
62 | 'end_of_recurring',
63 | 'frequence_number_of_recurring',
64 | 'frequence_type_of_recurring',
65 | 'is_public',
66 | ];
67 |
68 | $this->assertArraySubset($expectedFillables, $this->templateCalendarEvent->getFillable());
69 | }
70 |
71 | /**
72 | * Check relation with calendar_events
73 | * @test
74 | */
75 | public function events()
76 | {
77 | $templateCalendarEvent = factory(TemplateCalendarEvent::class)->create();
78 | $calendarEvent = factory(CalendarEvent::class)->make();
79 | $calendarEvent->template()->associate($templateCalendarEvent);
80 | $calendarEvent->save();
81 |
82 | $this->assertInstanceOf(CalendarEvent::class, $templateCalendarEvent->events()->first());
83 | }
84 |
85 | /**
86 | * Check parent (template_calendar_events)
87 | * @test
88 | */
89 | public function parent()
90 | {
91 | $templateCalendarEvent = factory(TemplateCalendarEvent::class)->create();
92 | $templateCalendarEventChild = factory(TemplateCalendarEvent::class)->create();
93 | $templateCalendarEventChild->parent()->associate($templateCalendarEvent);
94 |
95 | $this->assertInstanceOf(TemplateCalendarEvent::class, $templateCalendarEventChild->parent);
96 | }
97 |
98 | /**
99 | * Check user relation with null
100 | * @test
101 | */
102 | public function user_null()
103 | {
104 | $this->app['config']->set('calendar-event.user.model', null);
105 | $templateCalendarEvent = factory(TemplateCalendarEvent::class)->create();
106 | $user = $templateCalendarEvent->user();
107 |
108 | $this->assertNull($user);
109 | }
110 |
111 | /**
112 | * Check user relation
113 | * @test
114 | */
115 | public function user()
116 | {
117 | $this->app['config']->set('calendar-event.user.model', User::class);
118 | $user = factory(config('calendar-event.user.model'))->create();
119 | $templateCalendarEvent = factory(TemplateCalendarEvent::class)->create();
120 | $templateCalendarEvent->user()->associate($user);
121 |
122 | $this->assertInstanceOf(User::class, $user);
123 | $this->assertInstanceOf(User::class, $templateCalendarEvent->user);
124 | }
125 |
126 | /**
127 | * Check place relation with null
128 | * @test
129 | */
130 | public function place_null()
131 | {
132 | $this->app['config']->set('calendar-event.place.model', null);
133 | $templateCalendarEvent = factory(TemplateCalendarEvent::class)->create();
134 | $place = $templateCalendarEvent->place();
135 |
136 | $this->assertNull($place);
137 | }
138 |
139 | /**
140 | * Check place relation
141 | * @test
142 | */
143 | public function place()
144 | {
145 | $this->app['config']->set('calendar-event.place.model', Place::class);
146 | $place = factory(config('calendar-event.place.model'))->create();
147 | $templateCalendarEvent = factory(TemplateCalendarEvent::class)->create();
148 | $templateCalendarEvent->place()->associate($place);
149 |
150 | $this->assertInstanceOf(Place::class, $place);
151 | $this->assertInstanceOf(Place::class, $templateCalendarEvent->place);
152 | }
153 |
154 | /**
155 | * @test
156 | */
157 | public function scopeRecurring()
158 | {
159 | factory(TemplateCalendarEvent::class)->create([
160 | 'title' => str_random(16),
161 | 'start_datetime' => Carbon::parse('2017-08-29 10:00:00'),
162 | 'end_datetime' => Carbon::parse('2017-08-29 11:00:00'),
163 | 'description' => str_random(32),
164 | 'is_recurring' => false,
165 | 'is_public' => true,
166 | ]);
167 | factory(TemplateCalendarEvent::class)->create([
168 | 'title' => str_random(16),
169 | 'start_datetime' => Carbon::parse('2017-08-29 10:00:00'),
170 | 'end_datetime' => Carbon::parse('2017-08-29 11:00:00'),
171 | 'description' => str_random(32),
172 | 'is_recurring' => true,
173 | 'frequence_number_of_recurring' => 1,
174 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
175 | 'is_public' => true,
176 | ]);
177 |
178 | $templateCalendarEvents = $this->templateCalendarEvent->recurring()->get();
179 |
180 | $this->assertEquals(1, $templateCalendarEvents->count());
181 | $this->assertEquals(true, $templateCalendarEvents->first()->is_recurring);
182 | }
183 |
184 | /**
185 | * @test
186 | */
187 | public function scopePublic()
188 | {
189 | $input = [
190 | 'title' => str_random(16),
191 | 'start_datetime' => Carbon::parse('2017-08-29 10:00:00'),
192 | 'end_datetime' => Carbon::parse('2017-08-29 11:00:00'),
193 | 'description' => str_random(32),
194 | 'is_recurring' => false,
195 | 'is_public' => true,
196 | ];
197 |
198 | factory(TemplateCalendarEvent::class)->create(array_merge($input, ['is_public' => false]));
199 | factory(TemplateCalendarEvent::class)->create($input);
200 | factory(TemplateCalendarEvent::class)->create($input);
201 |
202 | $this->assertEquals(2, $this->templateCalendarEvent->public()->count());
203 | }
204 |
205 | public function dataProvider_for_getNextCalendarEventStartDateTime()
206 | {
207 | return [
208 | [
209 | [
210 | 'title' => str_random(16),
211 | 'start_datetime' => Carbon::parse('2017-08-30 10:00:00'),
212 | 'end_datetime' => Carbon::parse('2017-08-30 11:00:00'),
213 | 'description' => 'Foo bar',
214 | 'is_recurring' => false,
215 | ],
216 | null,
217 | ],
218 | [
219 | [
220 | 'title' => str_random(16),
221 | 'start_datetime' => Carbon::parse('2017-08-30 10:00:00'),
222 | 'end_datetime' => Carbon::parse('2017-08-30 11:00:00'),
223 | 'description' => 'Foo bar',
224 | 'is_recurring' => true,
225 | 'frequence_number_of_recurring' => 1,
226 | 'frequence_type_of_recurring' => RecurringFrequenceType::DAY,
227 | 'is_public' => true,
228 | ],
229 | Carbon::parse('2017-08-30')->addDay(),
230 | ],
231 | [
232 | [
233 | 'title' => str_random(16),
234 | 'start_datetime' => Carbon::parse('2017-08-30 10:00:00'),
235 | 'end_datetime' => Carbon::parse('2017-08-30 11:00:00'),
236 | 'description' => 'Foo bar',
237 | 'is_recurring' => true,
238 | 'frequence_number_of_recurring' => 1,
239 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
240 | 'is_public' => true,
241 | 'end_of_recurring' => Carbon::parse('2017-08-30'),
242 | ],
243 | null,
244 | ],
245 | ];
246 | }
247 |
248 | /**
249 | * @test
250 | * @dataProvider dataProvider_for_getNextCalendarEventStartDateTime
251 | * @param $input
252 | * @param $result
253 | */
254 | public function getNextCalendarEventStartDateTime($input, $result)
255 | {
256 | $calendarEvent = $this->calendarEvent->createCalendarEvent($input);
257 | $startDateTime = $calendarEvent->template->getNextCalendarEventStartDateTime(Carbon::parse($input['start_datetime']->format('Y-m-d')));
258 | $this->assertEquals($result, $startDateTime);
259 | }
260 |
261 | /**
262 | * Data provider for generate next calendar event
263 | * @return array
264 | */
265 | public function dataProvider_for_generateNextCalendarEvent()
266 | {
267 | return [
268 | [Carbon::parse('2017-08-10'), 4, RecurringFrequenceType::DAY, Carbon::parse('2017-08-14')],
269 | [Carbon::parse('2017-08-10'), 2, RecurringFrequenceType::WEEK, Carbon::parse('2017-08-24')],
270 | [Carbon::parse('2017-08-10'), 3, RecurringFrequenceType::MONTH, Carbon::parse('2017-11-10')],
271 | [Carbon::parse('2017-08-10'), 1, RecurringFrequenceType::YEAR, Carbon::parse('2018-08-10')],
272 | ];
273 | }
274 |
275 | /**
276 | * @test
277 | * @dataProvider dataProvider_for_generateNextCalendarEvent
278 | * @param $startDateTime
279 | * @param $frequence_number_of_recurring
280 | * @param $frequence_type_of_recurring
281 | * @param $calendarEventNext_startDateTime
282 | */
283 | public function generateNextCalendarEvent($startDateTime, $frequence_number_of_recurring, $frequence_type_of_recurring, $calendarEventNext_startDateTime)
284 | {
285 | $templateCalendarEvent = factory(TemplateCalendarEvent::class)->create([
286 | 'title' => str_random(16),
287 | 'start_datetime' => $startDateTime,
288 | 'end_datetime' => $startDateTime,
289 | 'description' => str_random(32),
290 | 'is_recurring' => true,
291 | 'frequence_number_of_recurring' => $frequence_number_of_recurring,
292 | 'frequence_type_of_recurring' => $frequence_type_of_recurring,
293 | 'is_public' => true,
294 | ]);
295 | $calendarEvent = factory(CalendarEvent::class)->make(['start_datetime' => $startDateTime]);
296 | $calendarEvent->template()->associate($templateCalendarEvent);
297 | $calendarEvent->save();
298 |
299 | $calendarEventNext = $templateCalendarEvent->generateNextCalendarEvent($startDateTime);
300 |
301 | $this->assertInstanceOf(CalendarEvent::class, $calendarEventNext);
302 | $this->assertInstanceOf(TemplateCalendarEvent::class, $calendarEventNext->template);
303 | $this->assertEquals($calendarEvent->template->id, $calendarEventNext->template->id);
304 | $this->assertEquals($calendarEventNext_startDateTime->format('Y-m-d'), $calendarEventNext->start_datetime->format('Y-m-d'));
305 |
306 | $this->assertDatabaseHas('calendar_events', ['start_datetime' => $calendarEventNext_startDateTime]);
307 | }
308 |
309 | /**
310 | * @test
311 | */
312 | public function createCalendarEvent()
313 | {
314 | $templateCalendarEvent = factory(TemplateCalendarEvent::class)->create();
315 | $startDateTime = Carbon::parse('2017-08-29');
316 | $calendarEvent = $templateCalendarEvent->createCalendarEvent($startDateTime);
317 |
318 | $this->assertInstanceOf(CalendarEvent::class, $calendarEvent);
319 | $this->assertInstanceOf(CalendarEvent::class, $templateCalendarEvent->events->first());
320 | $this->assertEquals($templateCalendarEvent->id, $calendarEvent->template_calendar_event_id);
321 | $this->assertEquals($startDateTime->format('Y-m-d'), $calendarEvent->start_datetime->format('Y-m-d'));
322 |
323 | $this->assertDatabaseHas('calendar_events', ['start_datetime' => $startDateTime]);
324 | }
325 |
326 | /**
327 | * @test
328 | */
329 | public function updateCalendarEvent()
330 | {
331 | $inputCreate = [
332 | 'title' => str_random(16),
333 | 'start_datetime' => Carbon::parse('2017-08-30 10:00:00'),
334 | 'end_datetime' => Carbon::parse('2017-08-30 11:00:00'),
335 | 'description' => str_random(16),
336 | 'is_recurring' => true,
337 | 'frequence_number_of_recurring' => 1,
338 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
339 | 'is_public' => true,
340 | ];
341 | $templateCalendarEvent = factory(TemplateCalendarEvent::class)->create($inputCreate);
342 | $calendarEvent = $templateCalendarEvent->createCalendarEvent(Carbon::parse($inputCreate['start_datetime']));
343 | $startDateTimeNext = $calendarEvent->start_datetime->addWeek();
344 | $calendarEventUpdated = $templateCalendarEvent->updateCalendarEvent($startDateTimeNext, $inputCreate);
345 |
346 | $this->assertNotEquals($templateCalendarEvent->id, $calendarEventUpdated->template->id);
347 | $this->assertDatabaseHas('template_calendar_events', $inputCreate + ['id' => $calendarEventUpdated->template->id]);
348 | }
349 |
350 | /**
351 | * @test
352 | */
353 | public function editCalendarEvent_notExistCalendarEvent()
354 | {
355 | $inputCreate = [
356 | 'title' => str_random(16),
357 | 'start_datetime' => Carbon::parse('2017-08-30 10:00:00'),
358 | 'end_datetime' => Carbon::parse('2017-08-30 11:00:00'),
359 | 'description' => str_random(16),
360 | 'is_recurring' => true,
361 | 'frequence_number_of_recurring' => 1,
362 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
363 | 'is_public' => true,
364 | ];
365 | $inputUpdate = [
366 | 'description' => str_random(16),
367 | ];
368 |
369 | $templateCalendarEvent = factory(TemplateCalendarEvent::class)->create($inputCreate);
370 | $calendarEvent = $templateCalendarEvent->createCalendarEvent(Carbon::parse($inputCreate['start_datetime']));
371 | $startDateTimeNext = $calendarEvent->start_datetime->addWeek();
372 | $calendarEventUpdated = $templateCalendarEvent->editCalendarEvent($startDateTimeNext, $inputUpdate);
373 |
374 | $this->assertInstanceOf(CalendarEvent::class, $calendarEvent);
375 | $this->assertEquals($templateCalendarEvent->id, $calendarEventUpdated->template->parent_id);
376 | $this->assertEquals($templateCalendarEvent->fresh()->end_of_recurring->format('Y-m-d'), $startDateTimeNext->format('Y-m-d'));
377 |
378 | $this->assertDatabaseHas('template_calendar_events', $inputUpdate);
379 | }
380 |
381 | /**
382 | * @test
383 | */
384 | public function editCalendarEvent_existCalendarEvent()
385 | {
386 | $inputCreate = [
387 | 'title' => str_random(16),
388 | 'start_datetime' => Carbon::parse('2017-08-30 10:00:00'),
389 | 'end_datetime' => Carbon::parse('2017-08-30 11:00:00'),
390 | 'description' => 'Foo bar',
391 | 'is_recurring' => true,
392 | 'frequence_number_of_recurring' => 1,
393 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
394 | 'is_public' => true,
395 | ];
396 | $inputUpdate = [
397 | 'description' => str_random(16),
398 | ];
399 |
400 | $templateCalendarEvent = factory(TemplateCalendarEvent::class)->create($inputCreate);
401 | $calendarEvent = $templateCalendarEvent->createCalendarEvent(Carbon::parse($inputCreate['start_datetime']));
402 | $calendarEventUpdated = $templateCalendarEvent->editCalendarEvent($calendarEvent->start_datetime, $inputUpdate);
403 |
404 | $this->assertNotNull($calendarEvent->fresh()->deleted_at);
405 | $this->assertInstanceOf(CalendarEvent::class, $calendarEvent);
406 | $this->assertEquals($templateCalendarEvent->id, $calendarEventUpdated->template->parent_id);
407 | $this->assertEquals($templateCalendarEvent->fresh()->end_of_recurring->format('Y-m-d'), $calendarEvent->start_datetime->format('Y-m-d'));
408 |
409 | $this->assertDatabaseHas('template_calendar_events', $inputUpdate);
410 | }
411 |
412 | /**
413 | * Data provider for generateNextCalendarEvent_notGenerated
414 | * @return array
415 | */
416 | public function dataProvider_for_generateNextCalendarEvent_notGenerated()
417 | {
418 | return [
419 | [
420 | [
421 | 'title' => str_random(16),
422 | 'start_datetime' => Carbon::parse('2017-08-29 10:00:00'),
423 | 'end_datetime' => Carbon::parse('2017-08-29 11:00:00'),
424 | 'description' => str_random(32),
425 | 'is_recurring' => true,
426 | 'frequence_number_of_recurring' => 1,
427 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
428 | 'is_public' => true,
429 | 'end_of_recurring' => '2017-09-04',
430 | ],
431 | ],
432 | [
433 | [
434 | 'title' => str_random(16),
435 | 'start_datetime' => Carbon::parse('2017-08-29 10:00:00'),
436 | 'end_datetime' => Carbon::parse('2017-08-29 11:00:00'),
437 | 'description' => str_random(32),
438 | 'is_recurring' => false,
439 | 'is_public' => true,
440 | ],
441 | ],
442 | ];
443 | }
444 |
445 | /**
446 | * @test
447 | * @dataProvider dataProvider_for_generateNextCalendarEvent_notGenerated
448 | */
449 | public function generateNextCalendarEvent_notGenerated(array $input)
450 | {
451 | $templateCalendarEvent = factory(TemplateCalendarEvent::class)->create($input);
452 | $calendarEvent = factory(CalendarEvent::class)->make(['start_datetime' => $input['start_datetime']]);
453 | $calendarEvent->template()->associate($templateCalendarEvent);
454 | $calendarEvent->save();
455 |
456 | $calendarEventNext = $templateCalendarEvent->generateNextCalendarEvent(Carbon::parse($input['start_datetime']));
457 |
458 | $this->assertNull($calendarEventNext);
459 | }
460 |
461 | /**
462 | * @test
463 | */
464 | public function deleteCalendarEvent_notExist()
465 | {
466 | $inputCreate = [
467 | 'title' => str_random(16),
468 | 'start_datetime' => Carbon::parse('2017-08-25 16:00:00'),
469 | 'end_datetime' => Carbon::parse('2017-08-25 17:00:00'),
470 | 'description' => str_random(32),
471 | 'is_recurring' => true,
472 | 'frequence_number_of_recurring' => 1,
473 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
474 | 'is_public' => true,
475 | ];
476 | $calendarEvent = $this->calendarEvent->createCalendarEvent($inputCreate);
477 | $templateCalendarEvent = $calendarEvent->template;
478 |
479 | $startDateTime = Carbon::parse('2017-09-08');
480 | $isDeleted = $templateCalendarEvent->deleteCalendarEvent($startDateTime);
481 |
482 | $this->assertTrue($isDeleted);
483 | $this->assertNull($calendarEvent->deleted_at);
484 | $this->assertNull($templateCalendarEvent->deleted_at);
485 | $this->assertEquals($startDateTime->format('Y-m-d'), $templateCalendarEvent->end_of_recurring->format('Y-m-d'));
486 | }
487 |
488 | /**
489 | * @test
490 | */
491 | public function deleteCalendarEvent_exist()
492 | {
493 | $startDateTime = Carbon::parse('2017-08-25');
494 | $inputCreate = [
495 | 'title' => str_random(16),
496 | 'start_datetime' => $startDateTime,
497 | 'end_datetime' => $startDateTime,
498 | 'description' => str_random(32),
499 | 'is_recurring' => true,
500 | 'frequence_number_of_recurring' => 1,
501 | 'frequence_type_of_recurring' => RecurringFrequenceType::WEEK,
502 | 'is_public' => true,
503 | ];
504 |
505 | $calendarEvent = $this->calendarEvent->createCalendarEvent($inputCreate);
506 | $templateCalendarEvent = $calendarEvent->template;
507 | $isDeleted = $templateCalendarEvent->deleteCalendarEvent($startDateTime);
508 |
509 | $this->assertTrue($isDeleted);
510 | $this->assertNotNull($calendarEvent->fresh()->deleted_at);
511 | $this->assertNotNull($templateCalendarEvent->fresh()->deleted_at);
512 | $this->assertEquals($startDateTime->format('Y-m-d'), $templateCalendarEvent->fresh()->end_of_recurring->format('Y-m-d'));
513 | }
514 | }
515 |
--------------------------------------------------------------------------------
/tests/Unit/Traits/CalendarEventPlaceTraitTest.php:
--------------------------------------------------------------------------------
1 | calendarEvents();
22 | $this->assertInstanceOf(\Illuminate\Database\Eloquent\Relations\HasManyThrough::class, $events);
23 | }
24 | }
--------------------------------------------------------------------------------
/tests/Unit/Traits/CalendarEventUserTraitTest.php:
--------------------------------------------------------------------------------
1 | calendarEvents();
22 | $this->assertInstanceOf(\Illuminate\Database\Eloquent\Relations\HasManyThrough::class, $events);
23 | }
24 | }
--------------------------------------------------------------------------------
/tests/Unit/config/ConfigTest.php:
--------------------------------------------------------------------------------
1 | [
17 | "model" => null
18 | ],
19 | "place" => [
20 | "model" => null
21 | ]
22 | ];
23 | $path = __DIR__ . '/../../../src/config/calendar-event.php';
24 |
25 | $this->assertFileExists($path);
26 | $this->assertEquals(include $path, $config);
27 | }
28 | }
--------------------------------------------------------------------------------
/tests/fixtures/Models/Place.php:
--------------------------------------------------------------------------------
1 | make(\Illuminate\Database\Eloquent\Factory::class);
7 |
8 | /** @var \Illuminate\Database\Eloquent\Factory $factory */
9 | $factory->define(Place::class, function (Faker $faker) {
10 | return [
11 | 'name' => $faker->name(),
12 | 'address' => $faker->address,
13 | ];
14 | });
--------------------------------------------------------------------------------
/tests/fixtures/database/factories/UserFactory.php:
--------------------------------------------------------------------------------
1 | make(\Illuminate\Database\Eloquent\Factory::class);
7 |
8 | /** @var \Illuminate\Database\Eloquent\Factory $factory */
9 | $factory->define(User::class, function (Faker $faker) {
10 | return [
11 | 'name' => $faker->name(),
12 | 'email' => $faker->email
13 | ];
14 | });
--------------------------------------------------------------------------------
/tests/fixtures/database/migrations/2017_09_08_064317_create_places_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
21 | $table->string('name');
22 | $table->text('address');
23 | $table->timestamps();
24 | });
25 | }
26 |
27 | /**
28 | * Reverse the migrations.
29 | *
30 | * @return void
31 | */
32 | public function down()
33 | {
34 | Schema::dropIfExists('places');
35 | }
36 | }
--------------------------------------------------------------------------------
/tests/fixtures/database/migrations/2017_09_08_064448_create_users_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
21 | $table->string('name');
22 | $table->string('email')->unique();
23 | $table->timestamps();
24 | });
25 | }
26 |
27 | /**
28 | * Reverse the migrations.
29 | *
30 | * @return void
31 | */
32 | public function down()
33 | {
34 | Schema::dropIfExists('users');
35 | }
36 | }
--------------------------------------------------------------------------------