Kategoriler
Teknik

Basit PDO Sınıfı ile Veritabanı İşlemlerini Kolaylaştırmak

Neden böyle bir şeye ihtiyaç var diye düşünebilirsiniz belki. Ama acemi ve yeni öğrenen arkadaşlar için böyle bir şey paylaşmak gerekiyor. PDO çok fazla kafa karıştıracak bir şey değil aslında ama öğrenme sürecinde sıkıntı çıkarabiliyor. Özellikle de mysql_connect() fonksiyonundan geçişlerde sancılı olabiliyor. Aşağıda yazdığım sınıf oldukça basit bir kullanıma sahip.

/**
 * Basit bir veritabanı sınıfı
 * Sorguları çalıştırır
 * PDO ile fetch, fetchAll, fetchColumn ... gibi metodlar
 * zincirleme çalıştırılabilir ve kullanılabilir.
 * 
 * @link http://demirphp.com
 * @author Yılmaz Demir <[email protected]>
 */
class BasitPDO
{
   /**
    * PDO sınıfını tutar
    * @var void
    */
   public static $pdo;
   /**
    * PDO bağlantısını kurar
    * @param void $pdo
    */
   public function __construct(PDO $pdo)
   {
      self::$pdo = $pdo;
   }
   /**
    * Sorgu çalıştırır
    * @param string $query
    * @return void
    */
   public static function query($query)
   {
      if (!self::$pdo instanceof PDO) {
         throw new Exception('PDO bağlantısı yapılmamış');
      }
      $stmt = self::$pdo->prepare($query);
      $args = array_slice(func_get_args(), 1);
      if (isset($args[0]) && is_array($args[0])) {
         $stmt->execute($args[0]);
      } else {
         $stmt->execute($args);
      }
      return $stmt;
   }
}

Yukarıdaki dosyayı kaydedelim. Öncelikle veritabanı ayarını yapalım.

Connection.php

$pdo = new PDO('mysql:host=localhost;dbname=database;charset=utf8', 'kullaniciadi', 'sifre');
$basit_pdo = new BasitPDO($pdo);

Ne yapmak istiyorsunuz? Veritabanından bir tek gönderi mi birden fazla gönderi mi çekmek istiyorsunuz? Bütün haberleri çekelim:

Haberler.php

require 'Connection.php';
$haberler = BasitPDO::query('SELECT * FROM haberler WHERE onaylanmis=?', 'evet')->fetchAll();

foreach ($haberler as $key => $haber) {
   echo $haber['baslik'] ;
}

Haber.php?id=5

require 'Connection.php';
$id = $_GET['id'];
$haber = BasitPDO::query('SELECT * FROM haberler WHERE id=?', $id)->fetch();
echo $haber['baslik'];

HaberSayisi.php

require 'Connection.php';
$haberSayisi = BasitPDO::query('SELECT * FROM haberler')->rowCount();
// ya da
$haberSayisi = BasitPDO::query('SELECT COUNT(id) FROM haberler')->fetchColumn();
echo $haberSayisi;

Ekleme/Düzenleme/Silme

require 'Connection.php';
$ekle = BasitPDO::query('INSERT INTO haberler (baslik, icerik) VALUES (:baslik, :icerik)', [':baslik' => 'Başlık', ':icerik' => 'İçerik']);
$duzenle BasitPDO::query('UPDATE haberler SET baslik=:baslik WHERE id=:id', [':baslik' => 'Yeni Başlık', ':id' => $_GET['id']]);
$sil = BasitPDO::query('DELETE FROM haberler WHERE id=?', $_GET['id']);
Kategoriler
Teknik

PHP ve Sabit Tanımlamalar

PHP’de değişkenlerden başka kullanabileceğimiz bir de sabitler vardır. Sabitler, tanımlandıktan sonra değiştirilemezler. Birkaç örnek verelim.

define('SABIT', 'foo');
var_dump(SABIT);

Sabitler, programlama dillerinde genellikle büyük harflerle tanımlanırlar. Bu genel bir gelenektir, daha farklı biçimlerde de kullanılabilir elbette. Sabitleri bir kere tanımladıktan sonra başka bir yerde değiştiremiyorsunuz ve yeniden tanımlayamıyorsunuz. Yani şöyle:

define('TEST', 'foo');
define('TEST', 'bar');
// Hata: Notice: Constant test already defined in /var/www/constant.php on line 2

