Skip to content

Commit dcc810a

Browse files
authored
Merge pull request #54 from falestra/hotfix/custom-polymorphic-types
hotfix: use getMorphClass for custom polymorphic types
2 parents f34998f + fb5a0d8 commit dcc810a

File tree

11 files changed

+49
-28
lines changed

11 files changed

+49
-28
lines changed

README.md

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,32 @@ Zap is a comprehensive calendar and scheduling system for Laravel. Manage availa
3232

3333
**Requirements:** PHP ≤8.5 • Laravel ≤12.0
3434

35+
You can install the package via composer:
36+
3537
```bash
3638
composer require laraveljutsu/zap
37-
php artisan vendor:publish --tag=zap-migrations
39+
```
40+
41+
You should publish the migration and the `config/zap.php` config file with:
42+
43+
```bash
44+
php artisan vendor:publish --provider="Zap\ZapServiceProvider"
45+
```
46+
47+
### Before Running Migrations
48+
49+
**If you are USING UUIDs**, see the [Custom Model Support](#custom-model-support) section of the docs on UUID steps, before you continue. It explains some changes you may want to make to the migrations and config file before continuing. It also mentions important considerations after extending this package's models for UUID capability.
50+
51+
If so, run the migration command:
52+
53+
```bash
3854
php artisan migrate
3955
```
4056

57+
### Note for Apps Using UUIDs/ULIDs/GUIDs
58+
59+
This package expects the primary key of your models to be an auto-incrementing int. If it is not, you may need to modify the `create_schedules_table` and `create_schedule_periods_table` migration and/or modify the default configuration. See [Custom Model Support](#custom-model-support) for more information.
60+
4161
### Setup Your Models
4262

4363
Add the `HasSchedules` trait to any Eloquent model you want to make schedulable:
@@ -51,14 +71,6 @@ class Doctor extends Model
5171
}
5272
```
5373

54-
### Note for Apps Using UUIDs/ULIDs/GUIDs
55-
56-
This package expects the primary key of your models to be an auto-incrementing int. If it is not, you may need to modify the `create_schedules_table` and `create_schedule_periods_table` migration and/or modify the default configuration. See [Custom Model Support](#custom-model-support) for more information.
57-
58-
### Before Running Migrations
59-
60-
**If you are USING UUIDs**, see the [Custom Model Support](#custom-model-support) section of the docs on UUID steps, before you continue. It explains some changes you may want to make to the migrations and config file before continuing. It also mentions important considerations after extending this package's models for UUID capability.
61-
6274
---
6375

6476
## 🧩 Core Concepts

src/Models/Concerns/HasSchedules.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ public function isAvailableAt(string $date, string $startTime, string $endTime,
156156
E_USER_DEPRECATED
157157
);
158158
// Get all active schedules for this model on this date
159-
$schedules = $schedules ?? $this->getScheduleClass()::where('schedulable_type', get_class($this))
159+
$schedules = $schedules ?? $this->getScheduleClass()::where('schedulable_type', $this->getMorphClass())
160160
->where('schedulable_id', $this->getKey())
161161
->active()
162162
->forDate($date)
@@ -318,7 +318,7 @@ public function getAvailableSlots(
318318
$iterations = 0;
319319
$slotInterval = $slotDuration + $bufferMinutes;
320320

321-
$schedules = $this->getScheduleClass()::where('schedulable_type', get_class($this))
321+
$schedules = $this->getScheduleClass()::where('schedulable_type', $this->getMorphClass())
322322
->where('schedulable_id', $this->getKey())
323323
->active()
324324
->forDate($date)
@@ -501,7 +501,7 @@ protected function getAvailabilityPeriodsForDate(string $date): \Illuminate\Supp
501501
$checkDate = \Carbon\Carbon::parse($date);
502502

503503
// Get all availability schedules for this date
504-
$availabilitySchedules = $this->getScheduleClass()::where('schedulable_type', get_class($this))
504+
$availabilitySchedules = $this->getScheduleClass()::where('schedulable_type', $this->getMorphClass())
505505
->where('schedulable_id', $this->getKey())
506506
->availability()
507507
->active()
@@ -543,7 +543,7 @@ protected function getAvailabilityPeriodsForDate(string $date): \Illuminate\Supp
543543
*/
544544
protected function getBlockingSchedulesForDate(string $date): \Illuminate\Support\Collection
545545
{
546-
return $this->getScheduleClass()::where('schedulable_type', get_class($this))
546+
return $this->getScheduleClass()::where('schedulable_type', $this->getMorphClass())
547547
->where('schedulable_id', $this->getKey())
548548
->whereIn('schedule_type', [
549549
ScheduleTypes::APPOINTMENT->value,

src/Services/ConflictDetectionService.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public function findSchedulableConflicts(Model $schedulable, \Zap\Models\Schedul
9999
{
100100
// Create a temporary schedule for conflict checking
101101
$tempSchedule = new $this->scheduleClass([
102-
'schedulable_type' => get_class($schedulable),
102+
'schedulable_type' => $schedulable->getMorphClass(),
103103
'schedulable_id' => $schedulable->getKey(),
104104
'start_date' => $schedule->start_date,
105105
'end_date' => $schedule->end_date,
@@ -355,7 +355,7 @@ public function findPeriodConflicts(
355355
string $startTime,
356356
string $endTime
357357
): Collection {
358-
return $this->scheduleClass::where('schedulable_type', get_class($schedulable))
358+
return $this->scheduleClass::where('schedulable_type', $schedulable->getMorphClass())
359359
->where('schedulable_id', $schedulable->getKey())
360360
->active()
361361
->forDate($date)

src/Services/ScheduleService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public function create(
4242

4343
// Create the schedule
4444
$schedule = new $this->scheduleClass($attributes);
45-
$schedule->schedulable_type = get_class($schedulable);
45+
$schedule->schedulable_type = $schedulable->getMorphClass();
4646
$schedule->schedulable_id = $schedulable->getKey();
4747
$schedule->save();
4848

src/Services/ValidationService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ protected function validateNoOverlap($config, Model $schedulable, array $attribu
547547

548548
// Create a temporary schedule for conflict checking
549549
$tempSchedule = new $this->scheduleClass([
550-
'schedulable_type' => get_class($schedulable),
550+
'schedulable_type' => $schedulable->getMorphClass(),
551551
'schedulable_id' => $schedulable->getKey(),
552552
'start_date' => $attributes['start_date'],
553553
'end_date' => $attributes['end_date'] ?? null,

tests/Feature/ComprehensiveUseCasesTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,7 @@
10251025
// Create the schedule object without saving to check conflicts
10261026
// Use the same approach as ValidationService
10271027
$tempSchedule = new Schedule([
1028-
'schedulable_type' => get_class($user),
1028+
'schedulable_type' => $user->getMorphClass(),
10291029
'schedulable_id' => $user->getKey(),
10301030
'start_date' => $newSchedule['attributes']['start_date'],
10311031
'end_date' => $newSchedule['attributes']['end_date'] ?? null,
@@ -1071,7 +1071,7 @@
10711071

10721072
// Create the schedule object without saving to check conflicts
10731073
$tempSchedule = new Schedule($schedule['attributes']);
1074-
$tempSchedule->schedulable_type = get_class($user);
1074+
$tempSchedule->schedulable_type = $user->getMorphClass();
10751075
$tempSchedule->schedulable_id = $user->getKey();
10761076
$tempSchedule->setRelation('periods', collect($schedule['periods'])->map(function ($period) {
10771077
return new \Zap\Models\SchedulePeriod($period);
@@ -1101,7 +1101,7 @@
11011101
// Create the schedule object without saving to check conflicts
11021102
// Use the same approach as ValidationService
11031103
$tempSchedule = new Schedule([
1104-
'schedulable_type' => get_class($user),
1104+
'schedulable_type' => $user->getMorphClass(),
11051105
'schedulable_id' => $user->getKey(),
11061106
'start_date' => $newSchedule['attributes']['start_date'],
11071107
'end_date' => $newSchedule['attributes']['end_date'] ?? null,
@@ -1148,7 +1148,7 @@
11481148
// Create the schedule object without saving to check conflicts
11491149
// Use the same approach as ValidationService
11501150
$tempSchedule = new Schedule([
1151-
'schedulable_type' => get_class($user),
1151+
'schedulable_type' => $user->getMorphClass(),
11521152
'schedulable_id' => $user->getKey(),
11531153
'start_date' => $newSchedule['attributes']['start_date'],
11541154
'end_date' => $newSchedule['attributes']['end_date'] ?? null,

tests/Feature/ConflictDetectionTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@
127127

128128
// Create a new appointment schedule that overlaps with both
129129
$newSchedule = new Schedule([
130-
'schedulable_type' => get_class($user),
130+
'schedulable_type' => $user->getMorphClass(),
131131
'schedulable_id' => $user->getKey(),
132132
'start_date' => '2025-01-01',
133133
'name' => 'Conflicting Meeting',

tests/Feature/DocumentationExamplesTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@
241241
expect($availability->id)->not->toBeNull();
242242
// Verify the schedule is associated with the doctor
243243
expect($availability->schedulable_id)->toBe($doctor->getKey());
244-
expect($availability->schedulable_type)->toBe(get_class($doctor));
244+
expect($availability->schedulable_type)->toBe($doctor->getMorphClass());
245245

246246
// Create appointment on a different date to avoid conflicts
247247
// Verify it was saved successfully
@@ -255,7 +255,7 @@
255255
expect($appointment->schedule_type->value)->toBe('appointment');
256256
// Verify the appointment is associated with the doctor
257257
expect($appointment->schedulable_id)->toBe($doctor->getKey());
258-
expect($appointment->schedulable_type)->toBe(get_class($doctor));
258+
expect($appointment->schedulable_type)->toBe($doctor->getMorphClass());
259259

260260
// Get schedules for a date (forDate scope filters by date range and recurrence)
261261
// Note: forDate works for recurring schedules, for non-recurring it checks if date is within range

tests/Feature/ScheduleManagementTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,8 +314,8 @@
314314
->addPeriod('11:00', '12:00')
315315
->save();
316316

317-
expect($userSchedule->schedulable_type)->toBe('Zap\Tests\ZapTestUser');
318-
expect($roomSchedule->schedulable_type)->toBe('Zap\Tests\ZapTestRoom');
317+
expect($userSchedule->schedulable_type)->toBe('users');
318+
expect($roomSchedule->schedulable_type)->toBe('rooms');
319319
expect($userSchedule->schedulable_id)->toBe($user->getKey());
320320
expect($roomSchedule->schedulable_id)->toBe($room->getKey());
321321
});

tests/Feature/WeeklyOddEven/ConflictDetectionTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@
124124
// Create a new appointment schedule that overlaps only Meeting 2.
125125
// Because 'Weekly-Even Meeting' is in even weeks
126126
$newSchedule = new Schedule([
127-
'schedulable_type' => get_class($user),
127+
'schedulable_type' => $user->getMorphClass(),
128128
'schedulable_id' => $user->getKey(),
129129
'start_date' => '2025-01-01',
130130
'name' => 'Conflicting Meeting',
@@ -168,7 +168,7 @@
168168
// Create a new appointment schedule that overlaps only Meeting 2.
169169
// Because 'Weekly-Odd Meeting' is in odd weeks
170170
$newSchedule = new Schedule([
171-
'schedulable_type' => get_class($user),
171+
'schedulable_type' => $user->getMorphClass(),
172172
'schedulable_id' => $user->getKey(),
173173
'start_date' => '2025-01-06',
174174
'name' => 'Conflicting Meeting',

0 commit comments

Comments
 (0)