n1crack / datatables

Simplify your Datatables server-side processing effortlessly using our lightning-fast PHP library, streamlining your workflow seamlessly.
https://datatables.ozdemir.be/
MIT License
267 stars 90 forks source link

DataTables Editor ile uyumluluk #62

Closed mertasan closed 4 years ago

mertasan commented 4 years ago

selamlar. gayet kullanışlı bir paket. teşekkür ederim öncelikle.

bir süredir kullanıyorum ancak şimdi DataTables Editor eklentisini edindim. veri güncelleme işlemleri ile yani editor ile uyumlu çalışır mı yoksa Editor eklentisinin server-side paketiyle mi devam etmeliyim?

teşekkürler.

n1crack commented 4 years ago

Bu kütüphane ile sadece gösterim tarafını yaparsın. Editör kısmını da yapmayı düşündüm ama çok karmaşık sorgular olabildiğinden her şeyi tanımlamak gerekiyor. Bu yüzden vazgeçmiştim.

Sonuç olarak editör desteklemiyor maalesef.

mertasan commented 4 years ago

hızlı yanıt için teşekkür ederim.

Çözüm açısından REST servisini kontrol ettim şimdi.. "sadece gösterim tarafını yaparsın" dediğinize göre aşağıdaki örnekte mevcut olan POST, PUT ve DELETE request isteklerini Editor ile başka server-side methoduna iletip, GET request isteği ile datayı alırken de sizin paketinizi kullansam bir uyumsuzluk olmaz o zaman dimi?

https://editor.datatables.net/examples/advanced/REST.html

sonuç olarak veri yapısını DataTables'e uyumlu olarak ürettiğiniz için bir problem çıkmayacağını düşünüyorum.

bir süre sonra geliştirmenize katkıda bulunacağım bu arada. iyi çalışmalar.

n1crack commented 4 years ago

Denemedim ama dediğiniz gibi bir problem çıkmaz diye düşünüyorum.

mertasan commented 4 years ago

teşekkürler

mertasan commented 4 years ago

Yusuf bey tekrar merhaba. Api routes ile gelen isteklere göre database columns'ları filtreleyecek bir yapı oluşturdum. Bu noktada SQL injection'lara karşı önlem almak adına PDO ile query ve execute konusunda bir sorgu oluşturmak istiyorum.

GET parametresi ile gelen isteklere göre loop bloğu içerisinde query oluşturacağım. Örneğin sipariş numarası şu id olanlar diye bir get parametresi filtresi geldiğinde, $pdo->execute() methodu ile query'den sonra ekleme yapmak istiyorum.

Bunu nasıl yapabilirim? Sanırım aşağıdaki $escapes kısmına ekleme yapmalıyım. Bu konuda yardımınızı rica ediyorum.

https://github.com/n1crack/datatables/blob/76db78135e1d98d58cb0097211ed6e5ae5682c8f/src/Query.php#L15

n1crack commented 4 years ago

custom filtre oluşturma için bir yapı oluşturmuştum.

Aşağıdaki class ı inceleyebilirsin.

https://github.com/n1crack/datatables/blob/master/src/FilterHelper.php

Örnek kullanımı şu şekilde https://datatables.ozdemir.be/custom-filter2

$dt->filter('MediaType', function () {

    if ($this->searchValue() === '') {
        return;
    }

    $array = explode('|', $this->searchValue());

    return $this->whereIn($array);
});

$this ile kullanabileceğin helper fonksiyonları da :

escape($value)
searchValue()
defaultFilter()
between($low, $high)
whereIn($array)
greaterThan($value)
lessThan($value)

Umarım yardımcı olur. iyi çalışmalar.

mertasan commented 4 years ago

Teşekkür ederim. Denedim ve ihtiyaca göre kullanıldığında işe yarıyor.

Ancak ben slim 4 rest api ile GET parametresinde yer alan özel filtreler kullanıyorum.

Örneğin,

?types[]=datatables

şeklinde istek geldiğinde datatables çıktısı ürettiriyorum.

?types[]=datatables&filters[siparisNo]=1&filters[uyeid]=2

şeklinde gelen istekte ise veritabanından yalnızca siparisNo 1 olan ve uyeid 2 olan kayıtları bulup buna uygun çıktı response ediyorum.

Eğer datatables isteği geldiyse sizin paketinizden çıktı üretilirken, ?types[]=datatables olarak gelmediğinde ise DB'den gelen normal json response dönüyor.

Sizin verdiğiniz örnek (bildiğiniz üzere ihtiyaç duyduğu get parametresi keylerinden dolayı) yalnızca DataTables tarafından gönderilen requestlerde çalışıyor. Bu pek bir problem olacağını sanmıyorum çünkü zaten postman gibi browser gibi yerlerden datatables response'u elde edilmesine pek gerek yok.

Ama asıl problem, benim DataTables tarafından gönderilen request parametrelerinin dışında özel parametreler kullanıyor olmam. Bunları searchValue() methodu tanımıyor haliyle.

Son olarak da büyük datalarda kullanılmak istendiğinde veritabanından tüm dataları fetch ettikten sonra filtrelendiği için önce tüm veriyi okuyup, ardından filtreleme yapması performans açısından olumsuz yönde bir etki yaratmaz mı?

Elde etmek istediğim şey aşağıdaki yapıyla eş değer bir şey.

$query = ModuleBase::pdo_lib()->prepare("SELECT * FROM odeme WHERE siparisNo = :sipNo AND uyeid = :id");
$query->execute(array(
    "sipNo" => "1"
    "id" => 2
));
return $query->fetchAll();

Böylelikle ben execute arrayını ve WHERE query stringini gelen filtrelere göre build edebileceğim.