Sabitlerin Kontrolü

Bir sabit tanımlı olup olmadığını kontrol etmemize yarayan fonksiyonlar da var. defined fonksiyonu sayesinde, sabitin tanımlı olup olmadığını öğrenebiliyoruz. Kullanalım:

define('TEST', 'foo');

defined('TEST') or define('TEST', 'foo'); // Tanımlamaz, çünkü zaten tanımlı
defined('DENEME') or define('DENEME', 'bar'); // Tanımlar, çünkü tanımlı değil

var_dump(defined('DIGER')); // bool(false)

Sabitlere Tanımlayabileceğimiz Türler

Sabitlere, değişkenleri tanımlayabiliriz fakat daha sonrasında değişkene yeni bir değer verdiğimizde sabitin değeri değişmez. Yani;

$foo = 'bar';
define('TEST', $foo);
$foo = 'baz';
var_dump(TEST); // string(3) "bar"

Sabitlere değer döndüren fonksiyon tanımladığımı test ettim (sürüm 5.4) fakat anonim fonksiyonlar sabitlere tanımlanmıyor.

function foo($bar) {
    return (string) $bar;
}

define('TEST', foo('test'));
var_dump(TEST); // string(4) "test"

// Hatalı kullanım:
define('TEST', function(){
    return 'foo';
});

Sabitlerde şimdilik dizi (array) tanımlaması yapamıyoruz ama PHP 7’de bunu kullanabileceğiz. PHP 7 ile çalıştırdığımızı varsayalım:

define('FOO', ['bar' => 'Bar...', 'baz' => 'Baz...']);
var_dump(FOO['bar']); // string(6) "Bar..."

Sınıflardaki Sabitler

Sınıf içerisinde kullandığımız sabitlerde, normalde kullandıklarımızla benzerlikler taşır. Bu sabitlerde daha sonrasında üzerine yazılamaz ve değiştirilemez. Sadece okumak içindir. Örneğimizi inceleyelim:

class Test
{
    const FOO = 'Sabit';

    public function bar()
    {
        return self::FOO;
    }
}

$test = new Test;
var_dump($test->bar()); // string(5) "Sabit"
var_dump(Test::FOO); // string(5) "Sabit"

Bu yapı yalnızca PHP 5.3 ve sonrasında kullanılabilir.

Sabitlerin Kullanım Yerleri

Sabitler daha çok ayar/konfigürasyon (config) dosyalarında kullanılırlar. Örneğin bir veritabanı bağlantı ayarları veya dizin belirleme ayarları gibi. Örnekleyelim:

defined('DB_DSN') or define('DB_DSN', 'mysql:host=localhost;dbname=veritabani');
defined('DB_USR') or define('DB_USR, 'root');
defined('DB_PWD') or define('DB_PWD', null);

$pdo = new PDO(DB_DSN, DB_USR, DB_PWD);

Bu şekilde veritabanı bağlantısını daha kontrollü biçimde yapabiliyoruz. İstersek sınıflar içinden de erişebiliyoruz. Başka bir senaryoda ise, dizin yapılarını kontrolümüz altında tutmak isteyelim.

defined('KOK_DIZIN') or define('KOK_DIZIN', __DIR__);
defined('UYG_DIZINI') or define('UYG_DIZINI', KOK_DIZIN.'/app');
defined('SINIFLAR') or define('SINIFLAR', KOK_DIZIN.'/classes');
defined('GORUNUMLER') or define('GORUNUMLER', KOK_DIZIN.'/views');

Herhangi bir yerde betik içine sınıf dahil etmek istediğimizde, yeniden dizin yolunu yazmak yerine sabit sayesinde tek sefer çağırabiliriz: require SINIFLAR.'/database.class.php'; gibi. Bu şekilde bir kullanım yapmak, daha sonrasında sınıflarının dizin yolunu değiştirdiğimizde de bizi zorlamayacaktır.

Sabitlerin Kullanımı ve Performans

Hiç istatistik ve ölçüm bulamadım fakat değişkenlerle global sabitleri karşılaştırdığımız vakit, sabitler değişkenlere nazaran daha yavaşmış. Yalnız bunu sınıflar için söyleyemem.

Kolay gelsin.

Kategoriler
Teknik

PDO’nun En Kolay Hali

PDO ile MySQL Veritabanına Bağlanmak

$pdo = new PDO('mysql:host=localhost;dbname=veritabani;charset=utf8', 'kullaniciAdi', 'sifre');

Bu satır, mysql_connect() satırıyla aynı işi hatta daha fazlasını yapar. Hem belirttiğimiz veritabanına bağlanır hem de karakter setini belirler. Böylece türkçe karakter sıkıntısı yaşamayız.

PDO ile Veri Listelemek

$sorgu = $pdo->query('SELECT * FROM tablo');
$ogeler = $sorgu->fetchAll();

foreach ($ogeler as $oge) {
    echo $oge['baslik'] . '<br>';
}

Burada, query() ile sorguyu yazdık ve fetchAll() metodu ile verileri birden fazla yani hepsini çekecek biçimde aldık. Daha sonra foreach() ile sayfaya yazdırdık.

PDO ile Veri Çekmek

PHP’de PDO ile veri çekerken veya listelerken iki yöntemimiz var. Bunlardan birincisi query() metodu diğeriyse önce prepare() yani hazırlama metodu sonrasında execute() yani çalıştır metodu. İlk metodun örneğini veri listelemek bölümünde yaptık, şimdi tekil veri çekerken, ikinci yöntemi yani prepare() metodunu kullanacağız.

$id = $_GET['id'];
$sorgu = $pdo->prepare('SELECT * FROM table WHERE id=?');
$calistir = $sorgu->execute(array($id));
$oge = $calistir->fetch();
echo $oge['baslik'];

Neden ilkinden farkı bir yöntem kullandık?

Çünkü, veritabanı ile bilgi alışverişi yaparken güvenliğe önem vermemiz gerekiyor. Son örnekte, kullanıcıdan gelen bilgiye göre ($id = $_GET['id'] satırına dikkat) bilgi çekiyoruz. Önceleri, yani PDO’dan evvel değişkeni sorgu içine ekleyip de veriler çekiliyordu. Ama SQL Injection dediğimiz açıkları da beraberinde getiriyordu. Biz, bu örnekte önce sorguyu hazırladık, şart yerine ? işareti koyduk ve soru işareti gelen yere $sorgu->execute(array($id)); kısmında göründüğü üzere gelecek verinin $id değişkeni olduğunu söyledik.

Bunun gibi ve bundan farklı birçok örnek mevcut ve kullanıma açık. Mesele mantığı kavramak. Ama en basit hali bu hali. Kolay gelsin. Bir dahaki yazıda, PDO ile veri ekleme, silme ve güncelleme konularına değineceğim.

Esen kalın.

Kategoriler
Teknik

SQL’de Sonraki ve Önceki Satırdaki Veriyi Getirmek

Bir gönderi/blog sistemi düşünelim. Hatta WordPress’ten örnekleyebiliriz. Bazı bloglarda, bir gönderiye girdiğimizde sonraki ve önceki gönderiler için bağlantı olduğunu görürüz. Bunlar için ayrı veriler çekmemiz gerekiyor. Örnek verirken bir model dosyasında kod yazıyormuş gibi örnekleyeceğim, SQL kodundan yola çıkarak sizde geliştirebilirsiniz.

class Post extends Model
{
  public function nextPost($id)
  {
    $sql = 'SELECT * FROM posts WHERE id > ? ORDER BY id ASC LIMIT 1';
    $sth = $this->db->prepare($sql);
    $sth->execute(array($id));
    return $sth->fetch();
  }

  public function prevPost($id)
  {
    $sql = 'SELECT * FROM posts WHERE id < ? ORDER BY id DESC LIMIT 1';
    $sth = $this->db->prepare($sql);
    $sth->execute(array($id));
    return $sth->fetch();
  }
}
Kategoriler
Teknik

Veritabanındaki Tablonun Varlığını Kontrol Etmek

PHP’de PDO ile çalışırken bir tablonun var olup olmadığını kontrol etmek için aşağıdaki yöntem kullanılabilir:

public function checkTable()
{
  try {
    return $this->fetchRow('SELECT * FROM posta');
  } catch(Exception $e) {
    return false;
    // Veya $this->exec('CREATE TABLE IF NOT EXISTS posta ...');
  }
}

Bir kurulum aşamasında, veritabanındaki tabloları yapılandırma sırasında işe yarayabilir.