-
Notifications
You must be signed in to change notification settings - Fork 12
Perbaikan error subquery pada fitur notifikasi desa di halaman desa #652
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: rilis-dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,16 @@ class Notifikasi extends Model | |
| /** {@inheritdoc} */ | ||
| protected $table = 'notifikasi'; | ||
|
|
||
| /** | ||
| * Relasi ke tabel notifikasi_desa (pivot). | ||
| * | ||
| * @return \Illuminate\Database\Eloquent\Relations\HasMany | ||
| */ | ||
| public function notifikasiDesa() | ||
| { | ||
| return $this->hasMany(NotifikasiDesa::class, 'id_notifikasi'); | ||
| } | ||
|
|
||
| /** | ||
| * Scope semua notif dari desa. | ||
| * | ||
|
|
@@ -22,6 +32,15 @@ class Notifikasi extends Model | |
| */ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [HIGH] ⚡ Performance: Missing Eager Loading untuk Relasi Masalah: Scope ini tidak melakukan eager loading untuk relasi Kode: return $query->where('aktif', 1)
->where(function ($q) use ($desaId) {
// ... whereHas logic
});
// Missing: ->with('notifikasiDesa')Dampak: Jika controller memanggil
Fix: public function scopeSemuaNotifDesa($query, $desaId)
{
return $query->where('aktif', 1)
->where(function ($q) use ($desaId) {
$q->whereHas('notifikasiDesa', function ($q) use ($desaId) {
$q->where('id_desa', $desaId)
->where('status', '!=', 0);
})
->orWhereDoesntHave('notifikasiDesa', function ($q) use ($desaId) {
$q->where('id_desa', $desaId);
});
})
->with(['notifikasiDesa' => function($q) use ($desaId) {
$q->where('id_desa', $desaId);
}]);
}
// Atau di controller:
Notifikasi::semuaNotifDesa($desaId)->with('notifikasiDesa')->get(); |
||
| public function scopeSemuaNotifDesa($query, $desaId) | ||
| { | ||
| return DB::select("select n.* from notifikasi as n where n.aktif = 1 and ((select nd.id from notifikasi_desa as nd where nd.id_notifikasi = n.id and nd.id_desa = '{$desaId}' and nd.status <> 0) is not null or (select nd.id from notifikasi_desa as nd where nd.id_notifikasi = n.id and nd.id_desa = '{$desaId}') is null)"); | ||
| return $query->where('aktif', 1) | ||
| ->where(function ($q) use ($desaId) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [HIGH] 📝 Code Quality: Missing Type Hints Kategori: PHP Quality Kode: public function scopeSemuaNotifDesa($query, $desaId)Fix: public function scopeSemuaNotifDesa(\Illuminate\Database\Eloquent\Builder $query, int|string $desaId): \Illuminate\Database\Eloquent\BuilderPenjelasan:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [HIGH] 📝 Code Quality: Missing Tests Kategori: Testing Kode: public function scopeSemuaNotifDesa($query, $desaId)
{
return $query->where('aktif', 1)
->where(function ($q) use ($desaId) {
$q->whereHas('notifikasiDesa', function ($q) use ($desaId) {
$q->where('id_desa', $desaId)
->where('status', '!=', 0);
})
->orWhereDoesntHave('notifikasiDesa', function ($q) use ($desaId) {
$q->where('id_desa', $desaId);
});
});
}Fix: <?php
namespace Tests\Unit\Models;
use App\Models\Notifikasi;
use App\Models\NotifikasiDesa;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class NotifikasiTest extends TestCase
{
use RefreshDatabase;
/** @test */
public function scope_semua_notif_desa_returns_active_notifications_with_desa_relation()
{
$desaId = 1;
// Notifikasi aktif dengan relasi desa (status != 0)
$notif1 = Notifikasi::factory()->create(['aktif' => 1]);
NotifikasiDesa::factory()->create([
'id_notifikasi' => $notif1->id,
'id_desa' => $desaId,
'status' => 1
]);
// Notifikasi aktif tanpa relasi desa (global)
$notif2 = Notifikasi::factory()->create(['aktif' => 1]);
// Notifikasi aktif dengan relasi desa tapi status = 0 (tidak muncul)
$notif3 = Notifikasi::factory()->create(['aktif' => 1]);
NotifikasiDesa::factory()->create([
'id_notifikasi' => $notif3->id,
'id_desa' => $desaId,
'status' => 0
]);
// Notifikasi tidak aktif (tidak muncul)
$notif4 = Notifikasi::factory()->create(['aktif' => 0]);
$result = Notifikasi::semuaNotifDesa($desaId)->get();
$this->assertCount(2, $result);
$this->assertTrue($result->contains($notif1));
$this->assertTrue($result->contains($notif2));
$this->assertFalse($result->contains($notif3));
$this->assertFalse($result->contains($notif4));
}
}Penjelasan: Test ini memverifikasi bahwa logic baru menghasilkan hasil yang sama dengan query SQL lama untuk berbagai skenario. |
||
| $q->whereHas('notifikasiDesa', function ($q) use ($desaId) { | ||
| $q->where('id_desa', $desaId) | ||
| ->where('status', '!=', 0); | ||
| }) | ||
| ->orWhereDoesntHave('notifikasiDesa', function ($q) use ($desaId) { | ||
| $q->where('id_desa', $desaId); | ||
| }); | ||
| }); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[CRITICAL] ⚡ Performance: whereHas + orWhereDoesntHave Subquery Tanpa Index
Masalah: Query menggunakan
whereHasdanorWhereDoesntHaveyang menghasilkan 2 subquery EXISTS/NOT EXISTS. Pada tabelnotifikasi_desadengan ribuan rows, ini akan sangat lambat tanpa composite index pada(id_desa, id_notifikasi, status).Kode:
Dampak: Pada production dengan 10,000+ notifikasi dan 50,000+ notifikasi_desa records:
Fix: