PHP Ürün filtrelemede mantık hatası var

abstractman

Decapat
Katılım
30 Ocak 2022
Mesajlar
100
Çözümler
2
Daha fazla  
Cinsiyet
Erkek
E-ticaret sitesi yaptım ürünleri çeşitli kategorilere göre filtreliyorum. Şu an kodumda mantık hatası var.
Örneğin 64GB ve 128GB hafıza seçersem hiç bir ürün gelmiyor ama 64GB hafıza ve 48MP kamera seçersem istediğim ürün geliyor. Sorunun sorguda olduğunu biliyorum ama çözemedim. İşte kullandığım tablolar:
"Ozellik_tbl" tablosunun sütunları şu şekilde: OzID/OzAdi/kategori/deger
"urnozellik_tbl" tablosu: uoID/OzellikID/urunID
İsterseniz verilerden örnekler de atabilirim.
En son da "Urunler_tbl" tablosundan ürünü çekiyorum. İşte gerekli kodlar:
Bu sorguları oluşturduğum fonksiyon:
PHP:
 Ürünleri getirme fonksiyonu
function getProducts($conn, $selectedSellers, $selectedColors, $selectedCategory, $selectedBrands, $selectedFeatures) {
 
$username2 = $_SESSION['username'];
// Kullanıcılar tablosundan ktur değerini alma
$sorgu1 = "SELECT * FROM Kullanicilar_Tbl WHERE Kullaniciadi = '$username2'";
$result1 = $conn->query($sorgu1);

if ($result1) {
    // Sorgu başarılı bir şekilde çalıştıysa devam edelim
    if ($result1->num_rows > 0) {
        $row = $result1->fetch_assoc(); // İlk satırı al
        $ktur = $row['ktur']; // ktur değerini al
        $girisci = $row['K_ID'];
     
    }
}
    // Koşulları bir araya getirmek için bir dizi kullanıyoruz
    $conditions = [];

 
    if (!empty($selectedBrands)) {
        $brands = implode("','", $selectedBrands);
        $conditions[] = "MarkaID IN ('$brands')";
    }

    if (!empty($selectedSellers)) {
        $sellers = implode(',', $selectedSellers);
        $conditions[] = "SaticiID IN ($sellers)";
    }

    if (!empty($selectedColors)) {
        $colors = implode(',', $selectedColors);
        $conditions[] = "renk IN ($colors)";
    }

    if (!empty($selectedCategory)) {
        $conditions[] = "KategoriID = '$selectedCategory'";
    }

    $conditions[]= " durum = 1";

    $productSql = "SELECT * FROM Urunler_tbl";
    if (!empty($conditions)) {
        $productSql .= " WHERE " . implode(" AND ", $conditions);
    }

    if (!empty($selectedFeatures)) {
        $features = implode(',', $selectedFeatures);
        $productSql .= " AND UrunID IN (
            SELECT urunID
            FROM urnozellik_tbl
            WHERE OzellikID IN ($features)
            GROUP BY urunID
            HAVING COUNT(DISTINCT OzellikID) = " . count($selectedFeatures) . "
        )";
    }

Burası da filtreleme kısmının formu ve uygulaya basınca gönderilmesi.


PHP:
        <h2>Ürün Özellikleri</h2>
                    <ul class="list-group">
                       <?php    
$sql = "SELECT o.*, oa.OzAd
        FROM Ozellik_tbl o
        INNER JOIN OzAd oa ON o.OzAdi = oa.OzADID
        WHERE o.kategori = 1";
$result = $conn->query($sql);

