Skip to content

Commit a17919c

Browse files
committed
Add ratings stats
1 parent a752acb commit a17919c

File tree

3 files changed

+171
-43
lines changed

3 files changed

+171
-43
lines changed

src/Contracts/ReviewRateableContract.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ public function averageRatingsByDepartment(string $department, bool $approved =
8585
*/
8686
public function getReviews(bool $approved = true, bool $withRatings = true): Collection;
8787

88+
/**
89+
* Get all reviews (with attached ratings) for a department,
90+
* filtered by the approved status.
91+
*
92+
* @param string $department
93+
* @param bool $approved
94+
* @param bool $withRatings
95+
* @return Collection
96+
*/
8897
public function getReviewsByDepartment(string $department, bool $approved = true, bool $withRatings = true): Collection;
8998

9099
/**
@@ -95,6 +104,15 @@ public function getReviewsByDepartment(string $department, bool $approved = true
95104
*/
96105
public function totalReviews(bool $approved = true): int;
97106

107+
/**
108+
* Get the total number of reviews for the model by department.
109+
*
110+
* @param string $department
111+
* @param bool $approved
112+
* @return int
113+
*/
114+
public function totalDepartmentReviews(string $department, bool $approved = true): int;
115+
98116
/**
99117
* Get the overall average rating for all ratings attached to the model.
100118
*
@@ -121,4 +139,16 @@ public function deleteReview(int $reviewId): bool;
121139
*/
122140
public function ratingCounts(?string $department = null, bool $approved = true): array;
123141

142+
/**
143+
* Return an array with:
144+
* • counts: [1 => x, 2 => y, …, 5 => z]
145+
* • percentages: [1 => pct1, …, 5 => pct5]
146+
* • total: total number of ratings
147+
*
148+
* @param string|null $department
149+
* @param bool $approved
150+
* @return array
151+
*/
152+
public function ratingStats(?string $department = null, bool $approved = true): array;
153+
124154
}

src/Services/ReviewRateableService.php

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace Codebyray\ReviewRateable\Services;
44

55
use Codebyray\ReviewRateable\Contracts\ReviewRateableContract;
6+
use Codebyray\ReviewRateable\Models\Rating;
7+
use Codebyray\ReviewRateable\Models\Review;
68
use Exception;
79
use Illuminate\Database\Eloquent\Collection;
810

@@ -145,6 +147,21 @@ public function getReviews(bool $approved = true, bool $withRatings = true): Col
145147
return $this->getModel()->getReviews($approved, $withRatings);
146148
}
147149

150+
/**
151+
* Get all reviews (with attached ratings) for a department,
152+
* filtered by the approved status.
153+
*
154+
* @param string $department
155+
* @param bool $approved
156+
* @param bool $withRatings
157+
* @return Collection
158+
* @throws Exception
159+
*/
160+
public function getReviewsByDepartment(string $department, bool $approved = true, bool $withRatings = true): Collection
161+
{
162+
return $this->getModel()->getReviewsByDepartment($department, $approved, $withRatings);
163+
}
164+
148165
/**
149166
* Get the total number of ratings for the attached model.
150167
*
@@ -157,6 +174,19 @@ public function totalReviews(bool $approved = true): int
157174
return $this->getModel()->reviewCount($approved);
158175
}
159176

177+
/**
178+
* Get the total number of reviews for the model by department.
179+
*
180+
* @param string $department
181+
* @param bool $approved
182+
* @return int
183+
* @throws Exception
184+
*/
185+
public function totalDepartmentReviews(string $department, bool $approved = true): int
186+
{
187+
return $this->getModel()->totalReviews($department, $approved);
188+
}
189+
160190
/**
161191
* Get the overall average rating for all ratings attached to the model.
162192
*
@@ -190,7 +220,22 @@ public function deleteReview(int $reviewId): bool
190220
*/
191221
public function ratingCounts(?string $department = null, bool $approved = true): array
192222
{
193-
return $this->getModel()->ratingCounts($approved);
223+
return $this->getModel()->ratingCounts($department, $approved);
194224
}
195225

226+
/**
227+
* Return an array with:
228+
* • counts: [1 => x, 2 => y, …, 5 => z]
229+
* • percentages: [1 => pct1, …, 5 => pct5]
230+
* • total: total number of ratings
231+
*
232+
* @param string|null $department
233+
* @param bool $approved
234+
* @return array
235+
* @throws Exception
236+
*/
237+
public function ratingStats(?string $department = null, bool $approved = true): array
238+
{
239+
return $this->getModel()->ratingStats($department, $approved);
240+
}
196241
}

src/Traits/ReviewRateable.php

Lines changed: 95 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -168,47 +168,6 @@ public function approveReview(int $reviewId): bool
168168
return $review->update(['approved' => true]);
169169
}
170170

