 ARCANEDEV    /
                    LaravelMessenger
                      ARCANEDEV    /
                    LaravelMessenger
                
                            This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
                                via PHP's auto-loading mechanism.
                                                    These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php | ||
| 2 | |||
| 3 | declare(strict_types=1); | ||
| 4 | |||
| 5 | namespace Arcanedev\LaravelMessenger\Models; | ||
| 6 | |||
| 7 | use Arcanedev\LaravelMessenger\Contracts\Discussion as DiscussionContract; | ||
| 8 | use Arcanedev\LaravelMessenger\Contracts\Message as MessageContract; | ||
| 9 | use Arcanedev\LaravelMessenger\Contracts\Participation as ParticipationContract; | ||
| 10 | use Illuminate\Database\Eloquent\Builder; | ||
| 11 | use Illuminate\Database\Eloquent\Model as EloquentModel; | ||
| 12 | use Illuminate\Support\Carbon; | ||
| 13 | use Illuminate\Support\Collection; | ||
| 14 | |||
| 15 | /** | ||
| 16 | * Class Discussion | ||
| 17 | * | ||
| 18 | * @package Arcanedev\LaravelMessenger\Models | ||
| 19 | * @author ARCANEDEV <[email protected]> | ||
| 20 | * | ||
| 21 | * @property int id | ||
| 22 | * @property string subject | ||
| 23 | * @property \Illuminate\Support\Carbon created_at | ||
| 24 | * @property \Illuminate\Support\Carbon updated_at | ||
| 25 | * @property \Illuminate\Support\Carbon deleted_at | ||
| 26 | * | ||
| 27 | * @property \Illuminate\Database\Eloquent\Model creator | ||
| 28 | * @property \Illuminate\Database\Eloquent\Collection messages | ||
| 29 | * @property \Illuminate\Database\Eloquent\Collection participations | ||
| 30 | * @property \Arcanedev\LaravelMessenger\Models\Message latest_message | ||
| 31 | * | ||
| 32 | * @method static \Illuminate\Database\Eloquent\Builder|static subject(string $subject, bool $strict) | ||
| 33 | * @method static \Illuminate\Database\Eloquent\Builder|static between(\Illuminate\Support\Collection|array $participables) | ||
| 34 | * @method static \Illuminate\Database\Eloquent\Builder|static forUser(\Illuminate\Database\Eloquent\Model|mixed $participable) | ||
| 35 | * @method static \Illuminate\Database\Eloquent\Builder|static forUserWithNewMessages(\Illuminate\Database\Eloquent\Model|mixed $participable) | ||
| 36 | */ | ||
| 37 | class Discussion extends Model implements DiscussionContract | ||
| 38 | { | ||
| 39 | /* ----------------------------------------------------------------- | ||
| 40 | | Properties | ||
| 41 | | ----------------------------------------------------------------- | ||
| 42 | */ | ||
| 43 | |||
| 44 | /** | ||
| 45 | * The attributes that can be set with Mass Assignment. | ||
| 46 | * | ||
| 47 | * @var array | ||
| 48 | */ | ||
| 49 | protected $fillable = ['subject']; | ||
| 50 | |||
| 51 | /** | ||
| 52 | * The attributes that should be mutated to dates. | ||
| 53 | * | ||
| 54 | * @var array | ||
| 55 | */ | ||
| 56 | protected $dates = ['deleted_at']; | ||
| 57 | |||
| 58 | /** | ||
| 59 | * The attributes that should be cast to native types. | ||
| 60 | * | ||
| 61 | * @var array | ||
| 62 | */ | ||
| 63 | protected $casts = [ | ||
| 64 | 'id' => 'integer', | ||
| 65 | ]; | ||
| 66 | |||
| 67 | /* ----------------------------------------------------------------- | ||
| 68 | | Constructor | ||
| 69 | | ----------------------------------------------------------------- | ||
| 70 | */ | ||
| 71 | |||
| 72 | /** | ||
| 73 | * Create a new Eloquent model instance. | ||
| 74 | * | ||
| 75 | * @param array $attributes | ||
| 76 | */ | ||
| 77 | 240 | public function __construct(array $attributes = []) | |
| 78 |     { | ||
| 79 | 240 | $this->setTable( | |
| 80 | 240 |             config('messenger.discussions.table', 'discussions') | |
| 81 | ); | ||
| 82 | |||
| 83 | 240 | parent::__construct($attributes); | |
| 84 | 240 | } | |
| 85 | |||
| 86 | /* ----------------------------------------------------------------- | ||
| 87 | | Relationships | ||
| 88 | | ----------------------------------------------------------------- | ||
| 89 | */ | ||
| 90 | |||
| 91 | /** | ||
| 92 | * Participants relationship. | ||
| 93 | * | ||
| 94 | * @return \Illuminate\Database\Eloquent\Relations\HasMany | ||
| 95 | */ | ||
| 96 | 168 | public function participations() | |
| 97 |     { | ||
| 98 | 168 | return $this->hasMany( | |
| 99 | 168 |             config('messenger.participations.model', Participation::class) | |
| 100 | ); | ||
| 101 | } | ||
| 102 | |||
| 103 | /** | ||
| 104 | * Messages relationship. | ||
| 105 | * | ||
| 106 | * @return \Illuminate\Database\Eloquent\Relations\HasMany | ||
| 107 | */ | ||
| 108 | 66 | public function messages() | |
| 109 |     { | ||
| 110 | 66 | return $this->hasMany( | |
| 111 | 66 |             config('messenger.messages.model', Message::class) | |
| 112 | ); | ||
| 113 | } | ||
| 114 | |||
| 115 | /** | ||
| 116 | * Get the participable that created the first message. | ||
| 117 | * | ||
| 118 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo | ||
| 119 | */ | ||
| 120 | 6 | public function creator() | |
| 121 |     { | ||
| 122 | 6 | return $this->messages()->oldest()->first()->author(); | |
| 123 | } | ||
| 124 | |||
| 125 | /* ----------------------------------------------------------------- | ||
| 126 | | Scopes | ||
| 127 | | ----------------------------------------------------------------- | ||
| 128 | */ | ||
| 129 | |||
| 130 | /** | ||
| 131 | * Scope discussions that the participable is associated with. | ||
| 132 | * | ||
| 133 | * @param \Illuminate\Database\Eloquent\Builder $query | ||
| 134 | * @param \Illuminate\Database\Eloquent\Model $participable | ||
| 135 | * | ||
| 136 | * @return \Illuminate\Database\Eloquent\Builder|static | ||
| 137 | */ | ||
| 138 | 12 | public function scopeForUser(Builder $query, EloquentModel $participable) | |
| 139 |     { | ||
| 140 | 12 | $table = $this->getParticipationsTable(); | |
| 141 | 12 |         $morph = config('messenger.users.morph', 'participable'); | |
| 142 | |||
| 143 | return $query | ||
| 144 | 12 |             ->join($table, $this->getQualifiedKeyName(), '=', "{$table}.discussion_id") | |
| 145 | 12 |             ->where("{$table}.{$morph}_type", '=', $participable->getMorphClass()) | |
| 146 | 12 |             ->where("{$table}.{$morph}_id", '=', $participable->getKey()) | |
| 147 | 12 |             ->whereNull("{$table}.deleted_at") | |
| 148 | 12 |             ->select("{$this->getTable()}.*"); | |
| 149 | } | ||
| 150 | |||
| 151 | /** | ||
| 152 | * Scope discussions with new messages that the participable is associated with. | ||
| 153 | * | ||
| 154 | * @param \Illuminate\Database\Eloquent\Builder $query | ||
| 155 | * @param \Illuminate\Database\Eloquent\Model $participable | ||
| 156 | * | ||
| 157 | * @return \Illuminate\Database\Eloquent\Builder|static | ||
| 158 | */ | ||
| 159 | 6 | public function scopeForUserWithNewMessages(Builder $query, EloquentModel $participable) | |
| 160 |     { | ||
| 161 | 6 | $prefix = $this->getConnection()->getTablePrefix(); | |
| 162 | 6 | $participations = $this->getParticipationsTable(); | |
| 163 | 6 | $discussions = $this->getTable(); | |
| 164 | |||
| 165 | 6 | return $this->scopeForUser($query, $participable) | |
| 0 ignored issues–
                            show | |||
| 166 |                     ->where(function (Builder $query) use ($participations, $discussions, $prefix) { | ||
| 167 | 6 |                         $expression = $this->getConnection()->raw("{$prefix}{$participations}.last_read"); | |
| 168 | |||
| 169 | 6 |                         $query->where("{$discussions}.updated_at", '>', $expression) | |
| 170 | 6 |                               ->orWhereNull("{$participations}.last_read"); | |
| 171 | 6 | }); | |
| 172 | } | ||
| 173 | |||
| 174 | /** | ||
| 175 | * Scope discussions between given participables. | ||
| 176 | * | ||
| 177 | * @param \Illuminate\Database\Eloquent\Builder $query | ||
| 178 | * @param \Illuminate\Support\Collection|array $participables | ||
| 179 | * | ||
| 180 | * @return \Illuminate\Database\Eloquent\Builder|static | ||
| 181 | */ | ||
| 182 | 6 | public function scopeBetween(Builder $query, $participables) | |
| 183 |     { | ||
| 184 |         return $query->whereHas($this->getParticipationsTable(), function (Builder $query) use ($participables) { | ||
| 0 ignored issues–
                            show The expression  $query->whereHas($this->...t($participables)); });of typeIlluminate\Database\Eloq...ns\QueriesRelationshipsadds the typeIlluminate\Database\Eloq...ns\QueriesRelationshipsto the return on line 184 which is incompatible with the return type declared by the interfaceArcanedev\LaravelMesseng...iscussion::scopeBetweenof typeIlluminate\Database\Eloquent\Builder. Loading history... | |||
| 185 | 6 |             $morph = config('messenger.users.morph', 'participable'); | |
| 186 | 6 | $index = 0; | |
| 187 | |||
| 188 | 6 |             foreach ($participables as $participable) { | |
| 189 | /** @var \Illuminate\Database\Eloquent\Model $participable */ | ||
| 190 | $clause = [ | ||
| 191 | 6 |                     ["{$morph}_type", '=', $participable->getMorphClass()], | |
| 192 | 6 |                     ["{$morph}_id", '=', $participable->getKey()], | |
| 193 | ]; | ||
| 194 | |||
| 195 | 6 | $query->where($clause, null, null, $index === 0 ? 'and' : 'or'); | |
| 196 | |||
| 197 | 6 | $index++; | |
| 198 | } | ||
| 199 | |||
| 200 | 6 |             $query->groupBy('discussion_id') | |
| 201 | 6 |                   ->havingRaw('COUNT(discussion_id)='.count($participables)); | |
| 202 | 6 | }); | |
| 203 | } | ||
| 204 | |||
| 205 | /** | ||
| 206 | * Scope the query by the subject. | ||
| 207 | * | ||
| 208 | * @param \Illuminate\Database\Eloquent\Builder $query | ||
| 209 | * @param string $subject | ||
| 210 | * @param bool $strict | ||
| 211 | * | ||
| 212 | * @return \Illuminate\Database\Eloquent\Builder|static | ||
| 213 | */ | ||
| 214 | 12 | public function scopeSubject(Builder $query, $subject, $strict = false) | |
| 215 |     { | ||
| 216 | 12 |         return $query->where('subject', 'like', $strict ? $subject : "%{$subject}%"); | |
| 217 | } | ||
| 218 | |||
| 219 | /* ----------------------------------------------------------------- | ||
| 220 | | Getters & Setters | ||
| 221 | | ----------------------------------------------------------------- | ||
| 222 | */ | ||
| 223 | |||
| 224 | /** | ||
| 225 | * Get the latest_message attribute. | ||
| 226 | * | ||
| 227 | * @return \Arcanedev\LaravelMessenger\Models\Message | ||
| 228 | */ | ||
| 229 | 6 | public function getLatestMessageAttribute() | |
| 230 |     { | ||
| 231 | 6 |         return $this->messages->sortByDesc('created_at')->first(); | |
| 232 | } | ||
| 233 | |||
| 234 | /** | ||
| 235 | * Get the participations table name. | ||
| 236 | * | ||
| 237 | * @return string | ||
| 238 | */ | ||
| 239 | 18 | protected function getParticipationsTable() | |
| 240 |     { | ||
| 241 | 18 |         return config('messenger.participations.table', 'participations'); | |
| 242 | } | ||
| 243 | |||
| 244 | /* ----------------------------------------------------------------- | ||
| 245 | | Main Methods | ||
| 246 | | ----------------------------------------------------------------- | ||
| 247 | */ | ||
| 248 | |||
| 249 | /** | ||
| 250 | * Returns all of the latest discussions by `updated_at` date. | ||
| 251 | * | ||
| 252 | * @return \Illuminate\Database\Eloquent\Collection | ||
| 253 | */ | ||
| 254 | 6 | public static function getLatest() | |
| 255 |     { | ||
| 256 | 6 |         return self::query()->latest('updated_at')->get(); | |
| 0 ignored issues–
                            show The expression  self::query()->latest('updated_at')->get();of typeIlluminate\Database\Eloq...base\Eloquent\Builder[]adds the typeIlluminate\Database\Eloquent\Builder[]to the return on line 256 which is incompatible with the return type declared by the interfaceArcanedev\LaravelMesseng...s\Discussion::getLatestof typeIlluminate\Database\Eloquent\Collection. Loading history... | |||
| 257 | } | ||
| 258 | |||
| 259 | /** | ||
| 260 | * Returns all discussions by subject. | ||
| 261 | * | ||
| 262 | * @param string $subject | ||
| 263 | * @param bool $strict | ||
| 264 | * | ||
| 265 | * @return \Illuminate\Database\Eloquent\Collection | ||
| 266 | */ | ||
| 267 | 12 | public static function getBySubject($subject, $strict = false) | |
| 268 |     { | ||
| 269 | 12 | return self::subject($subject, $strict)->get(); | |
| 0 ignored issues–
                            show The method  getdoes only exist inIlluminate\Database\Eloquent\Builder, but not inArcanedev\LaravelMessenger\Models\Discussion.It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
    public function foo() { }
}
class B extends A
{
    public function bar() { }
}
/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
  Loading history... | |||