// Özellikleri gruplayarak listeleme
$groupedProperties = array();
if ($result->num_rows > 0) {
    while($row = $result->fetch_assoc()) {
        $propertyName = $row["OzAd"];
        $propertyValue = $row["deger"];
     
        // Grup adına göre özellikleri gruplama
        if (!isset($groupedProperties[$propertyName])) {
            $groupedProperties[$propertyName] = array();
        }
        $groupedProperties[$propertyName][] = array(
            "id" => $row["OzID"],
            "value" => $propertyValue
        );
    }
 
    // Grupları listeleme
    foreach ($groupedProperties as $propertyType => $properties) {
        echo '<li class="list-group-item">';
        echo '<h5>' . $propertyType . '</h5>';
     
        foreach ($properties as $property) {
            echo '<input type="checkbox" name="selected_features[]" value="' . $property["id"] . '">';
            echo $property["value"] . '<br>';
        }
     
        echo '</li>';
    }
 
} else {
    echo '<li class="list-group-item">Özellik bulunamadı.</li>';
}
?>

                    </ul>
                    <!-- Ürün Özellikleri divi sonu -->
                 
                    <!-- Uygula butonu -->
                    <button type="submit" class="btn btn-primary mt-3" name="apply_btn">Uygula</button>
                </form>
            </div>
        </div>
        <!-- filtre paneli divi sonu -->
     

        <!-- Ürün kartları -->
        <div class="col-md-7">
            <div class="container mt-5">
                <div class="row">
                    <?php
                    // Form gönderilmiş mi kontrol et
                    if(isset($_POST['apply_btn'])) {
                        $selectedSellers = !empty($_POST['selected_sellers']) ? $_POST['selected_sellers'] : [];
                        $selectedColors = !empty($_POST['selected_colors']) ? $_POST['selected_colors'] : [];
                        $selectedCategory = isset($_POST['selected_category']) ? $_POST['selected_category'] : '';
                        $selectedBrands = !empty($_POST['selected_brands']) ? $_POST['selected_brands'] : [];
                        $selectedFeatures = !empty($_POST['selected_features']) ? $_POST['selected_features'] : [];
                       getProducts($conn, $selectedSellers, $selectedColors, $selectedCategory, $selectedBrands, $selectedFeatures);
                    } else {
                        // Hiçbir filtre uygulanmadığında tüm ürünleri listele
                        getProducts($conn, [], [], '', [], []);
                    }
                    ?>
                </div>
            </div>
        </div>
 
Son düzenleyen: Moderatör:
Sorun sanırsam şuradaki HAVING kısmında:

PHP:
if (!empty($selectedFeatures)) {
    $features = implode(',', $selectedFeatures);
    $productSql .= " AND UrunID IN (
        SELECT urunID
        FROM urnozellik_tbl
        WHERE OzellikID IN ($features)
        GROUP BY urunID
        HAVING COUNT(DISTINCT OzellikID) = " . count($selectedFeatures) . "
    )";
}
"Sorun" dediğime bakmayın, aslında mantıklı bir filtre ama sisteminizin dilediğiniz şekilde çalışmasını burası engelliyor.

Örneğin 64GB ve 128GB hafıza seçersem hiçbir ürün gelmiyor ama 64GB hafıza ve 48MP kamera seçersem istediğim ürün geliyor.

Bir ürün aynı anda 64 GB ve 128 GB hafızaya sahip olamaz -herhalde- ama 64 GB hafıza ve 48 MP kameraya sahip olabilir çünkü ikisi farklı türden özellikler.

İki sorguda da count($selectedFeatures) = 2 olacaktır ama ilk sorguda COUNT(DISTINCT OzellikID) = 1 olacaktır.

Filtre mantığınızda filtrelenecek cihazların seçilen tüm özelliklere sahip olmasını istiyorsunuz. Bu, tüm özellikler farklı türden olduğunda doğru bir işlem oluyor ancak aynı türden özellikler için "ve" (AND) değil de "veya" (OR) demelisiniz:
  • 64 GB veya 128 GB
  • 64 GB ve 48 MP
Bunun için işe, aynı türden özellikleri kendi içlerinde gruplayarak başlamak güzel bir fikir olabilir. Her özellik türünden seçilen değerler birer listede toplanır, sonra bu listeler kapsayıcı bir liste içine alınıp $selectedFeatures olarak gönderilir. Mesela:
PHP:
[
    ["64 GB", "128 GB", "256 GB"],
    ["48 MP", "64 MP"],
    ["4000 mAh"]
]
Ben isimlerini yazdım da ID'leri olacak tabii sizin kodunuza göre.

Burada $features'ın bunun tek boyuta indirilmiş hâli olması uygun sanırım: ["64 GB", "128 GB", "256 GB", "48 MP", "64 MP", "4000 mAh"].

Bu değişikliklerden sonra, en yukarıda alıntıladığım sorgu aynen öyle kalabilir gibi, gözümden bir şey kaçmadıysa. Tabii frontend kısmında da değişiklikler gerekecek.

Alternatif yollar mevcuttur illaki. Mesela, veri tabanında bir özellik türü tablosu oluşturulup $selectedFeatures'taki farklı özellik türlerinin sayısı oradan elde edilebilir ve count($selectedFeatures) yerine kullanılabilir. Frontend'de değişikliğe gerek kalmaz.
 
