1 | <?php |
||
2 | |||
3 | namespace NotificationTracker\Models; |
||
4 | |||
5 | use Carbon\Carbon; |
||
6 | use Illuminate\Database\Eloquent\Factories\HasFactory; |
||
7 | use Illuminate\Database\Eloquent\Model; |
||
8 | use Illuminate\Database\Eloquent\Relations\BelongsTo; |
||
9 | use Illuminate\Notifications\Notification; |
||
10 | use Illuminate\Support\Str; |
||
11 | use JsonFieldCast\Casts\SimpleJsonField; |
||
12 | use NotificationTracker\Database\Factories\TrackedChannelFactory; |
||
13 | use NotificationTracker\Notification\Trackable; |
||
14 | use NotificationTracker\NotificationTracker; |
||
15 | |||
16 | /** |
||
17 | * @property \JsonFieldCast\Json\SimpleJsonField $stats |
||
18 | * @property \JsonFieldCast\Json\SimpleJsonField $meta |
||
19 | */ |
||
20 | class TrackedChannel extends Model |
||
21 | { |
||
22 | use HasFactory; |
||
23 | |||
24 | protected $guarded = []; |
||
25 | |||
26 | protected $casts = [ |
||
27 | 'sent_at' => 'datetime', |
||
28 | 'first_open_at' => 'datetime', |
||
29 | 'last_open_at' => 'datetime', |
||
30 | 'open_count' => 'integer', |
||
31 | 'first_click_at' => 'datetime', |
||
32 | 'last_click_at' => 'datetime', |
||
33 | 'click_count' => 'integer', |
||
34 | 'stats' => SimpleJsonField::class, |
||
35 | 'meta' => SimpleJsonField::class, |
||
36 | ]; |
||
37 | |||
38 | 12 | public function getTable(): string |
|
39 | { |
||
40 | 12 | return config('notification-tracker.tables.channels'); |
|
41 | } |
||
42 | |||
43 | 13 | protected static function boot(): void |
|
44 | { |
||
45 | 13 | parent::boot(); |
|
46 | |||
47 | 13 | static::saving(function ($model) { |
|
48 | 9 | if (!$model->uuid) { |
|
49 | 9 | $model->uuid = (string)Str::uuid(); |
|
50 | } |
||
51 | 9 | if (!$model->sent_at) { |
|
52 | 6 | $model->sent_at = Carbon::now(); |
|
53 | } |
||
54 | 13 | }); |
|
55 | } |
||
56 | |||
57 | 5 | protected static function newFactory(): TrackedChannelFactory |
|
58 | { |
||
59 | 5 | return TrackedChannelFactory::new(); |
|
60 | } |
||
61 | |||
62 | 8 | public function getTrackerId(): string |
|
63 | { |
||
64 | 8 | if (!$this->uuid) { |
|
65 | 1 | $this->uuid = Str::uuid(); |
|
0 ignored issues
–
show
|
|||
66 | } |
||
67 | |||
68 | 8 | return (string)$this->uuid; |
|
69 | } |
||
70 | |||
71 | 6 | public function notification(): BelongsTo |
|
72 | { |
||
73 | 6 | return $this->belongsTo(NotificationTracker::modelClass('notification'), 'notification_id', 'id'); |
|
74 | } |
||
75 | |||
76 | 7 | public function scopeUuid($query, string $uuid) |
|
77 | { |
||
78 | 7 | return $query->where('uuid', $uuid); |
|
79 | } |
||
80 | |||
81 | 4 | public function getPixelImageUrl(): string |
|
82 | { |
||
83 | 4 | return route('notification-tracker.pixel', $this->getTrackerId()); |
|
84 | } |
||
85 | |||
86 | 1 | public function getClickTrackerUrl(?string $url = null): string |
|
87 | { |
||
88 | 1 | return route('notification-tracker.click', [ |
|
89 | 1 | $this->getTrackerId(), |
|
90 | 1 | NotificationTracker::clickTrackerUrlParameterName() => $url ?: url('/'), |
|
91 | 1 | ]); |
|
92 | } |
||
93 | |||
94 | 3 | public function getPixelImageHtml(): string |
|
95 | { |
||
96 | 3 | return sprintf( |
|
97 | 3 | '<img src="%s" style="display:block;height:0px;width:0px;max-width:0px;max-height:0px;overflow:hidden" width="1" height="1" border="0" alt="">', |
|
98 | 3 | $this->getPixelImageUrl(), |
|
99 | 3 | ); |
|
100 | } |
||
101 | |||
102 | 1 | public function incrementOpen(?Carbon $date = null): static |
|
103 | { |
||
104 | 1 | $date = $date ?? Carbon::now(); |
|
105 | 1 | if (!$this->first_open_at) { |
|
106 | 1 | $this->first_open_at = $date; |
|
0 ignored issues
–
show
|
|||
107 | } |
||
108 | |||
109 | 1 | return $this->fill([ |
|
110 | 1 | 'last_open_at' => $date, |
|
111 | 1 | 'open_count' => $this->open_count + 1, |
|
0 ignored issues
–
show
|
|||
112 | 1 | ]); |
|
113 | } |
||
114 | |||
115 | 1 | public function incrementClick(?Carbon $date = null): static |
|
116 | { |
||
117 | 1 | $date = $date ?? Carbon::now(); |
|
118 | 1 | if (!$this->first_click_at) { |
|
119 | 1 | $this->first_click_at = $date; |
|
0 ignored issues
–
show
|
|||
120 | } |
||
121 | |||
122 | 1 | return $this->fill([ |
|
123 | 1 | 'last_click_at' => $date, |
|
124 | 1 | 'click_count' => $this->click_count + 1, |
|
0 ignored issues
–
show
|
|||
125 | 1 | ]); |
|
126 | } |
||
127 | |||
128 | 2 | public function resendNotification(): bool |
|
129 | { |
||
130 | 2 | if (!$this->notification) { |
|
0 ignored issues
–
show
|
|||
131 | return false; |
||
132 | } |
||
133 | 2 | $channel = $this->channel; |
|
0 ignored issues
–
show
|
|||
134 | 2 | $route = unserialize($this->route); |
|
0 ignored issues
–
show
|
|||
135 | 2 | $notification = unserialize($this->notification->data); |
|
136 | |||
137 | if ( |
||
138 | 2 | !$channel || |
|
139 | 2 | !$route || |
|
140 | 2 | !($notification instanceof Notification) || |
|
141 | 2 | !($notification instanceof Trackable) |
|
142 | ) { |
||
143 | return false; |
||
144 | } |
||
145 | |||
146 | try { |
||
147 | 2 | \Illuminate\Support\Facades\Notification::route($channel, $route) |
|
148 | 2 | ->notify( |
|
149 | 2 | $notification |
|
150 | 2 | ->trackerMeta(function (\JsonFieldCast\Json\SimpleJsonField $meta, TrackedChannel $trackedChannel) { |
|
151 | 2 | $meta->toMorph('sent_from_parent', $this); |
|
152 | 2 | }) |
|
153 | 2 | ->trackerMeta(function (\JsonFieldCast\Json\SimpleJsonField $meta, TrackedChannel $trackedChannel) { |
|
154 | 2 | $meta->setData(array_merge( |
|
155 | 2 | $this->meta->getRawData(), |
|
156 | 2 | $meta->getRawData(), |
|
157 | 2 | )); |
|
158 | 2 | }) |
|
159 | 2 | ->notificationMeta(function (\JsonFieldCast\Json\SimpleJsonField $meta, TrackedNotification $trackedNotification) { |
|
160 | 2 | $meta->setData(array_merge( |
|
161 | 2 | $this->notification->meta->getRawData(), |
|
0 ignored issues
–
show
|
|||
162 | 2 | $meta->getRawData(), |
|
163 | 2 | )); |
|
164 | 2 | }) |
|
165 | 2 | ); |
|
166 | } catch (\Exception $e) { |
||
167 | return false; |
||
168 | } |
||
169 | |||
170 | 2 | return true; |
|
171 | } |
||
172 | |||
173 | 1 | public function resendNotOpenedNotification(int|Carbon $waitSeconds = 2 * 24 * 60 * 60): bool |
|
174 | { |
||
175 | 1 | if (!$this->sent_at) { |
|
176 | return false; |
||
177 | } |
||
178 | 1 | if (!($waitSeconds instanceof Carbon)) { |
|
179 | 1 | $waitSeconds = $this->sent_at->addSeconds($waitSeconds); |
|
180 | } |
||
181 | |||
182 | 1 | if ($waitSeconds->greaterThan(Carbon::now())) { |
|
183 | 1 | return false; |
|
184 | } |
||
185 | |||
186 | 1 | return $this->resendNotification(); |
|
187 | } |
||
188 | } |
||
189 |
Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.