David
David

Reputation: 1997

Count how many reviews a post has - Laravel 5.2

I need to count how many reviews a post has. How would I go about doing that?

Here is my Listing.php Model:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Listing extends Model
{

    public function reviews()
    {
        return $this->hasMany('\App\Review');
    }

}

Here is my Review.php model:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Review extends Model
{
    protected $fillable = ['stars','name','comment'];

    public function listing()
    {
        return $this->belongsTo('\App\Listing');
    }
}

Here is my method that I'am trying to count in controller

 public function mostReviews(Request $request) {

        $listings = Review::orderBy('-- most reviews here --')->take(10)->get();

        $headline = 'Most Reviewed Listings';

        return view('pages.listings', compact('listings', 'headline'));

    }

Here is my review table:

Review table for listing

Upvotes: 4

Views: 2504

Answers (5)

David
David

Reputation: 1997

This is what I did:

public function mostReviews() {

  $reviews = DB::table('reviews')
      ->select(DB::raw('AVG(stars) as review_score, listing_id'))
      ->groupBy('listing_id')
      ->orderBy('review_score', 'desc')
      ->limit(10)
      ->get();

  foreach($reviews as $key => $review) {
    $reviews[$key] = Listing::find($review->listing_id);
  }

  return view('listings.most-reviews', [
    'listings' => $reviews
  ]);

}

Upvotes: 1

Chris Cynarski
Chris Cynarski

Reputation: 513

I haven't tested it but the query below (using the query builder) should give you what you want - 10 listings with the most reviews. Additionally average_stars column should return average stars rate. You can easily modify the query to get 10 highest rated listings by changing orderBy to average_stars.

$listings = \DB::table('reviews AS r')
   ->select([
     'r.listing_id',
     \DB::raw('COUNT(*) AS no_of_reviews'),
     \DB::raw('AVG(r.stars) AS average_stars'),
     'l.*'])
   ->join('listings AS l', 'l.id', '=', 'r.listing_id')
   ->limit(10)
   ->orderBy('no_of_reviews', 'DESC')
   ->groupBy('listing_id')
   ->get();

Please note version up to version 5.2 of Laravel this will return array of stdObject. You can easily access those in your blade template in a similar way as Eloquent Collection.

@foreach($listings as $listing)
<tr>
   <td>{{ $listing->id }}</td>
   <td>{{ $listing->title }}</td>
   <td>{{ $listing->no_of_reviews }}</td>
   <td>{{ floor($listing->average_stars) }}</td>
</tr>
@endforeach

Upvotes: 1

Robin
Robin

Reputation: 59

in your listing model:

  public function countReview() { 
  return count($this->reviews); 
  } 

in your views :

 {{$listing->countReview()}} 

maybe in controller you can write somthing like :

 public function mostReviews() { 
  Review::orderBy('listing', 'desc')->blahblah; // or 'asc'
 }

Upvotes: 0

xhulio
xhulio

Reputation: 1103

The following should work

$listing = Listing::with('reviews')->orderByRaw(function($listing)
{
    return $listing->review->count();
}, desc)->take(10)->get();

Upvotes: 0

Vanya Avchyan
Vanya Avchyan

Reputation: 880

Try this

$review = Review::orderBy('-- most reviews here --');
$reviewCount = $review->count();
$listings=$review->take(10)->get();

Upvotes: 0

Related Questions