Sorun sanırsam şuradaki HAVING kısmında:

PHP:
if (!empty($selectedFeatures)) {
    $features = implode(',', $selectedFeatures);
    $productSql .= " AND UrunID IN (
        SELECT urunID
        FROM urnozellik_tbl
        WHERE OzellikID IN ($features)
        GROUP BY urunID
        HAVING COUNT(DISTINCT OzellikID) = " . count($selectedFeatures) . "
    )";
}
"Sorun" dediğime bakmayın, aslında mantıklı bir filtre ama sisteminizin dilediğiniz şekilde çalışmasını burası engelliyor.



Bir ürün aynı anda 64 GB ve 128 GB hafızaya sahip olamaz -herhalde- ama 64 GB hafıza ve 48 MP kameraya sahip olabilir çünkü ikisi farklı türden özellikler.

İki sorguda da count($selectedFeatures) = 2 olacaktır ama ilk sorguda COUNT(DISTINCT OzellikID) = 1 olacaktır.

Filtre mantığınızda filtrelenecek cihazların seçilen tüm özelliklere sahip olmasını istiyorsunuz. Bu, tüm özellikler farklı türden olduğunda doğru bir işlem oluyor ancak aynı türden özellikler için "ve" (AND) değil de "veya" (OR) demelisiniz:
  • 64 GB veya 128 GB
  • 64 GB ve 48 MP
Bunun için işe, aynı türden özellikleri kendi içlerinde gruplayarak başlamak güzel bir fikir olabilir. Her özellik türünden seçilen değerler birer listede toplanır, sonra bu listeler kapsayıcı bir liste içine alınıp $selectedFeatures olarak gönderilir. Mesela:
PHP:
[
    ["64 GB", "128 GB", "256 GB"],
    ["48 MP", "64 MP"],
    ["4000 mAh"]
]
Ben isimlerini yazdım da ID'leri olacak tabii sizin kodunuza göre.

Burada $features'ın bunun tek boyuta indirilmiş hâli olması uygun sanırım: ["64 GB", "128 GB", "256 GB", "48 MP", "64 MP", "4000 mAh"].

Bu değişikliklerden sonra, en yukarıda alıntıladığım sorgu aynen öyle kalabilir gibi, gözümden bir şey kaçmadıysa. Tabii frontend kısmında da değişiklikler gerekecek.

Alternatif yollar mevcuttur illaki. Mesela, veri tabanında bir özellik türü tablosu oluşturulup $selectedFeatures'taki farklı özellik türlerinin sayısı oradan elde edilebilir ve count($selectedFeatures) yerine kullanılabilir. Frontend'de değişikliğe gerek kalmaz.
hocam kendi içinde gruplama kısmını anlayamadım "Ozelllik_tbl" tablomda isimlerine göre grupladım ben bu özellikleri örnek olarak veri göstereyim. bu şekilde olmaz mı(ek olarak 64g ve 128gb seçeneklerini seçip sorguyu ekrana yazdırdım onu veri tabanında sorgulattığımda işe yaramıyor ama sizin dediğiniz gibi count =1 yaparsam getiriyor) işte bozuk olan çalışmayan sorgu şu şekilde
SELECT * FROM Urunler_tbl WHERE durum = 1 AND UrunID IN ( SELECT urunID FROM urnozellik_tbl WHERE OzellikID IN (1,4) GROUP BY urunID HAVING COUNT(DISTINCT OzellikID) = 2 )
 

Dosya Ekleri

  • Screenshot_3.png
    Screenshot_3.png
    11,9 KB · Görüntüleme: 10
Önceki mesajımı okuyup sorunu iyice anlamaya odaklanın.

HAVING COUNT(DISTINCT OzellikID) = " . count($selectedFeatures) . "

Burada, seçilen özelliklerin sayısına (count($selectedFeatures)) göre değil seçilen özellik türlerinin sayısına göre filtreleme yapmak doğru olacak. Sizde özellik türü tam neye karşılık geliyor bilmiyorum. (OzAdi, kategori) kombinasyonuna denk olabilir.

Aynı türden iki özellik seçtiğinizde (örneğin 64 GB ve 128 GB) COUNT(DISTINCT OzellikID) = 1 olurken count($selectedFeatures) = 2 oluyor ve bu yüzden sorgu istediğiniz gibi çalışmıyor.
 
