1
votes

I can paginate notifications and subnotifications for user notifiable_id 5 individually without any issues. However, I am trying to have the results paginated together in one instance.

1) DB table name/data

notifications

enter image description here

subnotifications

enter image description here

2) Pagination

I can paginate each relation I have individually like this:

$notifs = $user->notifications()->where('type', 'UserWasFollowed')->paginate(10);
$subnotifications = $user->subnotifications()->with('notification')->paginate(10);

I need to be able to merge them to get back only one paginate(10) instance which has both notifications and subnotifications, so something like this for example (pseudocode):

$allNotifs = $user->(notifications()->where('type', 'UserWasFollowed'))
                  ->(subnotifications()->with('notification'))
                  ->paginate(10);

How can this be done with one pagination instance efficiently?

Update 1:

User Model

class User extends Authenticatable {
    use Notifiable;
    use HasSubnotifications;
}

Subnotification Model

class Subnotification extends Model {
    protected $table = 'subnotifications';

    // set up relation to the parent notification
    public function notification() {
        return $this->belongsTo(DatabaseNotification::class);
    }

    // Get the notifiable entity that the notification belongs to.
    public function notifiable() {
        return $this->morphTo();
    }
}

Query for user's:

a. Notifications of UserWasFollowed type from notifications table.

b. Subnotifications from subnotifications table with the related notification from notifications table.

$allNotifications = $user->subnotifications()->whereHas('notifications',function($query){
  $query->where('type', 'UserWasFollowed');
})->with('notification')->get();
1
Need to have a look at the HasSubnotifications traitRezrazi
Replace 'notifications' with 'notification' in whereHas and with. I think it's just a naming issue, your relation in Subnotification is referred by notification method, and not notifications (typo). With and whereHas take the name of the method in argRezrazi
Replaced both 'notifications' to 'notification' instead, but returns an empty array [] even though all the data is there. Not sure why it's so complicated for such a simple joining of both notifications/subnotifications on the user model, but not issues at all when done individually.. Also, if you look at laravel.com/docs/5.4/notifications under Accessing The Notifications, you'll see you call it as notifications off the user, we only do notification for the subnotification's related notificationWonka
It should be empty, judging from your screenshots, you have no notifications typed UserWasFollowed for the user, try another type. There's no row for notififiable_id 5 and notification_id 1Rezrazi

1 Answers

2
votes

Having not much information about the purpose of the subnotification table or what it does, you can try the following method :

public function your_method_name()
{
    /* IMPORTANT : Purpose of subnotification must be known to have a more structured query */
    $collection = $user->notifications()->where('type', 'UserWasFollowed')->get()->merge($user->subnotifications()->with('notification')->get());

    $currentPage = LengthAwarePaginator::resolveCurrentPage();

    $perPage = 10;

    $currentPageData = $collection->slice($currentPage * $perPage, $perPage)->all();

    $paginatedFinalCollection = new LengthAwarePaginator($currentPageData, count($collection), $perPage);

    return dd($paginatedFinalCollection);
}

Note Talking about efficiency, the intent of subnotification must be known, why do you need it and how are you going to use the data retrieved by your second query. Having an answer to that might make a difference to $collection


EDIT
The simple way I can think of, is using a closure within your eager loading with Like so :

$sn = $user->subnotifications()->with(['notification'=>function($query){
      $query->where('type','UserWasFollowed');
}])->paginate(10);

You can learn more about it at Laravel Eloquent Relationships under Constraining Eager Loads


UPDATE 2
try this

$user->subnotifications()->whereHas('notifications',function($query){
    $query->where('notification_type','UserWasFollowed');
})->with('notifications')->get();

Using this with a similar setup worked fine for me.
Note Be sure to change the relations names to their proper ones if they don't match

UPDATE 3
When using your exact same setup for subnotifications provided in the related question, with the following queries :

Notifications\TestNotification.php is similar to the SomethingCoolHappen.php in the example.

The model, channel and migrations are the same. So you can use them as they are.
What I did to get what you wanted is the following :

Route::get('/step1', function () {
    // example - my followers
    $followers = App\User::first();
    // notify them
    $x = Notification::send($followers, new TestNotification(['arg1' => 1, 'arg2' => 2]));
    dd($x);
});

Route::get('/step2', function () {
    // my follower
    $user = App\User::find(1);

    $subnotifications = $user->subnotifications()->whereHas('notification',function($query){$query->where('type','App\Notifications\TestNotification');})->with('notification')->get();

//this gives you the subnotifications collection with the notification included
dd($subnotifications);

//get the notification linked to one entry of the collection
dd($subnotifications->first()->notification()->first());

});