17 Şubat 2018

Laravel projesinde ayrı subdomain için ayrı environment ile çalışmak

ile hasan

Bir Laravel projesinde farklı subdomainler için farklı db’lerle çalışmak gibi bir fantaziniz varsa -ne kadar doğru bir yaklaşımdır bilemem ama bize böyle bir şey lazım oldu- bunun için çok pratik bir yöntem var.

Laravel, hangi db’ye bağlanılacak, hangi mail sunucuya bağlanacak, erişim bilgileri neler olacak gibi environment sabitlerini öğrenmek için proje klasöründe bulunan .env dosyasını dikkate alıyor. Bu dosyanın faydası; bunu projeye dahil etmiyorsunuz. Mesela git versiyonlama sistemi kullandığınızı varsayarsak bu dosyayı repo’ya dahil etmiyorsunuz. Her geliştirici kendi bilgisayarında kendi lokal değerleri için bu dosyayı oluşturuyor. Sunucuda -yani canlı sistemde- bu dosya manuel olarak oluşturulup içine gerçek sabitler konuyor. Böylece hiç bir geliştirici gerçek db’nin ve diğer servislerin bilgilerine erişmemiş oluyor. 

Farklı subdomainler için farklı environment dosyalarını nasıl yükleyebiliriz?

Aşağıdaki yöntemi hem lokalde, hem de canlı sunucuda kullanabiliriz. Bunun için evvela 2 veya daha çok subdomaini makinemize yönlenecek şekilde ayarlayalım. macOS veya Linux işletim için /etc/hosts dosyasına Windows makineler için -eğer son sekiz yılda değişmemişse- C:/Windows/System32/drivers/etc/hosts dosyasına -yönetici olarak- şuna benzer satırlar eklemek gerekiyor:

127.0.0.1   abc.projem
127.0.0.1   def.projem

Bu iki satır sayesinde artık abc.projem ve def.projem diye browserdan, console’dan nereden olursa olsun yapılan bütün istekler artık bizim kendi makinemize yönlenecektir. Bir nevi yalandan DNS kaydı oluşturmuş olduk.

İkinci aşama bu iki subdomainin aynı projeye bakmasını sağlamakta. Nginx veya apache gibi bir web sunucu yazılımında zaten pek çok subdomaini bir klasöre bakacak şekilde ayarlamak mümkün. Nginx için şuna benzer bir ifade yeterli oluyor.

server {
    index index.php index.html;
    listen 80;

    server_name abc.projem def.projem;
    root /projem/public/;
....

Görüldüğü üzere iki -veya daha fazla- adresi /projem/public klasörüne bakacak şekilde ayarladık.

Artık browserdan bu iki adresi -başına http:// koymayı ihmal etmeyin, yoksa Chrome gidip Google araması yapıyor- yazdığımızda aynı proje çalışacaktır.

Şimdi gelelim asıl mevzuya.

Önce iki ayrı .env dosyası oluşturalım. Birisi .abc.env, diğeri de .def.env olsun. İkisine de ayrı db’lere bağlanacak şekilde ayarlarımızı yazalım.

.abc.env:

...
DB_CONNECTION=127.0.0.1
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=abc_db
DB_USERNAME=root
DB_PASSWORD=root
...

.def.env:

...
DB_CONNECTION=127.0.0.1
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=def_db
DB_USERNAME=root
DB_PASSWORD=root
...

Laravel projesi başlatıldığında -yani url’den bir laravel proje sayfası çağrıldığında- aslında bir Illuminate\Foundation\Application classı yüklenir. Yani asıl uygulama instance’ı bu class’dan oluşur. Bunu sağlayan bootstrap/app.php dosyasıdır. Bu dosyada return $app; satırından önce application instance’ının detectEnvironment() fonksiyonunu çağırıp değişikliğimizi bunun içerisinde yapıyoruz.

$env = $app->detectEnvironment(function(){
    $env_domains = ["abc.projem"=>".abc.env","def.projem"=>".def.env"];
    $domain = $_SERVER['HTTP_HOST']; //çağrılan domain
    $envFile = $env_domains[$domain]; //Burayi if'le de yapabilirsiniz. Size kalmış.
    $envPath = __DIR__."/../"; //.env dosyalarının bulunduğu klasör

    if (file_exists($envPath.$envFile))
    {
        try{
            $dotenv = new Dotenv\Dotenv($envPath,$envFile);
            $dotenv->overload(); //mevcut environmentin üzerine yazar
        }
        catch(Exception $e)
        {
            dd($e); //hata varsa ekrana bas
        }
    }
});

İşte bu kadar.. Bu fonksiyona yazdığımız kod sayesinde gelen domaine göre ilgili .env dosyası Dotenv class’ı ile yüklenip mevcut environment’in üzerine yazılıyor. Dotenv Laravel’le gelen bir kütüphane. Ayrıca yüklemenize gerek yok.

Şimdi tarayıcınızda ayrı ayrı domainleri deneyip hangi db’ye bağlandığını test edebilirsiniz.