| 270 | } | ||
| 271 | |||
| 272 | /** | ||
| 273 | * Returns an array of participables that are associated with the discussion. | ||
| 274 | * | ||
| 275 | * @return \Illuminate\Database\Eloquent\Collection | ||
| 276 | */ | ||
| 277 | 12 | public function getParticipables() | |
| 278 |     { | ||
| 279 | 12 | return $this->participations() | |
| 280 | 12 | ->withTrashed() | |
| 281 | 12 | ->get() | |
| 282 |             ->transform(function (ParticipationContract $participant) { | ||
| 283 | 12 | return $participant->participable; | |
| 0 ignored issues–
                            show Accessing  participableon the interfaceArcanedev\LaravelMessenger\Contracts\Participationsuggest that you code against a concrete implementation. How about adding aninstanceofcheck?If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
  Loading history... | |||
| 284 | 12 | }) | |
| 285 |             ->unique(function (EloquentModel $participable) { | ||
| 286 | 12 | return $participable->getMorphClass().'-'.$participable->getKey(); | |
| 287 | 12 | }); | |
| 288 | } | ||
| 289 | |||
| 290 | /** | ||
| 291 | * Add a participable to discussion. | ||
| 292 | * | ||
| 293 | * @param \Illuminate\Database\Eloquent\Model $participable | ||
| 294 | * | ||
| 295 | * @return \Arcanedev\LaravelMessenger\Models\Participation|mixed | ||
| 296 | */ | ||
| 297 | 84 | public function addParticipant(EloquentModel $participable) | |
| 298 |     { | ||
| 299 | 84 |         $morph = config('messenger.users.morph', 'participable'); | |
| 300 | |||
| 301 | 84 | return $this->participations()->firstOrCreate([ | |
| 302 | 84 |             "{$morph}_id"   => $participable->getKey(), | |
| 303 | 84 |             "{$morph}_type" => $participable->getMorphClass(), | |
| 304 | 84 | 'discussion_id' => $this->id, | |
| 305 | ]); | ||
| 306 | } | ||
| 307 | |||
| 308 | /** | ||
| 309 | * Add many participables to discussion. | ||
| 310 | * | ||
| 311 | * @param \Illuminate\Support\Collection|array $participables | ||
| 312 | * | ||
| 313 | * @return \Illuminate\Database\Eloquent\Collection | ||
| 314 | */ | ||
| 315 | 48 | public function addParticipants($participables) | |
| 316 |     { | ||
| 317 | 48 |         foreach ($participables as $participable) { | |
| 318 | 48 | $this->addParticipant($participable); | |
| 319 | } | ||
| 320 | |||
| 321 | 48 | return $this->participations; | |
| 322 | } | ||
| 323 | |||
| 324 | /** | ||
| 325 | * Remove a participable from discussion. | ||
| 326 | * | ||
| 327 | * @param \Illuminate\Database\Eloquent\Model $participable | ||
| 328 | * @param bool $reload | ||
| 329 | * | ||
| 330 | * @return int | ||
| 331 | */ | ||
| 332 | 12 | public function removeParticipant(EloquentModel $participable, $reload = true) | |
| 333 |     { | ||
| 334 | 12 | return $this->removeParticipants([$participable], $reload); | |
| 335 | } | ||
| 336 | |||
| 337 | /** | ||
| 338 | * Remove many participables from discussion. | ||
| 339 | * | ||
| 340 | * @param \Illuminate\Support\Collection|array $participables | ||
| 341 | * @param bool $reload | ||
| 342 | * | ||
| 343 | * @return int | ||
| 344 | */ | ||
| 345 | 36 | public function removeParticipants($participables, $reload = true) | |
| 346 |     { | ||
| 347 | 36 |         $morph   = config('messenger.users.morph', 'participable'); | |
| 348 | 36 | $deleted = 0; | |
| 349 | |||
| 350 | 36 |         foreach ($participables as $participable) { | |
| 351 | /** @var \Illuminate\Database\Eloquent\Model $participable */ | ||
| 352 | 36 | $deleted += $this->participations() | |
| 353 | 36 |                 ->where("{$morph}_type", '=', $participable->getMorphClass()) | |
| 354 | 36 |                 ->where("{$morph}_id", '=', $participable->getKey()) | |
| 355 | 36 |                 ->where('discussion_id', '=', $this->id) | |
| 356 | 36 | ->delete(); | |
| 357 | } | ||
| 358 | |||
| 359 | 36 | if ($reload) | |
| 360 | 18 | $this->load(['participations']); | |
| 361 | |||
| 362 | 36 | return $deleted; | |
| 363 | } | ||
| 364 | |||
| 365 | /** | ||
| 366 | * Mark a discussion as read for a participable. | ||
| 367 | * | ||
| 368 | * @param \Illuminate\Database\Eloquent\Model $participable | ||
| 369 | * | ||
| 370 | * @return bool|int | ||
| 371 | */ | ||
| 372 | 30 | public function markAsRead(EloquentModel $participable) | |
| 373 |     { | ||
| 374 | 30 |         if ($participant = $this->getParticipationByParticipable($participable)) { | |
| 375 | 24 | return $participant->update(['last_read' => Carbon::now()]); | |
| 376 | } | ||
| 377 | |||
| 378 | 6 | return false; | |
| 379 | } | ||
| 380 | |||
| 381 | /** | ||
| 382 | * See if the current thread is unread by the participable. | ||
| 383 | * | ||
| 384 | * @param \Illuminate\Database\Eloquent\Model $participable | ||
| 385 | * | ||
| 386 | * @return bool | ||
| 387 | */ | ||
| 388 | 12 | public function isUnread(EloquentModel $participable) | |
| 389 |     { | ||
| 390 | 12 | return ($participant = $this->getParticipationByParticipable($participable)) | |
| 391 | 12 | ? $participant->last_read < $this->updated_at | |
| 392 | 12 | : false; | |
| 393 | } | ||
| 394 | |||
| 395 | /** | ||
| 396 | * Finds the participant record from a participable model. | ||
| 397 | * | ||
| 398 | * @param \Illuminate\Database\Eloquent\Model $participable | ||
| 399 | * | ||
| 400 | * @return \Arcanedev\LaravelMessenger\Models\Participation|mixed | ||
| 401 | */ | ||
| 402 | 42 | public function getParticipationByParticipable(EloquentModel $participable) | |
| 403 |     { | ||
| 404 | 42 |         $morph = config('messenger.users.morph', 'participable'); | |
| 405 | |||
| 406 | 42 | return $this->participations() | |
| 407 | 42 |             ->where("{$morph}_type", '=', $participable->getMorphClass()) | |
| 408 | 42 |             ->where("{$morph}_id", '=', $participable->getKey()) | |
| 409 | 42 | ->first(); | |
| 410 | } | ||
| 411 | |||
| 412 | /** | ||
| 413 | * Get the trashed participations. | ||
| 414 | * | ||
| 415 | * @return \Illuminate\Database\Eloquent\Collection | ||
| 416 | */ | ||
| 417 | 12 | public function getTrashedParticipations() | |
| 418 |     { | ||
| 419 | 12 | return $this->participations()->onlyTrashed()->get(); | |
| 420 | } | ||
| 421 | |||
| 422 | /** | ||
| 423 | * Restores all participations within a discussion. | ||
| 424 | * | ||
| 425 | * @param bool $reload | ||
| 426 | * | ||
| 427 | * @return int | ||
| 428 | */ | ||
| 429 | 6 | public function restoreAllParticipations($reload = true) | |
| 430 |     { | ||
| 431 | 6 | $restored = $this->getTrashedParticipations() | |
| 432 |             ->filter(function (ParticipationContract $participant) { | ||
| 433 | 6 | return $participant->restore(); | |
| 434 | 6 | }) | |
| 435 | 6 | ->count(); | |
| 436 | |||
| 437 | 6 | if ($reload) | |
| 438 | 6 | $this->load(['participations']); | |
| 439 | |||
| 440 | 6 | return $restored; | |
| 441 | } | ||
| 442 | |||
| 443 | /** | ||
| 444 | * Generates a participant information as a string. | ||
| 445 | * | ||
| 446 | * @param \Closure|null $callback | ||
| 447 | * @param string $glue | ||
| 448 | * | ||
| 449 | * @return string | ||
| 450 | */ | ||
| 451 | 12 | public function participationsString($callback = null, $glue = ', ') | |
| 452 |     { | ||
| 453 | /** @var \Illuminate\Database\Eloquent\Collection $participations */ | ||
| 454 | 12 | $participations = $this->participations->load(['participable']); | |
| 455 | |||
| 456 | 12 |         if (is_null($callback)) { | |
| 457 | // By default: the participant name | ||
| 458 |             $callback = function (ParticipationContract $participant) { | ||
| 459 | 6 | return $participant->stringInfo(); | |
| 460 | 6 | }; | |
| 461 | } | ||
| 462 | |||
| 463 | 12 | return $participations->map($callback)->implode($glue); | |
| 464 | } | ||
| 465 | |||
| 466 | /** | ||
| 467 | * Checks to see if a participable is a current participant of the discussion. | ||
| 468 | * | ||
| 469 | * @param \Illuminate\Database\Eloquent\Model $participable | ||
| 470 | * | ||
| 471 | * @return bool | ||
| 472 | */ | ||
| 473 | 12 | public function hasParticipation(EloquentModel $participable) | |
| 474 |     { | ||
| 475 | 12 |         $morph = config('messenger.users.morph', 'participable'); | |
| 476 | |||
| 477 | 12 | return $this->participations() | |
| 478 | 12 |             ->where("{$morph}_id", '=', $participable->getKey()) | |
| 479 | 12 |             ->where("{$morph}_type", '=', $participable->getMorphClass()) | |
| 480 | 12 | ->count() > 0; | |
| 481 | } | ||
| 482 | |||
| 483 | /** | ||
| 484 | * Get the unread messages in discussion for a specific participable. | ||
| 485 | * | ||
| 486 | * @param \Illuminate\Database\Eloquent\Model $participable | ||
| 487 | * | ||
| 488 | * @return \Illuminate\Support\Collection | ||
| 489 | */ | ||
| 490 | 12 | public function getUnreadMessages(EloquentModel $participable) | |
| 491 |     { | ||
| 492 | 12 | $participation = $this->getParticipationByParticipable($participable); | |
| 493 | |||
| 494 | 12 | if (is_null($participation)) | |
| 495 | 6 | return new Collection; | |
| 496 | |||
| 497 | 12 | return is_null($participation->last_read) | |
| 498 | 12 | ? $this->messages->toBase() | |
| 499 |             : $this->messages->filter(function (MessageContract $message) use ($participation) { | ||
| 500 | 12 | return $message->updated_at->gt($participation->last_read); | |
| 0 ignored issues–
                            show Accessing  updated_aton the interfaceArcanedev\LaravelMessenger\Contracts\Messagesuggest that you code against a concrete implementation. How about adding aninstanceofcheck?If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
  Loading history... | |||
| 501 | 12 | })->toBase(); | |
| 502 | } | ||
| 503 | } | ||
| 504 | 
 
                                
It seems like the method you are trying to call exists only in some of the possible types.
Let’s take a look at an example:
Available Fixes
Add an additional type-check:
Only allow a single type to be passed if the variable comes from a parameter: