Selam,
Bugün veritabanı üzerinde çalışıyorum. Konularım:
- Migrasyon
- SchemaBuilder
- Veri Ekleme (Seeding)
- Model
- Eloquent
- İlişkisel veritabanı tasarımları ve Laravel
Veritabanı üzerinde çalışacağımız için halihazırda bir veritabanımıza bağlantımızın olduğunu varsayıyorum ve vakit kaybetmeden migrasyon (migration) ile başlıyorum.
Migrasyon
Migrasyonlar veritabanı için bir sürüm kontrol türüdür. Bir ekibin veritabanı şemasını değiştirmesine ve son şema durumuna güncel kalmalarına imkan verir.
Migrasyon oluşturmak için komut satırında “Artistan
“ı kullanmamız gerecek. Migrasyon dosyaları app/database/migrations
altında toplanıyor. Komut satırımı açıp Laravel’i kurduğum dizine geliyorum ve şu kodu yazıyorum:
php artisan migrate:make tarifler_tablosu_olustur
Komutu çalıştırdığımız zaman app/database/migrations
altında bizim için bir dosya oluşturulduğunu görebiliriz. Bu dosyanın içi hemen hemen şöyle bir şey:
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class TariflerTablosuOlustur extends Migration { /** * Run the migrations. * * @return void */ public function up() { // } /** * Reverse the migrations. * * @return void */ public function down() { // } }
up()
metodunda veritabanı üzerinde çalıştırmak istediğimiz kodları yazacağız. down()
metodu ise up()
metodunda yaptığımız işlemleri geri almak için. Yani up()
metodundaki sorguların tersini down()
metoduna yazabiliriz.
up()
metodu içinde tarifler
tablomu oluşturmak için gerekli kodları yazıyorum:
public function up() { DB::statement(" CREATE TABLE tarifler ( id INTEGER PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) UNIQUE NOT NULL, text TEXT NOT NULL ) "); }
down()
metodu içine ise bu kodun tersini yapacak kodlarımı yazıyorum. Yani tarifler
tablosunu silmek için:
public function down() { DB::statement(" DROP TABLE tarifler "); }
Şimdi bu migrasyon dosyamızı çalıştıralım. Bunun için komut satırına şu kodu yazıyoruz:
php artisan migrate
Böylece veritabanında tarifler
tablosunu oluşturduk. Ayrıca veritabanımıza "migrations"
adında bir tablo daha ekleniyor. Bu tabloya şimdilik dokunmamız daha iyi.
Eğer son sorgumuzu geri almak istersek, yani tarifler tablosunu silmek için, komut satırına şu kodu yazmamız yeterli:
php artisan migrate:rollback
Bazen bu tür geri alma işlemlerinde hatayla karşılaşabilirsiniz. Böyle bir durumda aşağıdaki komutu çalıştırıp yeniden denemelisiniz:
php composer dump-autoload
SchemaBuilder
Yukarıda migrasyon ile çalışırken SQL kodlarımızı uzunca yazdık. Bu pek kullanıcı dostu olan bir işlem değil açıkcası. Laravel’in SchemaBuilder
‘ı ile pratik bir şekilde bu işlemleri yapabiliriz. Ayrıca veritabanı tiplerine göre sorgularımızı düzenlememize gerek kalmaz.
Bu örnekte kitaplar
tablosu üzerinden gideceğiz. Yeni bir migrasyon ile başlıyorum:
php artisan migrate:make kitaplar_tablosu_olustur
Komut satırına kodu yazdıktan sonra app/database/migrations
altında oluşturulan dosyamı düzenlemeye başlıyorum. Yeni bir tablo oluşturacağım için up()
metodu içinde Schema
classını kullanarak şu kodları yazmam gerek:
public function up() { Schema::create("kitaplar", function($table) { $table->increments("id"); $table->string("baslik"); $table->string("yazar"); $table->string("ozet")->nullable(); }); }
Yeni bir tablo için yapmamız gereken Schema::create()
metodunu kullanmak. İlk parametre olarak tablo adını, 2. parametre olarak anonim bir fonksiyon gönderiyoruz. Bu fonksiyon $table
parametresi alıyor ve bu $table
ı kullanarak tablomuzun sütunlarını oluşturuyoruz. increments("id")
ile id adında, otomatik artan, primary key özelliğinde bir sütun oluşturduk. Tüm bu fonksiyonların listesi dökümantasyonda mevcut.
Eğer oluşturduğumuz tabloyu silmek istersek down()
metoduna şu kodu eklememiz yeterli:
public function down() { Schema::drop("kitaplar"); }
Var olan tablomuza yeni bir alan eklemek isteyebiliriz. kitaplar
tablomuz için "tur"
alanı ekleyelim. Önce yeni bir migrasyon dosyası oluşturmakla başlıyorum:
php artisan migrate:make tur_alani_ekle
app/database/migrations
altında yeni oluşturulan dosyamda up()
metodunu düzenliyorum:
public function up() { Schema::table("kitaplar", function($table) { $table->string("tur"); }); }
down()
metodunda ise bu işlemi geriye alacak kodlarım:
public function down() { Schema::table("kitaplar", function($table) { $table->dropColumn("tur"); }); }
Aynı anda birden fazla alanı silmek istersek dropColumn()
metoduna dizi içinde sütunların adını göndermemiz yeterli:
public function down() { Schema::table("kitaplar", function($table) { $table->dropColumn( array("tur", "ozet", "yazar")); }); }
Veri Ekleme (Seeding)
Veri Ekme (seeding), migrasyon ile oluşturulacak veritabanı tablosunda gerekli olacak ilk veri kayıtlarının (seed data) oluşturulması işlemidir.
Veritabanımız için oluşturacağımız deneme verilerini app/database/seeds
içinde ekleyebiliriz. Hazırda DatabaseSeeder.php
isminde bir dosya bizim için bekliyor. Şimdi DatabaseSeeder
sınıfını kullanarak öylesine veri eklemeyi öğreneceğim.
DatabaseSeeder.php
içinde kendime bir sınıf oluşturup, bu sınıf içinde run()
metodu hazırlacağım. Hazırladığımız sınıflar Seeder
sınıfını extend
etmeli. Şimdi kitaplar
tablomu örnek verilerle doldurmak için gerekli kodları yazıyorum:
class KitaplarTablosunaVeriEkle extends Seeder { public function run(){ for($i=0; $i<100; $i++) { DB::table("books")->insert( array( "baslik" => "Kitap ".$i, "yazar" => "Yazar ".$i, "ozet" => "Kitap ".$i."e ait özet...", "tur" => "Tur ".$i )); } } }
Hazırladığım bu örnek verileri eklemek için DatabaseSeeder
sınıfındaki run()
metodunu düzenlemem lazım. run()
metodu içinde call()
metoduna parametre olarak hazırladığım sınıfın adını göndereceğim: "KitaplarTablosunaVeriEkle"
class DatabaseSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { Eloquent::unguard(); $this->call('KitaplarTablosunaVeriEkle'); } }
Son haliyle DatabaseSeeder.php
dosyam şu şekilde:
class DatabaseSeeder extends Seeder { public function run() { Eloquent::unguard(); $this->call('KitaplarTablosunaVeriEkle'); } } class KitaplarTablosunaVeriEkle extends Seeder { public function run(){ for($i=0; $i<100; $i++) { DB::table("kitaplar")->insert( array( "baslik" => "Kitap ".$i, "yazar" => "Yazar ".$i, "ozet" => "Kitap ".$i."e ait özet...", "tur" => "Tur ".$i )); } } }
Son olarak komut satırından verilerin eklenmesi için komutu vermem gerek:
php artisan db:seed
Böylelikle kitaplar tablomuza 100 adet veri eklenmiş oldu. Yalnız bu veriler pek gerçekçi değil. Daha gerçekçi veriler eklemek istersek “Faker” isimli php sınıfını kullanabiliriz. Bunu sonraki derslerde öğreneceğim. Şimdilik Seeder
‘ın mantığını kavramaya çalıştığım için bu kadarıyla yetiniyorum.
Modeller
Üzerinde çalışmak için makaleler
adında örnek bir tablo oluşturarak başlıyorum. Önce komut satırından migrasyon komutunu yazıyorum:
php artisan migrate:make makaleler_tablosu_olustur
app/database/migrations
altında oluşan dosyamda Schema
sınıfını kullanarak tablomun alanlarını belirtiyorum:
class MakalelerTablosuOlustur extends Migration { public function up() { Schema::create("makaleler", function($table) { $table->increments("id"); $table->string("baslik")->unique(); $table->text("icerik"); }); } public function down() { Schema::drop("makaleler"); } }
Ve migrasyonu çalıştırmak için tekrar komut satırından gerekli kodu yazıyorum:
php artisan migrate
Böylelikle makaleler
tablom hazırlanmış oldu. Bu tablom üzerinde model dosyalarını kullanarak çalışacağım.
Model dosyaları app/models
altında toplanıyor. app/models
altında User.php
adında hazır bir model dosyası zaten mevcut. Ben kendime ait Makale.php
isminde yeni bir model dosyası oluşturuyorum. Bu model dosyamda makaleler
tablosuna ait veritabanı işlemlerini gerçekleştireceğim.
Eloquent
MVC yapısının temelini öğrendiğim derste, her model dosyasının veritabanımızdaki tablolarla ilişkilendirdiğimizi öğrenmiştim. Makale.php
model dosyam ile makaleler
tablosu arasında bir bağ olursa, Makale.php
model dosyam üzerinden makaleler tablosuna rahatça erişebilir ve müdahale edebilirim. Bunun için Laravel’in Eloquenti
kullanacağım. Eloquent hakkında detaylı bilgi dökümantasyonda mevcut.
Model dosyalarımız üzerinde Eloquent ile çalışmak için Eloquent’i kalıtım yapmamız lazım:
class Makale extends Eloquent{ }
Burada bilmemiz gereken önemli bir nokta var. Eloquent kalıtım yapıldığı sınıfın veritabanında var olan bir tablo olduğunu düşünüyor. Ama varsayılan olarak bu tablonun adını, sınıfın adının çoğulu olarak düşünüyor. Tabii ki İngilizce dil bilgisi kurallarına göre. Bizim durumda Eloquent, veritabanında makales
isminde bir tablo olduğunu varsayacaktır. Eloquent’e “kardeşim aslında o tablonun adı makales değil de makaleler olacak” demek istersek $table
özelliğini değiştirmemiz gerek. Şu şekilde:
class Makale extends Eloquent{ protected $table = "makaleler"; }
Ayrıca Eloquent tablolarımızda timestamps()
alanlarının (created_at
ve updated_at
) olduğunu düşünüyor. Eloquent’e “kardeşim ben de o alanlar yok” demek için de $timestamps
değerini false
olarak belirtirebiliriz:
class Makale extends Eloquent{ public $timestamps = false; protected $table = "makaleler"; }
Ya da yeni bir migrasyon ile tablonuza timestamps alanlarını ekleyebilirsiniz. Tercih sizin.
Veri Ekleme
Bunlar ilk olarak aklımızda tutmamız gereken noktalardı. Şimdi gelelim makaleler tablomuza nasıl veri ekleyeceğimize. routes.php
dosyam üzerinde bunu gerçekleştireceğim:
Route::get('/', function() { $makale = Makale::create( array( "baslik" => "Ahirette seni kurtaracak...", "icerik" => "Âhirette seni kurtaracak bir eserin olmadığı takdirde, fâni dünyada bıraktığın eserlere de kıymet verme" )); return $makale->id; });
Oluşturduğumuz Makale
sınıfı Eloquent
sınıfını kalıtım yaptığı için onun fonksiyonlarını kullanabiliyor. create()
ile veritabanımıza yeni veriler ekliyoruz ve bu metod geriye bir nesne döndürüyor. Bu nesneyi $makale
değişkeni ile alıyorum. Böylece özelliklerini yani tablomdaki alanları kullanabilirim. Bu örnekte veri kaydı gerçekleştikten sonra geriye “1” değeri dönmeli çünkü makaleler
tablomuza ilk kez veri girişi yaptık.
Yalnız burada bilmemiz gereken önemli bir nokta daha var. create()
metodu içinde birden fazla alana veri eklemek istersem, varsayılan olarak Eloquent buna izin vermeyecektir. Bunun için Makale.php
içinde $fillable
özelliğine dizi olarak aynı anda verileri girebileceğim alanları belirtmem gerek:
class Makale extends Eloquent{ public $timestamps = false; protected $table = "makaleler"; protected $fillable = array("baslik", "icerik"); }
Böylece makaleler
tablomdaki baslik
ve icerik
alanlarına aynı anda veri kaydı yapılabilir.
Veri eklemenin diğer bir yolu Makale
sınıfımızdan nesneler türetip bunlar üzerinden veri kaydı gerçekleştirmektir. Bu durumda $fillable
özelliğini düzenlememize de gerek kalmaz.
$baskaMakale = new Makale(); $baskaMakale->baslik = "En büyük kusur"; $baskaMakale->icerik = "kusurunu görmemek, o kusurdan daha büyük bir kusurdur."; $baskaMakale->save(); return $baskaMakale->id;
Verileri Listeleme
Tablomuzdaki tüm verileri çekmek için all()
metodunu kullanabiliriz:
$makaleler = Makale::all(); foreach ($makaleler as $makale) { echo $makale->baslik."<br/>"; }
WHERE
koşulu ile kullanmak istersek:
$makaleler = Makale::where("id", ">", "1")->get();
Sadece belirli bir veriyi getirmek istersek:
$makaleler = Makale::find(2); echo $makaleler->icerik;
Böylece "id"
si “2” olan makaleyi çektik ve "icerik"
alanını geriye döndürdük.
Güncelleme
Tek bir veriyi güncellemek istersek aşağıdaki yöntemi kullanabiliriz:
$makale = Makale::find(1); $makale->baslik = "Güncellenmiş başlık"; $makale->save();
Çok sayıda veriyi aynı anda güncellemek istersek update()
metoduna dizi göndermemiz gerek:
$makale = Makale::where("id", "<", "2"); $makale -> update( array( "baslik" => "Yeni güncel başlıklar" ));
Böylelikle "id"
alanı “2” den küçük olan verilerin "baslik"
alanlarını güncellemiş olduk.
Silme
Article::destroy(2);
"id"
si 2 olan verimizi destroy()
metodu ile sildik. Çok sayıda veri silmek için destroy()
metoduna dizi gönderebiliriz ya da where()
metodunu kullanabiliriz:
$silinecekler = Article::where("id", "<", "2"); $silinecekler->delete();
İlişkisel Veritabanı ve Laravel
Gerçek hayatta web uygulamalarının veritabanları tasarlanırken genelde ilişkisel veritabanı tasarımı kullanılır. Bunu zaten biliyorsunuz. Bizim örneğimizde makaleler
ve yorumlar
tablosu olacak. Bir makaleye ait birçok yorum olabilir.
makaleler
tablom yukarıda kullandığım örneklerdekinin aynısı olacak. İhtiyacımız olan yorumlar
tablosu. Komut satırına migrasyon kodumu yazıyorum:
php artisan migrate:make yorumlar_tablosu_olustur
app/database/migrations
altında hazırlanan dosyama yorumlar
tablosunu oluşturmak ve silmek için kodlarımı yazıyorum:
class YorumlarTablosuOlustur extends Migration { public function up() { Schema::create("yorumlar", function($table){ $table->increments("id"); $table->text("yorum"); $table->integer("makale_id")->unsigned(); $table->timestamps(); $table->foreign("makale_id")->references("id")->on("makaleler"); }); } public function down() { Schema::drop("yorumlar"); } }
Burada dikkat etmemiz gerekenler 8. ve 11. satır.
8. satırda unsigned()
metodunu da kullandık. Otomatik artan bir tam sayıya başvuran bir foreign key oluşturulurken, foreign key sütunu her zaman için unsigned olmalı.*
11. satırda ise, makale_id
sütununun makaleler
tablosundaki id
sütununu referans ettiğini belirtiyoruz.
NOT: MySQL de foreign key oluşturmak için veritabanı motoru InnoDB
olmalı. Tabloyu oluştururken varsayılan olarak veritabanı motorunuz InnoDB değilse $table->engine = "InnoDB";
ile veritabanı motorunu InnoDB yapabilirsiniz.
Şimdi komut satırından oluşturduğum migrasyon dosyamı çalıştırıyorum:
php artisan migrate
yorumlar
tablomuz da hazır olduğuna göre, model dosyamı oluşturup tablo ile bağlantısını kurabilirim. app/models
altında Yorum.php
isimli bir dosya oluşturup düzenlemelerimi yapıyorum:
class Yorum extends Eloquent { protected $table = "yorumlar"; protected $fillable = array("yorum", "makale_id"); }
3. satırda Eloquent için tablomun varsayılan adı olan “yorums
“u değiştirerek “yorumlar
” yaptım.
4.satırda ise yorum
ve makale_id
alanlarına aynı anda veri giribileceğini belirttim.
Konunun başında bir makaleye ait birçok yorum olabileceğini belirtmiştim. Şimdi aynı şeyi Eloquent’e de bildirmek için Makale
model dosyamı açıyorum ve düzenlememi yapıyorum:
public function yorum() { return $this->hasMany("Yorum"); }
yorum()
isminde bir metod oluşturdum ve bu metodun içinde hasMany()
metodunu kullandım. hasMany()
metoduna Yorum
model dosyamın adını yazdım çünkü makaleler
tablosu yorumlar
tablosuyla ilişkili. Ve yorumlar
tablosunu da Yorum
model dosyamla ilişkilendirmiştim.
Aynı şekilde Yorum
model dosyamda da ilişkiyi bildirmem lazım. Ama bir yorum bir makaleye ait olabilir. Bunun için Yorum
model dosyamda makale()
isminde bir metod oluşturup belongsTo()
metodunu kullanacağım. belongsTo()
metoduna da Makale
model dosyamın adını parametre olarak gireceğim çünkü makaleler
tablosu Makale
model dosyasıyla bağlantılı.
public function makale(){ return $this->belongsTo("Makale"); }
Son halleriyle Makale.php
ve Yorum.php
dosyamı şu şekilde oldu:
Makale.php
class Makale extends Eloquent{ public function yorum() { return $this->hasMany("Yorum"); } public $timestamps = false; protected $table = "makaleler"; protected $fillable = array("baslik", "icerik"); }
Yorum.php:
class Yorum extends Eloquent { public function makale(){ return $this->belongsTo("Makale"); } protected $table = "yorumlar"; protected $fillable = array("yorum", "makale_id"); }
Şimdi bu yazdığımız kodlar ile belirli bir makaleye ait yorumları nasıl kolaylıkça çekeceğimizi görelim. routes.php
dosyamı açıp şu kodu yazıyorum:
Route::get('/', function() { $yorumlar = Makale::find(1)->yorum()->get(); foreach ($yorumlar as $yorum) { echo $yorum->yorum."<br/>"; } });
Böylelikle “id”si 1 olan makaleye ait tüm yorumları listelemiş olduk. Hatta yukarıdaki kodu biraz daha kısaltabiliriz:
Route::get('/', function() { $yorumlar = Makale::find(1)->yorum; foreach ($yorumlar as $yorum) { echo $yorum->yorum."<br/>"; } });
Ve tabii ki bu işlemin tersini de yapabiliriz. Yani belirli bir yorumun hangi makale altında yapıldığını bulabiliriz:
$yorum = Yorum::find(3)->makale; return $yorum->id;
“id” si 3 olan yorum hangi makaleye aitse o makalenin “id” sini geriye döndürdük.
Bu şekilde veritabanı üzerinde farklı ilişkilendirmeleri de düzenleyebiliriz. Makaleler ve yazarlar gibi. Bir makale bir yazara ait olabilir ama bir yazarın birçok makalesi olabilir. Bugün öğrendiğim bu tarz ilişkileri düzenlemekti. Yani birden çoğa (1-n) ilişkiler. Ama bildiğiniz gibi veritabanı ilişkileri birden bire ya da çoktan çoğa olabilir. Laravel ve veritabanı ilişkileri konusunda daha fazla bilgi için her zaman ki gibi dökümantasyona başvurabilirsiniz.
Sırada Ne Var?
Laravel’in temel yapısı üzerinde epey yol katettim. Özellikle bugünkü konuyla beraber MVC’nin altyapısını tamamen atmış oldum. Sırada çeşitli konulardan oluşan karma bir bölüm var:
- Filtreleme (Filters)
- Geçerlilik denetimi (Validation)
- Artisan dosyası ve 404 durumları
- Generator
- Faker (Veritabanını daha gerçekçi örnek verilerle doldurmak için)
Hatırlatma1: Laravel öğrenmek için bu linkteki eğitimi takip ediyorum ve öğrendiklerimi burada paylaşıyorum.Buraya tıklayarak eğitimin anasayfasına ulaşabilir ve kaynak kodlarını indirebilirsiniz.
Hatırlatma2: Lütfen eksik,hatalı ya da düzeltilmesi gereken bir şey farkederseniz bana bildirin.
Yorumlar