Aynı türden iki özellik seçtiğinizde (örneğin 64 GB ve 128 GB) COUNT(DISTINCT OzellikID) = 1 olurken count($selectedFeatures) = 2 oluyor ve bu yüzden sorgu istediğiniz gibi çalışmıyor.
sanırım formuyla alakalı bi problem hangi seçenek olursa olsun özellik kabul ettiğinden yapıyor formda şu şekilde
PHP:
<h2>Ürün Özellikleri</h2>
                    <ul class="list-group">
                       <?php      
$sql = "SELECT o.*, oa.OzAd
        FROM Ozellik_tbl o
        INNER JOIN OzAd oa ON o.OzAdi = oa.OzADID
        WHERE o.kategori = 1";
$result = $conn->query($sql);

// Özellikleri gruplayarak listeleme
$groupedProperties = array();
if ($result->num_rows > 0) {
    while($row = $result->fetch_assoc()) {
        $propertyName = $row["OzAd"];
        $propertyValue = $row["deger"];
       
        // Grup adına göre özellikleri gruplama
        if (!isset($groupedProperties[$propertyName])) {
            $groupedProperties[$propertyName] = array();
        }
        $groupedProperties[$propertyName][] = array(
            "id" => $row["OzID"],
            "value" => $propertyValue
        );
    }
   
    // Grupları listeleme
    foreach ($groupedProperties as $propertyType => $properties) {
        echo '<li class="list-group-item">';
        echo '<h5>' . $propertyType . '</h5>';
       
        foreach ($properties as $property) {
            echo '<input type="checkbox" name="selected_features[]" value="' . $property["id"] . '">';
            echo $property["value"] . '<br>';
        }
       
        echo '</li>';
    }
   
} else {
    echo '<li class="list-group-item">Özellik bulunamadı.</li>';
}
?>

                    </ul>

Önceki mesajımı okuyup sorunu iyice anlamaya odaklanın.



Burada, seçilen özelliklerin sayısına (count($selectedFeatures)) göre değil seçilen özellik türlerinin sayısına göre filtreleme yapmak doğru olacak. Sizde özellik türü tam neye karşılık geliyor bilmiyorum. (OzAdi, kategori) kombinasyonuna denk olabilir.

Aynı türden iki özellik seçtiğinizde (örneğin 64 GB ve 128 GB) COUNT(DISTINCT OzellikID) = 1 olurken count($selectedFeatures) = 2 oluyor ve bu yüzden sorgu istediğiniz gibi çalışmıyor.
hocam her şey için teşekkür ederim sorun formdaymış kodu şu şekilde düzelttim ve şuan çalışıyor
PHP:
<h2>Ürün Özellikleri</h2>
<ul class="list-group">
<?php
$sql = "SELECT o.*, oa.OzAd
        FROM Ozellik_tbl o
        INNER JOIN OzAd oa ON o.OzAdi = oa.OzADID
        WHERE o.kategori = 1";
$result = $conn->query($sql);

// Özellikleri gruplayarak listeleme
$groupedProperties = array();
if ($result->num_rows > 0) {
    while ($row = $result->fetch_assoc()) {
        $propertyName = $row["OzAd"];
        $propertyValue = $row["deger"];

        // Grup adına göre özellikleri gruplama
        if (!isset($groupedProperties[$propertyName])) {
            $groupedProperties[$propertyName] = array();
        }
        $groupedProperties[$propertyName][] = array(
            "id" => $row["OzID"],
            "value" => $propertyValue
        );
    }

    // Grupları listeleme
    foreach ($groupedProperties as $propertyType => $properties) {
        echo '<li class="list-group-item">';
        echo '<h5>' . $propertyType . '</h5>';

        foreach ($properties as $property) {
            echo '<input type="checkbox" name="selected_features[' . $propertyType . '][]" value="' . $property["id"] . '">';
            echo $property["value"] . '<br>';
        }

        echo '</li>';
    }
} else {
    echo '<li class="list-group-item">Özellik bulunamadı.</li>';
}
?>
</ul>
 
Son düzenleme:
Hocam her şey için teşekkür ederim. Sorun formdaymış, kodu şu şekilde düzelttim ve şu an çalışıyor.

Elinize sağlık, düzelttiğiniz kısmı gördüm: name="selected_features[' . $propertyType . '][]".

Form kodunuzu yeterince iyi incelememişim, kusura bakmayın. Tam da anlattığım şeyi yapmaya çalışıyormuşsunuz zaten en başından beri. Gayet doğru düşünmüşsünüz. : )
 

Geri
Yukarı