v2.5.2
Giriş yap

Ürün varyosyonları alt özellikleri nasıl oluşturulur.

kartal
219 defa görüntülendi

Burada ki her seçeneğin adet grupları ve fiyatları var
örnek

Klasik varyasyon görüntüsü sonucu benim oluşturduğum

Klasik tablo yapım
option (Renk,Beden vb)
option values (s,m,l - sarı,mavi,beyaz vb)
product option values (option values tablosunda ki id değerler)
varyant tablosu (her kombinasyonun id si resim dekilerin kaydedilmiş satırları)

Burada farklı olarak linkte adet grupları verilmiş bunlar özelliklere göre değişmezse sorun olmaz gibi.
Ancak diyelim ki dijital baskı adet grubu 100,200,500 adet ve top. fiyatları
Dijital baskı
1 adet 10 tl.
5 adet 45 tl.
10 adet 80 tl.

Öte yandan ölçü belirten bir özellik seçildiğin de de fiyat alanları değişmeli.
2 farklı ölçü ye göre fiyat alanları.

Aslında karışık görünsede tasarımı oluşturulmayınca kafa kurcakıyor fikirleriniz nedir.
Şimdiden teşekkürler.

ebykdrms
187 gün önce

Uzun ve açıklayıcı bir cevap olacak.
Senin işine yaramıyorsa bile birileri faydalanabilsin diye...

Kırılım oluşturmak için şöyle bir tablo kullanabilirsin:
id
top_id
type
image
name
price
quantity
...
Kırılım oluşturabileceğin yapıyı "id" ve "top_id" sağlıyor.
Mesela:
{id: 1, top_id: 0, type: 1, name: "Sandalye", ...}
{id: 2, top_id: 1, type: 2, name: "Sarı", ...}
{id: 3, top_id: 1, type: 2, name: "Mavi", ...}
{id: 4, top_id: 2, type: 3, name: "Küçük Boy", ...}
{id: 5, top_id: 2, type: 3, name: "Orta Boy", ...}
{id: 6, top_id: 3, type: 3, name: "Küçük Boy", ...}
Burada bir "Sandalye" ürünümüz var. type:1 diyerek ürünün tüm kombinasyonlarını içeren bir kapsayıcı olduğunu belirttik.
type:2 olanlar renkleri temsil ediyor. Her ürününün birkaç rengi olabilir. top_id:1 ve type:2 olanlar, Sandalye ürününün renklerini belirtiyor.
type:3 olanlar da ebatları temsil ediyor. Her rengin birkaç ebatı olabilir. top_id:2 ve type:3 olanlar, Sandalye ürününün sarı renginin farklı ebatlarını belirtiyor.

burada type ifadesini ben uydurdum. Hangi düzeyde olduğumuz belli olsun diye...
top_id de ilgili kaydın bir üst düzeyinde hangi kayıt olduğunu belirtiyor.
Böylece aşağıdaki yapıyı elde ettik:
Sandalye (id:1) -> Sarı (id:2, top_id:1) -> Küçük Boy (id:4, top_id:2)
Sandalye (id:1) -> Sarı (id:2, top_id:1) -> Orta Boy (id:5, top_id:2)
Sandalye (id:1) -> Mavi (id:3, top_id:1) -> Küçük Boy (id:6, top_id:3)

Tabi ben örnek olarak renklerin(type:2) ebatları(type:3) olması gerektiğini belirledim. Ama ebatların renkleri de olabilirdi. Kırılımı nasıl yapacağın projene göre değişir...
Fiyatlar meselesine gelince, tablonun her kaydı için bir fiyat alanı var malum. Burada da "varsayılan fiyat" kullanmak mümkün.
Mesela bir ürüne (type:1 düzeyinde) fiyat verirsek ve alt kırılımlarında fiyat alanını boş bırakırsak, varsayılan olarak ürünün fiyatı kullanılabilir.
Yani bir ebatı ekrana basarken eğer fiyat bilgisi yoksa, onun üst düzeyindeki fiyat bilgisini varsayılan olarak kullanabiliriz. Onun üst düzeyinde de fiyat yoksa onun da üst düzeyine çıkabiliriz...
Örneğin bir sandalyenin fiyatı 100TL ise tüm renk ve ebatlarının fiyatı da 100TL olur.
Ama eğer mavi renkli sandalyeler 200TL olsun istersek, sandalyenin fiyatı 100TL olmasına rağmen mavi (id:3) renk için 200TL fiyat yazabiliriz. Böylece mavi renkli sandalyeler (tüm ebatları için) 200TL olur.
Eğer tüm sandalyeler 100TL olsun ama sadece sarı renkli ve orta boy sandalyeler 150TL olsun dersek, sandalye (id:1) için 100TL yazarız. Renkler (id:2 ve id:3) için fiyat vermeyiz. Orta boy ebat için (id:5) 150TL fiyat veririz...

