dglaser2's avatar

Combining QB result with an Array

Hello, I am working on an existing codebase and am having much difficult grappling with two data sources involving an array and collection in Laravel 5.6.

I am still familiarizing myself with Laravel and would greatly appreciate if someone could please explain how I could combine reposts (aka "favorite posts") and posts. I added the reposts code using code from elsewhere in the app and the app is working otherwise without the reposts code. Upon trying to run the function with the reposts code, I run into an error when I try to merge $qb and $favorite_posts. It makes sense why this is the case, but I'm trying to figure out how I can achieve merging these two groups and sorting them by 'created_at' so that the later code (i.e. the foreach-loop and pagination) can be applied to the single array/collection.

My code looks like the following:

private function get_posts($input) {
    $limit = (isset($input['limit'])) ? $input['limit'] : $this->per_page;
    $sortBy = (isset($input['sort_by'])) ? $input['sort_by'] : 'created_at';
    $sortOrder = (isset($input['sort_order'])) ? $input['sort_order'] : 'desc';        
    
    $qb = Post::orderBy($sortBy, $sortOrder);
    $data_type = 'Posts';

    // feed
    if (isset($input['user_id'])) 
    {
        $data_type = 'Feed';
        $user = User::find($input['user_id']);

        if ($user) {
            $user_ids = array_merge($user->followings->pluck('user_id')->toArray(), [ $user->id ]);
            $qb = $qb->whereIn('user_id', $user_ids);
            
            // reposts
            $following_favs = \DB::table('fav_posts')->whereIn('user_id', $user_ids)->get()->toArray();
            $favorites = [];
            foreach($following_favs as $f) 
                $favorites[ $f→post_id ] = $f;
                    
            $favorite_posts = array_map(function ($f) use ($favorites){
                $fav = $favorites[$f['id']];
                return array_merge($fav, [
                    'reposted_at' => (new Carbon($fav->created_at))->timestamp
                ]);
            }, Post::whereIn('id', array_keys($favorites))->get()->toArray());

            $qb = array_values(collect(array_merge($qb, $favorite_posts))
            ->sortByDesc('created_at')->toArray());
			// reposts
        }
    }  

	$posts = array_merge($favorite_posts, $qb);

    $total = $qb->count();
    $posts_data = $qb->paginate( $limit );
    $posts = [];

    foreach ($posts_data as $p) {
        $posts[] = array_merge($p->toArray(), [
            'user' ⇒ $p->user,
            'body' ⇒ $p→text
        ]);
    };

    return [
        'data' ⇒ $posts, 
        'header' => [
            'status' => $data_type . ' retrieved successfully',
            'pages' => $this->getPages($total, $limit),
            'page' => isset($input['page']) ? +$input['page'] : 1,
            'total' => $total
        ]
    ];
}
0 likes
1 reply
kevinbui's avatar

I believe you code will fail at the following lines:

$qb = array_values(collect(array_merge($qb, $favorite_posts))
            ->sortByDesc('created_at')->toArray());

$posts = array_merge($favorite_posts, $qb);

You are merging the $favourite_posts array with $qb, an instance of Illuminate\Database\Eloquent\Builder class.

Reading your code, I think you want to get posts that:

  • paginated and sorted by the input.
  • created by the user and all his following.
  • reposted by the user and all his following.

When a feature involves pagination, I suggest creating a main query, then get the count and paginated results in the end.

I think you code can be refactored to this, I rename some variables to my likings:

$limit = (isset($input['limit'])) ? $input['limit'] : $this->per_page;
$sortBy = (isset($input['sort_by'])) ? $input['sort_by'] : 'created_at';
$sortOrder = (isset($input['sort_order'])) ? $input['sort_order'] : 'desc';        
    
$query = Post::orderBy($sortBy, $sortOrder);
$dataType = 'Posts';

if (isset($input['user_id'])) {
    $dataType = 'Feed';

    $user = User::find($input['user_id']);

    $userIds = $user->followings->push($user)->pluck('id')->toArray();

    $query->selectRaw('posts.*, fav_posts.user_id as reposted_user_id, fav_posts.created_at as reposted_at')
        ->join('fav_posts', 'posts.id', '=', 'fav_posts.post_id')
        ->whereIn('user_id', $userIds)
        ->orWhereIn('reposted_user_id', $userIds);
}

return [
        'data' ⇒ $query->paginate($limit), 
        'header' => [
            'status' => $data_type . ' retrieved successfully',
            'pages' => $this->getPages($total, $limit),
            'page' => isset($input['page']) ? +$input['page'] : 1,
            'total' => $query->count(),
        ]
    ];

Please or to participate in this conversation.