Net olarak herhangi bir yöntemi doğru kabul edemiyoruz. Tarayıcıda yaptığımız geliştirmeler tam olarak gerçek cihazı taklit edemiyor. Emulatörlerden kontrol edilen geliştirmeler daha doğru sonuç verse de kaç emülatörde test edebiliriz ki...
Mecburen tarayıcıyı doğru kabul ediyoruz ama cihazların dpi farklarını da hesap ederek, aslında zihnen çalışan bir emülatör üzerinden geliştirme yapıyoruz. Responsive geliştirme yaparken tarayıcının sunduğu örnek cihazları doğru kabul edemeyiz. Bu yüzden manuel olarak genişliği iyice daraltmak, zoom out yapıp genişliği iyice artırmak gibi denemeler yapıp her duruma uygun kod yazmak gerek.
Çok daha doğru sonuç vermesi için en düşük ekran genişliğine sahip ios ve android sistemli cihazlarda test etmek iyi olabilir. Ama pratikte böyle testler geliştirici için çok zaman alacak, projenin tamamlanma süresini uzatacaktır. Bu yüzden proje en azından ilk başta sadece tarayıcı üzerinden kontroller sağlanarak tamamlanabilir. En sonunda da emülatör testleri yapılıp ona uygun düzeltmeler yapılabilir.
Kendi adıma, projemi geliştirirken sadece tarayıcı üzerinde geliştirmemi yapıyorum. Zaman içinde tecrübe edindiğim için hangi CSS kodunun IOS'taki Safari tarayıcısında farklı davranacağını biliyorum. O CSS koduna alternatif üretemiyorsam mecburen gerçek bir cihaza ya da emülatöre bakıyorum.
HTML yapısını kurarken mümkün mertebe IOS'un Safari'sinin sistemini baz alıyorum çünkü çok katı kurallara sahip. Mesela bir elementi position:fixed
ile en üst düzeyde göstermem gerekiyorsa, o elementi DOM'da da en üst düzeyde tutmaya çalışıyorum. Çünkü Chrome tarayıcısı geliştirici dostu bir yaklaşımla benim stil yazarken ne kastettiğimi anlayıp ona uygun bir görünümü render edebiliyor ama Safari geliştiriciden net olmasını bekliyor.
Özellikle yeni CSS komutlarını kullanmaktan kaçınıyorum ama eğer kullanmam çok yerinde olacaksa mecburen tarayıcı farklılıklarını gözeterek kullanmam gerekiyor.
Verdiğin örnekte bir yükseklik problemi görünüyor. IPhone bu modelinde -utanmasa- kare ekran kullanacakmış da yine de yüksekliğe biraz daha pay vermiş sağ olsun. Bu daracık alanda güzel bir tasarım çıkarmak zor. Ama ille de buraya özgü de bir çalışma yapılması gerekecekse mecburen media query'leriyle min-height konrolüne göre stilleri overload etmek gerek. Belki header'ın height değerinden kısmak, başlığın puntosunu küçültmek, kutuların tasarımlarını daha küçük bir yapıda sunmak...
Ama işte bunun da bir sonu yok. Sadece ekranın width değeri olsa neyse de ekranın height değeri de devreye girince 4 kombinasyon çıkıyor, işler iyice birbirine geçiyor. Zaman da önemli bir faktör olduğundan en doğrusu projeyi sadece tarayıcı kontrolleri yaparak sürdürmek ve sadece mobil cihazlarda sorun olacağı çok belli stiller için mobil cihazda kontroller yapmak gerek. Sonrasında proje tamamlanınca kullanıcı dönüşlerine göre açıklar kapatılabilir.
O uygulamanın algoritmasını bilmeden buna cevap veremeyiz.
Eğer uygulama kullanmayı zorunlu tutuyorlarsa sanırım
bildirim yoluyla gönderiyorlar otp kodunu. Bu bildirimi
alabilmen için o uygulamayı kullanmak zorundasın çünkü
bildirimi gönderen sistem (belki firebase) doğrudan
o uygulamaya yönlendirilmiştir.
Eğer otp kodu sms yoluyla geliyorsa belki tarayıcıyı
mobil uygulama gibi gösterip login ekranını görüntülemek
mümkün olabilir ama yine o sitenin kurgusunu bilmek lazım.
Eğer otp kodunu web sitesinde gösteriyor ve uygulamanın
login ekranında web sayfasındaki kodu yazmanı istiyorsa
belki de web tarafında hiç login sayfası yoktur veya
o uygulamadan gönderilen bazı şifreli bilgiler olmadan
web'deki login ekranına erişim engellenmiştir. Bu durumda
yine yazacağın mobil uygulamayla o ekranı görüntülemen
mümkün olmaz.
Türlü hack denemeleri yapılabilir ama yapmamak gerek.
Belli ki her hesabın sadece 1 kullanıcısı olsun istiyorlar.
Böylece, giriş yapmak isteyen kişi kimse zaten telefonu da
yanındadır ve kendi hesabına kolayca giriş yapabilir.
Aksi halde sanırım en uygun yol 1 kullanıcının birkaç farklı
hesaba tek uygulama üzerinden girebilmesi için ilgili
firmayla iletişime geçip geliştirme yapmaları istenebilir.
Muhtemelen bu tahminlerimin hiçbiri tutmadı. Sitenin
kurgusunu tahmin ederek bir yanıt vermem mümkün değil.
Ama soruna yanıt olarak, kendi uygulamanı yazman bu sorununu
çözmeyecektir çünkü uygulama ile sunucu muhakkak
o uygulamaya özgü ve değişken bir şifreleme ile
haberleşiliyordur. Sen türlü yazılımlar kullanarak o
uygulamadan sunucuya atılan istekleri görüp aynı istekleri
kendi uygulamandan sunucuya atamazsın. Çünkü o isteklerde
muhakkak uygulama içindeki verileri de içeren bir token
bulunuyordur. Sen sunucuya header değişiklikleri ile
kendini o uygulama gibi gösterip token'ı da isteğe
eklediğinde, yine de güvenlik önlemine takılacaksın.
Çünkü token, uygulama içinde şifreleniyor ve bu şifrenin
nasıl açılacağını sadece uygulama ve sunucu biliyor. Haliyle
bu token'ı taklit etmen mümkün değil.
Tabi sistemde böyle güvenlik önlemleri almamış da olabilirler.
Belki de PostMan üzerinden header değişiklikleriyle yapacağın
basit bir login isteğine yanıt verecektir, kim bilir...
Çok ucu açık bir soru. Aslında ne yapacağın çok belli. Veritabanına eklediğin kişi sayısı 100'e ulaşmışsa yeni kişi kaydetmeyeceksin. Kullanıcılara da tablonda kaç kişinin kayıtlı olduğunu göstereceksin. Anlık bir gösterim için websocket veya socket.io gibi bir yapı kullanman gerekir ama basit xhr/ajax istekleriyle de işi kotarabilirsin.
Soruyu sorarken cevabı zaten vermişsin yani. O yüzden tam olarak ne sorduğunu anlayamadım sanırım. Doğrudan kod yazmamızı istiyor olabilir misin?
Çok özel bi'proje istenmiyorsa bu tip siteler için en güzeli Wordpress'le yapıp geçmek.
Ben de müşterilerime panel yapardım. Ama paneli sanki kendim için yazıyor gibiydim.
Çoğunlukla panele giriş şifresini bile sormuyorlar.
Aslında başta söylüyorum, paneliniz olursa şu kadar olmazsa bu kadar diye...
Olsun, diyorlar ama neye para ödediklerine girip bakmıyorlar bile.
En güzeli Wordpress için hazır bir tema seçip içini doldurup teslim etmek.
Peki ben bugüne kadar kaç Wordpress site verdim müşterilerime? Sıfır!
Neden? Çünkü bende o ticari kafa yok.
Adam sıfırdan site oluşturuyormuş gibi fiyat çekiyor müşterisine ama yarım günde Wordpress'le siteyi tamamlayıp kenarda bekletiyor. İşin sonunda müşteri "bana niye wordpress site yaptın da bu kadar para aldın" diye sormuyor. Anlamıyor çünkü. Wordpress ne ki? Onun için sıfırdan olmasıyla hazır olması arasında bir fark yok. Aradaki fark bizim için büyük gibi görünse de onun için anlamlı bir fark değil.
Wordpress öğrenirsen, bu tip işleri 4-5 saat bile sürmeden tamamlarsın. Yani günde 2-3 iş bile tamamlayabilirsin. Bu kadar saati de Wordpress site yayınlamanın uğraştırıcı olmasından değil, içerik girmekle uğraşmanın zaman almasından dolayı veriyorum. Yani içeriği de müşterinin kendisinin girmesini istersen her saat bir iş tamamlayabilirsin.
Tanesi 10 bin liradan (sunucu/domain masrafları hariç) 100 müşteri bulup işi tamamladığında 1 milyon lirayı cebine koyarsın.
Wordpress'i ve yayınlama süreçlerini iyi biliyorsan, içerik girme işini de müşteriye veya bir arkadaşına uygun bir fiyatla (mesela 4bin lira versen saatte bin lira vermiş olursun) yaptırabiliyorsan, çevrende çok da iş varsa...
Kısacası, potansiyel olarak -teoride- birkaç ay içinde milyon lira kazanman mümkün.
Ben bunu biliyorum. Peki milyon lira kazanabildim mi? Hayır! Neden?...
PHP, C#, Python, Nodejs gibi sistemleri öğrenmek sana istediğin her şeyi yapabilme gücü verir. Wordpress temalarına bağımlı kalmazsın. Wordpress temaları yapan adam olabilirsin. Kendi yapay zeka algoritmanı eğitip ses, görüntü, türlü veriler işleyebilirsin. Yapabileceklerin senin hayal gücüne kalmış. Potansiyel olarak -teoride- bu da seni milyoner yapar.
Peki mesela ben milyoner miyim? Hayır! Neden?...
İçimi dökesim varmış, bol bol yazdım.
Şu anki ruh halimde sana Wordpress'i iyi öğrenmeni ve sana iş getirecek bir çevre edinmeni öneriyorum. :)
Bir ChatGPT 4o sohbetinden özetle:
Görev Zamanlayıcı Kullanarak
~ Başlat menüsüne "Görev Zamanlayıcı" yazarak (Task Scheduler) görev zamanlayıcıyı aç..
~ Sağ taraftaki "Görev Oluştur..." seçeneğinden...
~ ~ Genel sekmesinde görev adını ve açıklamasını gir. (örn. "Tkinter Program").
~ ~ Tetikleyiciler sekmesinde Yeni butonuna bas. "Görev başladığında" seçeneğini seç.
~ ~ Eylemler sekmesinde Yeni butonuna bas.
~ ~ ~ Eylem kısmında "Program başlat"ı seç.
~ ~ ~ Program/komut dosyası alanına Python yürütülebilir dosyasının path'ini gir (örn. C:\Python39\python.exe).
~ ~ ~ "Argüman ekle (isteğe bağlı)" kısmına da Python script'inin yolunu gir (örn. C:\Kullanıcılar\KullanıcıAdı\Desktop\programım.py).
~ ~ Koşullar ve Ayarlar sekmelerinde gerekirse diğer yapılandırmaları yap.
~ Görevi kaydet ve çık.
Başlangıç Klasörünü Kullanarak
~ Python script'in için bir kısayol oluştur:
~ ~ Script dosyana sağ tıkla ve "Kısayol oluştur"a bas.
~ Kısayolu Başlangıç klasörüne taşı:
~ ~ Win + R tuşlarına basarak "Çalıştır" penceresini aç.
~ ~ shell:startup
yazıp ve Enter'a basınca açılan klasöre kısayolunu taşı.
Kayıt Defteri (Registry) Düzenlemesi ile
~ Kayıt Defteri Düzenleyicisini Aç:
~ ~ Win + R tuşlarına basarak "Çalıştır" penceresini aç.
~ ~ regedit
yazıp Enter'a bas.
~ ~ Kayıt Defteri Düzenleyicisi'nde şu anahtara git: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
~ ~ Yeni Bir Değer Ekle:
~ ~ ~ Sağ taraftaki boş alana sağ tıkla ve "Yeni" > "Dize Değeri" (String Value) seçeneğini seç.
~ ~ ~ Değer adı olarak programının adını (örn. TkinterProgram) gir.
~ ~ ~ Değer Verisini Ayarla:
~ ~ ~ ~ Yeni oluşturduğun değere çift tıkla ve açılan pencerede:
~ ~ ~ ~ ~ Değer verisi olarak Python yürütülebilir dosyasının yolunu ve kendi script'inin yolunu gir.
~ ~ ~ ~ ~ Örn. C:\Python39\python.exe C:\Kullanıcılar\KullanıcıAdı\Desktop\programım.py
Programının bilgisayar açıldıktan sonra hemen çalışmasını sağlamak için en etkili yöntem, kayıt defteri (Registry) düzenlemesidir.
Registry düzenlemesi, bilgisayar başlatıldığında uygulamanın çalışmasını garanti eden doğrudan bir yoldur ve genellikle diğer yöntemlerden daha hızlı çalışır çünkü işletim sistemi yüklenirken bu ayar hemen işleme konur.
Bonus: Programı kayıt defteri ile çalıştırmak istiyorum ama bahsettiğin adımları uygulamak çok zahmetli. Bu adımları benim yerime yapacak bir bat dosyası hazırla ve bu dosyaya çift tıkladığımda bu ayarlar otomatik olarak yapılsın.
Cevap özeti:
Tabii, aşağıda vereceğim batch dosyası (bat dosyası) ile kayıt defterine gerekli ayarları ekleyebilirsin. Bu batch dosyasını çalıştırdığında, Python programının bilgisayar açıldığında otomatik olarak çalışması için gerekli kayıt defteri ayarları yapılacaktır.
Not Defteri'ni (Notepad) Aç.
Aşağıdaki kodu Not Defteri'ne yapıştır. (Tabi Python yürütülebilir dosyasının yolunu, programının adını ve script dosyanın yolunu doğru şekilde yazarak):
@echo off
setlocal
set PYTHON_PATH=C:\Python39\python.exe
set SCRIPT_PATH=C:\Kullanıcılar\KullanıcıAdı\Desktop\programınız.py
reg query "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" /v ProgramiminAdi >nul 2>&1
if %ERRORLEVEL% equ 0 (
echo Kayıt defteri ayarları zaten yapılmış.
) else (
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" /v ProgramiminAdi /t REG_SZ /d "\"%PYTHON_PATH%\" \"%SCRIPT_PATH%\"" /f
echo Kayıt defteri ayarları başarıyla yapıldı.
)
pause
Not Defteri'nde "Dosya" menüsünden "Farklı Kaydet"e bas.
Dosya adı olarak "programimi_kur.bat" yaz.
"Kayıt türü" bölümünde "Tüm Dosyalar" (All Files) seçeneğini seç.
Dosyayı uygun bir konuma kaydet.
Bu bat dosyasını çift tıklayıp çalıştırdığında kayıt defteri ayarlarının yapıldığını belirten bir mesaj görmelisin.
Dosyayı çalıştırıken Yönetici olarak çalıştır diyerek açman gerekebilir.
Daha detaylı bi'şeyler yapmak istersen veya hata alırsan yukarıda verdiğim yazışmaları kullanarak ChatGPT konuşmasını devam ettirebilirsin...
Apple > System Settigns... > Displays altında 2 monitör de görünüyor olmalı. İki monitöre de ayrı ayrı tıklayıp Color Profile değerlerini aynı yapmayı deneyebilirsin.
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: []},
]
}
]
},
...
];
Safari'de inspect var. Sadece, geliştirici olmayanların işine yaramayacağı için varsayılan olarak kapalı geliyor.
Üst menüden Safari > Settings... > Advanced sekmesinin en altında Show features for web developers kutusunu işaretleyerek aktif edebilirsin.
ChatGPT 3.5 ile biraz yazıştım. Yazışmamızın sonucu:
Esnek bir arama fonksiyonu oluşturmak için basit bir yaklaşım, terimlerin benzerliğini kontrol etmek için bir tür benzerlik ölçüsü kullanmaktır. Örneğin, iki metin arasındaki benzerliği Levenshtein mesafesi gibi bir ölçümle değerlendirebiliriz. Levenshtein mesafesi, iki metin arasındaki karakter dizisi farkını belirler.
Bu kodda, levenshteinDistance fonksiyonu iki metin arasındaki Levenshtein mesafesini hesaplar. flexibleSearch fonksiyonu, verilen sorgu ve alan adına göre, veri kümesindeki her bir öğe için benzerlik kontrolü yapar ve sonuçları döndürür.
Bu örnek, belirli bir benzerlik eşik değeri kullanır ve bu eşik değeri değiştirilebilir (3.parametre). Bu sayede, isteğe bağlı olarak daha sıkı veya daha gevşek bir eşik belirlenebilir.
// Veri
const data = [
{ id: 1, name: "John Doe", age: 30, city: "New York" },
{ id: 2, name: "Jane Smith", age: 25, city: "Los Angeles" },
{ id: 3, name: "Alice Johnson", age: 35, city: "Chicago" },
{ id: 4, name: "Ata Kuzey", age: 35, city: "Chicago" }
];
// Levenshtein mesafesi hesaplama fonksiyonu
function levenshteinDistance(a, b) {
if (a.length === 0) return b.length;
if (b.length === 0) return a.length;
const matrix = [];
// İlk satır ve sütunun başlangıç değerleri
for (let i = 0; i <= b.length; i++) {
matrix[i] = [i];
}
for (let j = 0; j <= a.length; j++) {
matrix[0][j] = j;
}
// Levenshtein mesafesi hesaplama
for (let i = 1; i <= b.length; i++) {
for (let j = 1; j <= a.length; j++) {
if (b.charAt(i - 1) === a.charAt(j - 1)) {
matrix[i][j] = matrix[i - 1][j - 1];
} else {
matrix[i][j] = Math.min(
matrix[i - 1][j - 1] + 1,
matrix[i][j - 1] + 1,
matrix[i - 1][j] + 1
);
}
}
}
return matrix[b.length][a.length];
}
// Veriye esnek bir arama yapmak için fonksiyon
function flexibleSearch(query, field, threshold) {
const results = [];
for (const item of data) {
// Levenshtein mesafesi hesaplayarak benzerlik kontrolü
if (levenshteinDistance(query.toLowerCase(), item[field].toLowerCase()) <= threshold) {
results.push(item);
}
}
return results;
}
// Örnek kullanım
const searchResults = flexibleSearch("Atalay Kuzey", "name", 5);
console.log(searchResults); // [{"id": 4, "name": "Ata Kuzey", "age": 35,"city": "Chicago"}]