171-
/**
172-
* Get all reviews (with attached ratings) for the model,
173-
* filtered by the approved status.
174-
*
175-
* @param bool $approved
176-
* @param bool $withRatings
177-
* @return Collection
178-
*/
179-
public function getReviews(bool $approved = true, bool $withRatings = true): Collection
180-
{
181-
$query = $this->reviews()->where('approved', $approved);
182-
183-
if ($withRatings) {
184-
$query->with('ratings');
185-
}
186-
187-
return $query->get();
188-
}
189-
190-
/**
191-
* Get all reviews (with attached ratings) for a department,
192-
* filtered by the approved status.
193-
*
194-
* @param string $department
195-
* @param bool $approved
196-
* @param bool $withRatings
197-
* @return Collection
198-
*/
199-
public function getReviewsByDepartment(string $department, bool $approved = true, bool $withRatings = true): Collection
200-
{
201-
$query = $this->reviews()
202-
->where('department', $department)
203-
->where('approved', $approved);
204-
205-
if ($withRatings) {
206-
$query->with('ratings');
207-
}
208-
209-
return $query->get();
210-
}
211-
212171
/**
213172
* Calculate the average rating for a given key, filtering reviews by approval.
214173
*
@@ -321,6 +280,47 @@ public function averageRatingsByDepartment(string $department, bool $approved =
321280
return $averages;
322281
}
323282

283+
/**
284+
* Get all reviews (with attached ratings) for the model,
285+
* filtered by the approved status.
286+
*
287+
* @param bool $approved
288+
* @param bool $withRatings
289+
* @return Collection
290+
*/
291+
public function getReviews(bool $approved = true, bool $withRatings = true): Collection
292+
{
293+
$query = $this->reviews()->where('approved', $approved);
294+
295+
if ($withRatings) {
296+
$query->with('ratings');
297+
}
298+
299+
return $query->get();
300+
}
301+
302+
/**
303+
* Get all reviews (with attached ratings) for a department,
304+
* filtered by the approved status.
305+
*
306+
* @param string $department
307+
* @param bool $approved
308+
* @param bool $withRatings
309+
* @return Collection
310+
*/
311+
public function getReviewsByDepartment(string $department, bool $approved = true, bool $withRatings = true): Collection
312+
{
313+
$query = $this->reviews()
314+
->where('department', $department)
315+
->where('approved', $approved);
316+
317+
if ($withRatings) {
318+
$query->with('ratings');
319+
}
320+
321+
return $query->get();
322+
}
323+
324324
/**
325325
* Get the total number of reviews for the model.
326326
*
@@ -333,8 +333,9 @@ public function totalReviews(bool $approved = true): int
333333
}
334334

335335
/**
336-
* Get the total number of reviews for the model.
336+
* Get the total number of reviews for the model by department.
337337
*
338+
* @param string $department
338339
* @param bool $approved
339340
* @return int
340341
*/
@@ -419,4 +420,56 @@ public function ratingCounts(?string $department = null, bool $approved = true):
419420

420421
return $counts;
421422
}
423+
424+
/**
425+
* Return an array with:
426+
* • counts: [1 => x, 2 => y, …, 5 => z]
427+
* • percentages: [1 => pct1, …, 5 => pct5]
428+
* • total: total number of ratings
429+
*
430+
* @param string|null $department
431+
* @param bool $approved
432+
* @return array
433+
*/
434+
public function ratingStats(?string $department = null, bool $approved = true): array
435+
{
436+
$min = config('review-rateable.min_rating_value', 1);
437+
$max = config('review-rateable.max_rating_value', 5);
438+
$reviewTable = (new Review)->getTable();
439+
$ratingTable = (new Rating)->getTable();
440+
441+
// base query: gives you value => count
442+
$raw = Rating::select("{$ratingTable}.value", DB::raw('COUNT(*) as count'))
443+
->join($reviewTable, "{$ratingTable}.review_id", '=', "{$reviewTable}.id")
444+
->where("{$reviewTable}.reviewable_type", $this->getMorphClass())
445+
->where("{$reviewTable}.reviewable_id", $this->getKey())
446+
->where("{$reviewTable}.approved", $approved)
447+
->when($department, fn($q) => $q->where("{$reviewTable}.department", $department))
448+
->groupBy("{$ratingTable}.value")
449+
->pluck('count', 'value')
450+
->all();
451+
452+
// zero-fill missing star values
453+
$counts = [];
454+
for ($i = $min; $i <= $max; $i++) {
455+
$counts[$i] = $raw[$i] ?? 0;
456+
}
457+
458+
// total number of ratings
459+
$total = array_sum($counts);
460+
461+
// percentages (integer 0–100)
462+
$percentages = [];
463+
foreach ($counts as $star => $count) {
464+
$percentages[$star] = $total
465+
? round(($count / $total) * 100)
466+
: 0;
467+
}
468+
469+
return [
470+
'counts' => $counts,
471+
'percentages' => $percentages,
472+
'total' => $total,
473+
];
474+
}
422475
}

0 commit comments

Comments
 (0)