Zend_Db_Table ile JOIN Kullanarak Tabloları Birleştirmek
Eğer PHP programlarınızda Zend Framework kullanıyorsanız Zend_Db_Table bileşeninin veritabanı işlemlerinizi ne kadar kolaylaştırdığınız fark etmişsinizdir.
Zend_Db_Table ile MVC yapımızın Model kısmında tek satır kodla veritabanındaki istediğimiz tabloya bağlanarak Controller üzerinden bunu yönetebiliyoruz.
Peki, Zend_Db_Table ile JOIN işlemleri nasıl yapılıyor? Zend_Db_Table, mantığı gereği sadece tek bir tabloyla çalışmak istiyor.
Zend Framework Manual kılavuzuna göre Zend_Db_Table ile JOIN kullanabiliyoruz:
You can allow JOIN clauses on a select to allow multi-table lookups.
Peki bunun şartı nedir? Cevap yine kılavuzdan geliyor:
You can not specify columns from a JOINed tabled to be returned in a row/rowset.
Doing so will trigger a PHP error. This was done to ensure the integrity of the. i.e. A
Zend_Db_Table is retainedZend_Db_Table_Rowshould only reference columns
derived from its parent table.
Örnek Durum
Şu an çalıştığım projede Zend Framework kullanıyorum. Proje oldukça iyi ilerliyor. Üniversitede Zend Framework kullanılarak geliştirilen ilk projemiz ve WebWizard gibi yine Türkiye'de bir ilk olacak.
Zend_Db_Table ile yaşadığım olayı özetlemek gerekirse:
Sistemde birden çok kullanıcı olacak, birden çok site olacak. Bir siteyi düzenleme yetkisi birden çok kullanıcıda olabilecek (ACL'yi falan hiç karıştırmıyorum). Bu durumda sitelerle kullanıcıları eşleştiren bir tablomuzun daha olması gerek.
Tablolarımızın isimleri şöyle: users, sites, sites_users. Birincisi oturum açma bilgilerinin bulunduğu kullanıcı tablosu, ikincisi sitelerin listesi ve sonuncu tablo da sitelerle kullanıcıları eşleştiriyor.
Sites isimli modelimiz hazır, bunu sites_users ile JOIN kullanarak birleştirip oturum açmış olan kullanıcının düzenlemeye yetkili olduğu sitelerin listesini almak istiyoruz. Aşağıdaki kodu inceleyelim.
1 2 3 4 5 6 7 8 9 10 11 12 13 | $userId = $this->_auth->getIdentity()->id;
$table = new Sites();
$select = $table->select();
$select
->from($table)
->join('sites_users', 'sites.id = sites_users.user_id')
->where('sites_users.user_id = ?', $userId)
;
$rows = $table->fetchAll($select)->toArray();
var_dump($rows); |
Bu kodun üretmesi gereken SQL query ise şu şekilde:
SELECT `sites`.* FROM `sites` INNER JOIN `sites_users` ON sites.id = sites_users.user_id WHERE (sites_users.user_id = '1')
Maalesef yazdığımız kod çalışmıyor. Buyrun Zend'in verdiği hata:
Zend Framework kullanım kılavuzu JOIN yapabileceğimizi söylerken ekrandaki hata mesajı buna izin verilmediğini söylüyor. Projeyi geliştirdiğim bilgisayarda o sırada internet yoktu ve Zend Framework Manual de yanımda değildi. Bu yüzden sorunu çözmek yarım saatimi aldı.
Aslında ekrandaki hata daha açıklayıcı olsa çözüm basit. Sorun iki tabloyu JOIN ile birleştirmemizden değil JOIN yaptığımız tablodaki sütunları da SELECT işlemine eklediğimizden kaynaklanıyor. Yukarıdaki ikinci alıntıyı tekrar okuyalım:
You can not specify columns from a JOINed tabled to be returned in a row/rowset.
Doing so will trigger a PHP error.
Çözüm
Sorunun iki çözümü var. Birincisi SELECT bileşenine bütünlük kontrolü yapma demek. İkincisi ise Zend_Db_Table'ı önerildiği gibi kullanmak.
SELECT bileşeninin bütünlük kontrolü yapmasını engellemek için kodu aşağıdaki şekilde değiştirmek gerek:
4 | $select = $table->select()->setIntegrityCheck(false); |
Fakat bu durum Zend_Db_Table kullanmanın mantığına aykırı. Bu sebeple Zend'in de önerdiği gibi JOIN yaptığımız tablonun sütunlarını dönen sütunlarda içermeniz gerek. Bunu yapmak için koddaki JOIN kısmına şu şekilde değiştirmemiz yeterli:
8 | ->join('sites_users', 'sites.id = sites_users.user_id', '') |
Sondaki boş string hiçbir sütunun SELECT'e dahil edilmemesini bildiriyor.