Bu arada iki seferdir hızlı ve ilgili yanıtlarınız için çok teşekkür ederim. Günümü kurtarıyorsunuz.

Edit:

Mantık hatası mı yapıyorum? Bunu DataTables javascript tarafında mı gerçekleştirmeliyim? Ben datatables type'inde de olsa normal formatta da olsa request şekli her birisi aynı düzende olsun derdindeyim aslında ama bilemedim.

n1crack commented 4 years ago

anladım. DB Adaptörünü özelleştirip datatables kütüphanesini extend ile genişleterek yapılabilir diye düşünüyorum.

$datatables->query("SELECT column1, column2 FROM odeme WHERE siparisNo = :sipNo AND uyeid = :id");
$datatables->where([
    "sipNo" => "1"
    "id" => 2
]);
$datatables->generate();

sanırım bu şekilde kullanmak istiyorsunuz..

n1crack commented 4 years ago

Aslında dışarıdan gelen istekleri filtrelemek için kullanıyorum filter metodunu. https://datatables.ozdemir.be/custom-filter (mesela buradaki örnekte 5 ve 11 id arasını filtreledim.) filtre sorgusuna escape ile bu değerleri ekliyor tabi ki. ama veritabanındaki ana sorguyu da toplam sayı için çalıştırıyor ve filtrelenmiştir ibaresi geliyor.

filter metodu ile her bir sütun için istediğiniz değişkeni atayabilirsiniz. ama query içinde kullanacaksanız kodlarda değişikliğe gitmek gerekir. Daha önce ihtiyacım olmadığı için bu şekilde bir kullanımı yapmamıştım.

aşağıdaki kodu test etmedim.(muhtemelen hata verecektir.) ama bu şekilde bir kullanımın işinizi göreceği kanaatindeyim.

$datatables->query("SELECT siparisNo, uyeid FROM odeme");

$query_string1 = "1";
$query_string2 = 2;

$dt->filter('siparisNo', function () {
    return 'siparisNo LIKE ' . $this->escape('%'.$query_string1.'%', $this->query);
});

$dt->filter('uyeid', function () {
    return 'uyeid LIKE ' . $this->escape('%'.$query_string2.'%', $this->query);
});

$datatables->generate();
mertasan commented 4 years ago

Yardımlarınız için çok teşekkür ederim.

Son verdiğiniz örneği gayet iyi çalıştırdım. Hiçbir problem olmadı.

Ancak içime sinmedi ve bir önceki dediğiniz yöntemi uygulamak üzere kodlarda değişiklik yaptım.

Öncelikle DB\SQLite classının kopyasını oluşturdum ve yeni adapter classında yer alan query() methodundaki execute() ve fetchAll() methodunu, ardından da count() methodundaki execute() ve fetchColumn() methodunu ayrı methodlar içerisine aktardım.

Datatables classını yeni bir classa extend ettim.

Yeni classta execute() adında bir set methodu oluşturdum. Ardından da getData() ve setResponseData() methodundaki $this->db->query() ve $this->db->count() methodlarının çalıştığı kısımlara aşağıdakine benzer bir koşul/kod ilave ettim.

    protected function getData(): array
    {
        $data = $this->db->query($this->builder->full);
        if($this->executes){
            $data = $this->db->execute($this->executes);
        }
        return array_map([$this, 'prepareRowData'], $data);
    }

Aşağıdaki gibi kullanım sağlayabiliyorum.

$datatables->query($query);
$datatables->execute(
    array(
        "id" => 2
    )
);

Eğer execute methodunu çalıştırmazsam zaten Datatables classındaki $this->execute boş döneceği için yukarda örneklendirdiğim getData() methodu ve aynı mantıkla çalışan setResponseData() methodundaki if($this->executes){ koşulu gerçekleşmeyecek.

Koşul gerçekleşiyorsa, benim yaptığım DB adapter kullanılıyor demektir zaten execute() ve fetchAll() gibi methodlar query() methodunun içerisinde değil. Eğer koşul gerçekleşmiyorsa zaten normal bir şekilde çalışmaya devam edecek.

Biraz derme çatma gibi görünüyor. Bu nedenle pull request göndermedim. Ancak kendimce geliştirdiğim mantığı anlatmak istedim.

Tekrar teşekkürler.

Edit: Datatables içerisinde oluşturduğum execute() methodu $this->execute datasını set etmek için. Bir de aynı isimde adapter classında execute() methodu oluşturdum. O da pdo'nun execute() ve fetchAll() gibi methodlarını çalıştıran ayrı bir method. İsim benzerliği kafa karıştırmasın diye açıklamak istedim.

DB adapter:

screenshot 398

Datatables:

screenshot 399 screenshot 400
n1crack commented 4 years ago

selamlar, biraz önce küçük bir değişiklik yaptım. Kontrol etmek isteyebilirsin.

kullanım şekli :

$dt = new Datatables(new MySQL($config));

$dt->query('Select TrackId as id, Name, UnitPrice, Composer from Track where TrackId > :binding_track_id and TrackId < :binding_track_id2');

$dt->escape(':binding_track_id', 1780);
$dt->escape(':binding_track_id2', 3000);

echo $dt->generate();
mertasan commented 4 years ago

Yusuf bey çok teşekkür ederim. Benim yaptığım sonradan ufak tefek düzeltmeler ile beraber gayet iyi çalışıyor. Ancak hem eklentiyi dinamik ve stabil tutmak açısından hem de daha pratik olduğu için bugün test edip sizin yaptığınızı kullanıma almayı düşünüyorum.

Döngüye almak yetecektir gayet pratik olmuş elinize sağlık.

foreach($escapes as $key => $value){
   $dt->escape($key, $value);
}