Tabi diğer bir mesele de bu verilerin nasıl SELECT edilebileceği...
Bir ürünün tüm kayıtlarını almak istiyoruz diyelim.
Sadece SELECT * FROM products WHERE id=1 desek, sadece ürünü seçebiliriz. Hiçbir kırılımı seçmemiş oluruz.
SELECT * FROM products WHERE id=1 OR top_id=1 desek, ürünü ve renklerini seçebiliriz. Ama ebatları seçememiş oluruz.

---Ebatları seçmek için aşağıda birkaç yaklaşımda bulundum ama bunları okumayabilirsin :)---
Ebatları de almak için farklı bir sorgu yapısına ihtiyaç var. Bu tür bir veri yapısında tüm alt seviyeleri almak için genellikle rekürsif sorgular kullanılır. MySQL'de, 8.0 sürümünden itibaren rekürsif Common Table Expressions (CTE) kullanılabiliyor.
Örnek sorgu olarak (bunu ChatGPT 3.5'e yazdırdım):
WITH RECURSIVE ProductHierarchy AS (SELECT * FROM products WHERE id = 1 UNION ALL SELECT p.* FROM products p INNER JOIN ProductHierarchy ph ON p.top_id = ph.id) SELECT * FROM ProductHierarchy
Veya CTE kullanmadan JOIN yardımıyla bir sorgu (bunu da ChatGPT 3.5'e yazdırdım):
SELECT p1.*, p2.*, p3.* FROM products p1 LEFT JOIN products p2 ON p2.top_id = p1.id LEFT JOIN products p3 ON p3.top_id = p2.id WHERE p1.id = 1
Her türlü veritabanını çok yoracak işlemler bunlar. Hoş değil.
---okumaya devam---

Aslında veritabanına bir sütun daha eklemek bütün sorunumuzu çözer. Tüm ebatlar için ürün id'sini de tutan bir sütuncuk:
{id: 1, top_id: 0, product_id: 1, type: 1, name: "Sandalye", ...}
{id: 2, top_id: 1, product_id: 1, type: 2, name: "Sarı", ...}
{id: 3, top_id: 1, product_id: 1, type: 2, name: "Mavi", ...}
{id: 4, top_id: 2, product_id: 1, type: 3, name: "Küçük Boy", ...}
{id: 5, top_id: 2, product_id: 1, type: 3, name: "Orta Boy", ...}
{id: 6, top_id: 3, product_id: 1, type: 3, name: "Küçük Boy", ...}
product_id adlı bir sütun kullanarak tüm alt kırılımlara, en üst düzeyde hangi ürüne ait olduklarını belirtmiş olduk.
Böylece ürüne ait tüm verileri basit bir sorguyla çekebilir haldeyiz:
SELECT * FROM products WHERE product_id=1
Tabi burada da ayrı bir sorunla karşılaşıyoruz. Ürünü INSERT ederken id'sinin ne olduğunu bilmediğimiz için product_id'sini belirtemeyeceğiz.
Bu durumda bir ürün insert ettikten sonra bir de update sorgusu çalıştırmamız gerekir. Örnek:

$sql = "INSERT INTO products (top_id, product_id, type, name) VALUES (:top_id, NULL, :type, :name)";
$stmt = $pdo->prepare($sql);
$stmt->execute([':top_id' => 0, ':type' => 1, ':name' => 'Sandalye']); // ürünü ekledik...
$lastId = $pdo->lastInsertId(); // son eklenen id değerini aldık...
$updateSql = "UPDATE products SET product_id = :product_id WHERE id = :id";
$updateStmt = $pdo->prepare($updateSql);
$updateStmt->execute([':product_id' => $lastId, ':id' => $lastId]); // product_id değerini id olarak belirledik...

Tabi bununla uğraşmak yerine SELECT sorgumuz aşağıdaki gibi de olabilirdi:
SELECT * FROM products WHERE id=1 OR product_id=1
Ama o zaman mysql'i her select işleminde 2 sütun kontrol etmesi için uğraştırmış olacaktık. Oysa ki insert işleminde bir kere uğraştırıp update sorgusu da göndermek daha uygun olacaktır.
Tabi bu sadece yeni bir ürün eklerken gereken bir işlem. Kırılımlar eklerken zaten ürünün id değeri elimizde olacağı için böyle bir update'e gerek yok.

Peki ürünleri bu şekilde aldık diyelim. Select sorgusundan sonra elimizde şöyle bir array olacak:

[
    ['id' => 1, 'top_id' => 0, 'product_id => 1, 'type' => 1, 'name' => 'Sandalye', ...],
    ['id' => 2, 'top_id' => 1, 'product_id => 1, 'type' => 2, 'name' => 'Sarı', ...],
    ['id' => 3, 'top_id' => 1, 'product_id => 1, 'type' => 2, 'name' => 'Mavi', ...],
    ['id' => 4, 'top_id' => 1, 'product_id => 1, 'type' => 3, 'name' => 'Küçük Boy', ...],
    ['id' => 5, 'top_id' => 1, 'product_id => 1, 'type' => 3, 'name' => 'Orta Boy', ...],
    ['id' => 6, 'top_id' => 1, 'product_id => 1, 'type' => 3, 'name' => 'Küçük Boy', ...],
    ...
]

Ama bu front-end'de işlenmek için uygun bir yapı değil. Hiyerarşik olarak uygun bir yapıya çevrilmeli. Ama bu çevrim işini back-end'e yıkmak yerine front-end'e (kullanıcının tarayıcısına) yıkmak daha uygun olur. Bu yüzden veriyi json formatında front-end'e ilettik diyelim. Front-end'de bu veri elimizde json formatında gelmiş olsun:

const response = [
    {id: 1, top_id: 0, type: 1, product_id: 1, name: "Sandalye", ...},
    {id: 2, top_id: 1, type: 2, product_id: 1, name: "Sarı", ...},
    {id: 3, top_id: 1, type: 2, product_id: 1, name: "Mavi", ...},
    {id: 4, top_id: 2, type: 3, product_id: 1, name: "Küçük Boy", ...},
    {id: 5, top_id: 2, type: 3, product_id: 1, name: "Orta Boy", ...},
    {id: 6, top_id: 3, type: 3, product_id: 1, name: "Küçük Boy", ...},
    ...
];

Bu veriyi bir hizaya sokmak için bir fonksiyonumuz olsun. (ChatGPT 3.5)

function buildHierarchy(data) {
    const hierarchy = [];

    // Her bir ürünü işle
    data.forEach(item => {
        // Ürünün hiyerarşik konumunu bul
        const parent = hierarchy.find(parentItem => parentItem.id === item.top_id);

        // Ürünün alt elemanları için "items" dizisini oluştur
        if (!item.items) item.items = [];

        // Eğer ürünün "top_id" değeri 0 ise, ana hiyerarşik yapıya ekle
        if (item.top_id === 0) hierarchy.push(item);
        else {
            // Eğer ürünün "top_id" değeri 0 değilse, parent'ının alt elemanlarına ekle
            if (parent) parent.items.push(item);
        }
    });

    // Derinlik kontrolü
    const addItemsRecursively = items => {
        items.forEach(item => {
            const children = data.filter(child => child.top_id === item.id);
            if (children.length > 0) {
                item.items = children;
                addItemsRecursively(item.items);
            }
        });
    };

    addItemsRecursively(hierarchy);

    return hierarchy;
}

// Kullanırken:
const hierarchy = buildHierarchy(response);

Böylece gelen veriyi şu hale getirmiş olacağız:

const hierarchy = [
    {
        id: 1, 
        top_id: 0, 
        type: 1, 
        product_id: 1, 
        name: "Sandalye",
        items: [
            {
                id: 2, 
                top_id: 1, 
                type: 2, 
                product_id: 1, 
                name: "Sarı",
                items: [
                    {id: 4, top_id: 2, type: 3, product_id: 1, name: "Küçük Boy", items: []},
                    {id: 5, top_id: 2, type: 3, product_id: 1, name: "Orta Boy", items: []},
                ]
            },
            {
                id: 3, 
                top_id: 1, 
                type: 2, 
                product_id: 1, 
                name: "Mavi",
                items: [
                    {id: 6, top_id: 3, type: 3, product_id: 1, name: "Küçük Boy", items: []},
                ]
            }
        ]
    },
    ...
];