简体   繁体   中英

How to have query by 3 join in Laravel Eloquent model without foreach

Is there anyway to remove to foreach from this code?

    $user = \Auth::user();
    foreach ($user->categories as $category) {
        $channels[] = $category->channel();
    }
    return $channels;

I want to use the paginate function but it's not possible with the foreach !

Eloquent does not perform JOIN queries, if you actually need a JOIN, you'll need to drop down to the query builder and write the query your self.

If, however, you're simply trying to avoid the N+1 problem, the you should use eager loading. This will create 1 additional WHERE foreign_id IN(...) query per relationship type. So in total there would be:

  • 1 query to fetch the user record
  • 1 query to fetch all categories that belong to the user
  • 1 query to fetch all channels that belong to any of the previously fetched categories

Since you already have the user instance in memory, you can avoid re-fetching the user record via lazy eager loading .

Laravel paginator documentation is a little short, especially with creating/paginating manually like you will have to do .... here is a brief overview of how they work how to make them work...

No magic, paginators will call your controller function for every page. The request will have the pagination information in it. It is your job to actually select and slice the page. The paginator simply presents it... which is a big part of the work...

Your $channels[] array will have to be sliced and returned properly... something like this...

public function channels(){

    // we have to build the paginator ourselves, your result is an array...
    $user = \Auth::user();
    foreach ($user->categories as $category) {
        $channels[] = $category->channel();
    }

    // this basically gets the request's page variable...This is how pagination works under the hood... we defaults to 1
    $page = Paginator::resolveCurrentPage('page') ?: 1;

    // Assume 15 items per page... so start index to slice our array
    $startIndex = ($page - 1) * 15;

    // Length aware paginator needs a total count of items... to paginate properly
    $total = count($channels);

    // Eliminate the non relevant items... We have to slice the array ourselves...
    $results = array_slice($channels, $startIndex, 15);

    $paginatedChannels =  new LengthAwarePaginator($results, $total, 15, $page, [
        'path' => Paginator::resolveCurrentPath(),
        'pageName' => 'page',
    ]);
    return view('yourViews', compact('paginatedChannels'));
}

The key is you have to prepare the data slice yourself...

You can post your data structure so we can come up with a better alternative to the query itself... but this should work if that $category->channel() function works...

What about this way?

$categories = \Auth::user()->categories()->pluck('id')->toArray();
return \App\Channel::wherein('category_id', $categories)->paginate();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM