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.

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.

PHP ile PDO Sorgu Hatalarını Yakalamak

PHP PDO uzantısını kullanırken, try/catch blokları içerisinde veritabanı bağlantısında oluşabilecek hataları şu şekilde yakalayabiliyoruz.

try {
  $pdo = new \PDO($dsn, $user, $pass);
} catch (\PDOException $e) {
  throw new \Exception('Bağlantı hatası: ' . $e->getMessage());
}

Fakat sorgulardaki hataları bu şekilde yakalayamıyoruz maalesef. Sorgu hatalarını yakalamak için, PDO bağlantısının hemen altına aşağıdaki gibi bir metodla tanımlama yapmamız gerekiyor:

$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);

Bunu yaptıktan sonra, aşağıdaki gibi sorgu hatalarını yakalayabiliyoruz:

try {
  $query = $pdo->prepare('SELECT * FROM post');
  $query->execute();
  $posts = $query->fetchAll();
} catch (\PDOException $e) {
  throw new \Exception('Sorgu hatası: ' . $e->getMessage());
}

gibi. Kolay gelsin.

PHP’de PDO Veritabanı İşlemleri Sınıfı

Dikkat: Bu yazıyı ve kodları yazmamın üzerinden seneler geçti. Bu sebepten bu sınıf güncel işlemleri yapabilecek kapasiteye sahip değil. Bu sınıftan sonra daha gelişmiş birkaç sınıf daha yazdım (blog içerisinden ulaşabiirsiniz), bu sınıflardan faydalanmanız daha sağlıklı olacaktır; iyi çalışmalar.

Çok kullandığım veritabanı işlemleri için bir sınıf yazdım. Bu PHP sınıfı sayesinde veri çekme, listeleme, ekleme, güncelleme ve silme işlemlerini hızlıca alabiliyorum. Kodları aşağıda paylaştıktan sonra nasıl kullanıldığına dair bilgiler vereceğim.

<?php
/**
 * Hızlı Veritabanı İşlemleri
 * @author Yılmaz Demir
 * @link http://yilmazdemir.com.tr
 * @version 0.1
 */

class Database extends PDO {
	/**
	 * Veritabanı bilgilerine ait sabitler
	 * Kendinize göre düzenleyebilirsiniz
	 */
	const DB_HOST = "localhost";
	const DB_NAME = "veritabaniadi";
	const DB_USER = "kullaniciadi";
	const DB_PASS = "sifre";

	// Tablodaki asıl anahtar (Primary key)
	const PK = "id";

	public $query;

	/**
	 * Başlatıcı
	 * PDO veritabanı bağlantısı kurar
	 * Karakter setini UTF-8 olarak belirler
	 * Olası hatada çalışmayı durdurur
	 */
	public function __construct()
	{
		try {
			parent::__construct(
				"mysql:host=" . 
				self::DB_HOST . 
				";dbname=" . 
				self::DB_NAME, 
				self::DB_USER, 
				self::DB_PASS,
				array(
					PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8",
					PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET utf8"
					)
				);
		} catch (PDOException $e) {
			exit($e->getMessage());
		}
	}

	/**
	 * Tablo adına ve koşullara göre tek satır veri döndürür
	 * @param string $table Tablo adı
	 * @param string $conditions Şartlar (WHERE id=? gibi)
	 * @param array $parameters Parametreler (array(1) gibi)
	 * @return object Obje şeklinde döndürür ($post->title gibi)
	 */
	public function getOne($table, $conditions = null, $parameters = [])
	{
		$this->query = $this->prepare("SELECT * FROM " . $table . " " . $conditions);
		$this->query->execute($parameters);
		return $this->query->fetch(PDO::FETCH_OBJ);	
	}

	/**
	 * Tablo adına ve koşullara göre çoklu veri döndürür
	 * @param string $table Tablo adı
	 * @param string $conditions Şartlar (type=? gibi)
	 * @param array $parameters Parametreler (array("post") gibi)
	 * @return object Obje şeklinde döndürür ($post->title gibi)
	 */
	public function getAll($table, $conditions = null, $parameters = [])
	{
		$this->query = $this->prepare("SELECT * FROM " . $table . " " . $conditions);
		$this->query->execute($parameters);
		return $this->query->fetchAll(PDO::FETCH_OBJ);
	}

	/**
	 * Tabloya yeni veri eklemek için kullanılır
	 * @param string $table Tablo adı
	 * @param array $data Dizi şeklinde sütun adları
	 * ve karşılarında veriler olmak üzere
	 * @return int Son eklenen verinin ID'sini döndürür
	 */
	public function insert($table, $data)
	{
		$values = array();
		$columns = array();
		foreach ($data as $column => $value) {
			$values[] = $value;
			$columns[] = $column;
		}

		$columns = implode(",", $columns);
		$marks = trim(substr(str_repeat("?,", count($values)), 0, -1));

		$this->query = $this->prepare("INSERT INTO " . $table . " (" . $columns . ") VALUES (" . $marks . ")");
		if ($this->query->execute($values)) {
			return $this->lastInsertId();
		}
		return false;
	}

	/**
	 * Tablodaki veriyi güncellemek için kullanılır
	 * @param string $table Tablo adı
	 * @param int $id Güncellenecek verinin ID'si
	 * @param array $data Dizi şeklinde sütun adları
	 * ve karşılarında veriler olmak üzere
	 * @return int Güncellenen verinin ID'sini ya da false döndürür
	 */
	public function update($table, $id, $data)
	{
		$values = array();
		$columns = array();
		foreach ($data as $column => $value) {
			$values[] = $value;
			$columns[] = $column;
		}

		$columnsAndMarks = implode("=?,", $columns) . "=?";

		$this->query = $this->prepare("UPDATE " . $table . " SET " . $columnsAndMarks ." WHERE " . self::PK . "=" . $id);
		if ($this->query->execute($values)) {
			return $id;
		}
		return false;
	}

	/**
	 * Tablodaki veriyi silmek/kaldırmak için kullanılır
	 * @param string $table Tablo adı
	 * @param int $id Silinecek verinin ID'si
	 * @return int Silinen verinin ID'sini ya da false döndürür
	 */
	public function delete($table, $id)
	{
		$this->query = $this->prepare("DELETE FROM " . $table . " WHERE " . self::PK . "=" . $id);
		if ($this->query->execute()) {
			return $id;
		}
		return false;
	}

	/**
	 * Tablo adına ve koşullara göre satır sayısını döndürür
	 * @param string $table Tablo adı
	 * @param string $conditions Şartlar (WHERE type=? gibi)
	 * @param array $parameters Parametreler (array("post") gibi)
	 * @return int Kaç satır veri olduğunu döndürür
	 */
	public function count($table, $conditions = null, $parameters = [])
	{
		$this->query = $this->prepare("SELECT * FROM " . $table . " " . $conditions);
		$this->query->execute($parameters);
		return $this->query->rowCount();
	}
}

Sınıfın kullanımı

Veri çekme

Sınıf içerisindeki getOne() methodu ile tek satırlık veri çekiyoruz. Kullanımı:

$db = new Database;
$gonderi = $db->getOne("gonderi", "WHERE id=?", array(5));
echo $gonderi->baslik;

Veri Listeleme

getAll() methodu ile bütün gönderileri çekebiliyoruz. Parametrelerle şartlar belirlenebiliyor.

$db = new Database;
$gonderiler = $db->getAll("gonderi", "WHERE taslak=?", array(0));
foreach ($gonderiler as $gonderi) {
	echo $gonderi->baslik . "<br/>";
}

Veri Ekleme

insert() methodu ile veri ekleyebiliyoruz.

$db = new Database;
$id = $db->insert("gonderi", array(
	"baslik" => "Gönderi Başlığı",
	"icerik" => "<p>Gönderi İçeriği</p>",
	"taslak" => 1
	)
);

echo $id ? $id . " ID'li gönderi eklendi." : "Gönderi eklenemedi";

Veri Güncelleme

update() methodu ile veri güncelleyebiliyoruz. İkinci parametre düzenlenecek gönderinin ID’sini alıyor.

$id = 5;
$db = new Database;
$guncelle = $db->update("gonderi", $id, array(
		"baslik" => "Güncellenen başlık",
		"icerik" => "<p>Güncellenen içerik</p>",
		"taslak" => 0
	)
);

echo $guncelle ? "Gönderi başarıyla güncellendi" : "Güncelleme başarısız";

Veri Silme

Verileri silmek için delete() methodundan faydalanabiliriz.

$id = 5;
$db = new Database;
$sil = $db->delete("gonderi", $id);
echo $sil ? "Gönderi silindi" : "Silme başarısız";

 Toplam Sayısı Alma

Toplam satır sayısı için count() methodunu kullanabiliriz. Parametre de eklenebiliyor.

$db = new Database;
$sayi = $db->count("gonderi");
echo "Toplamda " . $sayi . " adet gönderi bulunuyor";

Ek olarak, dikkat edilmesi gereken diğer bir nokta sınıf içerisindeki PK sabitini belirlemek gerekiyor. Ben asıl anahtar (primary key) olarak id adını kullanıyorum. Farklı bir isim kullanılıyorsa örn. tblId ise, bu şekilde değiştirilmesi gerekiyor.

Kolay gelsin.

PHP ile SEF (Arama Motoru Dostu) URL Fonksiyonu

Daha önceden jQuery ile SEF Bağlantı Yapımı başlıklı bir yazı paylaşmıştım. Şimdi aynı ihtiyaç PHP ile doğdu. Search Engine Friendly URL yani Arama Motoru Dostu URL’ye aslında birçok internet sitesine girdiğimizde adres çubuğunda rastlıyoruz. Şöyle ki: orneksite.com/arama-motoru-dostu-baglanti şeklinde görünüyor. Fonksiyona aşağıdan ulaşabilirsiniz.

function SefBaglanti ($gelen) 
{
	$bul = array('Ç', 'Ş', 'Ğ', 'Ü', 'İ', 'Ö', 'ç', 'ş', 'ğ', 'ü', 'ö', 'ı');
	$degistir = array('c', 's', 'g', 'u', 'i', 'o', 'c', 's', 'g', 'u', 'o', 'i');
	$giden = strtolower(str_replace($bul, $degistir, $gelen));
	$giden = preg_replace("@[^A-Za-z0-9\-_\.\+]@i", ' ', $giden);
	$giden = trim(preg_replace('/\s+/', ' ', $giden));
	$giden = str_replace(' ', '-', $giden);
	return $giden;
}

Gelen veri ve giden veri diye isimlendirdim. Bul değişkenindeki verileri Değiştir değişkenindeki verilerle değiştirmesi için str_replace fonksiyonunu kullanıyoruz. Regex ile süzüyoruz, yandaki boşlukları varsa siliyoruz ve boşluğı tireye çevirip fonksiyonun veriyi döndürmesini sağlıyoruz. Kullanımını ise şu şekilde yapabiliriz:

echo SefBaglanti("Bu Bir Gönderi Başlığıdır");
// Çıktısı: bu-bir-gonderi-basligidir

Kolay gelsin.

Slim Framework ve RedBeanPHP’yi Anlamak

Daha önceleri birkaç forum sitesinde Slim Framework’ü anlamak için sorulara rast gelmiştim. Bundan mütevellit Slim ve RedBeanPHP’yi anlamak için basit bir blog betiği yazdım. Slim Framework için rota işlemleri, RedBeanPHP içinse CRUD işlemlerini anlamak için kod satırlarında gerekli açıklamaları yaptım. Blog betiğinin özellikleri;

  • Gönderi (Listele, ekle, düzenle, sil)
  • Kategori (Listele, ekle, düzenle, sil)
  • Ayar (Basit key/value)
  • Yönetici paneli giriş/çıkış

Hızlı Blog

Örnek kod satırları:

/**
 * Blog gönderi sayfası
 * Gönderiyi görüntüler
 * @param int $id
 */
$app->get("/gonderi/:id", function ($id) use ($app)
{
	// $id değişkeni nümerik değilse hata ver
	if (!is_numeric($id)) exit("Hata");

	// Gönderiyi $id'sine göre çekiyoruz
	$gonderi = R::load("gonderi", $id);

	// Gönderi sayfasını yorumluyoruz
	// $gonderi değişkenini tema dosyasına atıyoruz
	$app->render("gonderi.php", 
		["gonderi" => $gonderi,
		"baslik" => $gonderi["baslik"] ]);
});

Herhangi bir konuda sorularınızı bu sayfadan yorum yaparak veya e-posta ile iletişime geçerek iletebilirsiniz. Kolay gelsin.

Github bağlantısı
HizliBlog Dosyaları (zip)

MySQL’den Gelen Zamanı Dönüştürmek

MySQL’de ayarladığımız datetime/timestamp veri tipli alanlarından gelen tarih verisini ekrana dökmek istediğimizde 2014-11-19 17:16:25 gibi farklı bir tarih-zaman biçimiyle karşılaşıyoruz. Bunu düzgün bir hale getirmek için PHP’de strtotime() fonksiyonunu kullanabiliriz. Şöyle bir ek fonksiyon kullanırsak, işimizi daha rahat görmüş oluruz:

<?php
function mysqlTarihCevir ($tarihzaman, $duzen = null) {
    $tarihzaman = strtotime($tarihzaman);
    if ($duzen) {
        return date($duzen, $tarihzaman);
    } else {
        return date("d F Y l", $tarihzaman);
    }
}

Yukarıdaki fonksiyonda gelen tarihi otomatikmen d F Y l şeklinde biçimlendiriyoruz ve fonksiyonu mysqlTarihCevir("2014-11-19 17:16:25") olarak çalıştırdığımızda sonuç olarak “19 Kasım 2014 Çarşamba” çıktısını alıyoruz. Tarih biçimlendirme hakkında daha fazla bilgi almak için buradaki manuel sayfasına bakabilirsiniz. Farklı şekilde kullanmak içinse şöyle yapabiliriz: mysqlTarihCevir("2014-11-19 17:16:25", "d-m-Y") böylelikle çıktı “19-11-2014” olacaktır.

PHP ile Kısa If Else Kullanımı

En basitinden bir değişkenin, fonksiyonun vs. TRUE ya da FALSE döndürüp döndürmediğini öğrenmek için uzunca bir if, else ifadesi kullanmamıza gerek yok. Kullandığım bir iki yöntem şöyle:

<?php
$deger = 'Herhangi';
echo $deger == 'Herhangi' ? 'Değer doğru' : 'Doğru değil';

ya da

<?php
function dene($deger = null) {
    return is_null($deger) ? 'Değer gelmedi' : 'Değer geldi';
}

ya da

<?php
function dene($deger = null) {
    if ($deger === null) return true;
    return false;
}

gibi gibi.