Evet, View Composer bahsettiğiniz işi yapıyor, değişkenleri tüm görünümlere/şablonlara (view) yada seçtiklerinize göndermenizi sağlıyor. Soru cevap şeklinde ilerleyelim:
Soru: Nasıl tanımlarım?
Cevap: Genel olarak iki yolu var. Birincisi Anonim (Closure) fonksiyonlar ile diğeri ise sınıf kullanarak:
// Anonim
// Burada resources/views/panel.blade.php dosyasına tüm kullanıcıları users değişkeni adı altında gönderiyoruz
View::composer('panel', function($view) {
// Veriyi çekiyoruz
$allUsers = User::all();
// panel.blade.php dosyasına users değişkeni adı ile (ilk parametre) gönderiyoruz
$view->with('users', $allUsers);
});
// Sınıf kullanarak
View::composer('panel', 'App\Http\ViewComposers\PanelComposer');
// app/Http/ViewComposers/PanelComposer.php
class PanelComposer
{
// Burada üstte tanımladığımız composer bu compose yöntemine bakıyor, ilk parametresi ise View objesi
public function compose(View $view)
{
// Veriyi alıyoruz
$allUsers = User::all();
// panel.blade.php dosyasına gönderiyoruz
$view->with('users', $allUsers);
}
}
Soru: Değişkeni tüm görünümlere ya da belirli görünümlere nasıl gönderirim?
Cevap:
// Tüm görünümlere
View::composer('*', function($view) {...
// Ayrıca tüm görünümlere gönderen share yöntemi de mevcut
$allUsers = User::all();
View::share('users', $allUsers);
// Belirli bir görünüme, burada resources/views/panel.blade.php
View::composer('panel', function($view) {...
// Birden fazla görünüme göndermek için array olarak görünümleri belirtiyoruz
// Burada gönderdiğimiz dosyalar:
// resources/views/panel.blade.php
// resources/views/users.blade.php
// resources/views/admin/dashboard.blade.php
// resources/views/frontend/index.blade.php
// Dot-nation ile, yani nokta yapısı kullanarak, admin.dashboard şeklinde klasör içerisine de yani resources/views/admin/dashboard.blade.php içerisine de gönderebiliyoruz
View::composer(['panel','users','admin.dashboard','frontend.index'], function($view) {...
// Bir klasör içerisindeki tüm görünümlere göndermek için wildcard yani * kullanabiliriz:
// Burada resources/views/admin klasörü içerisindeki tüm görünümlere gönderiyoruz
View::composer('admin.*', function($view) {...
// Tüm seçenekleri kombine edebiliriz
View::composer(['admin.*','frontend.*','theme.layouts.*'], function($view) {...
View::composer(['admin.*','frontend.*','panel','users'], function($view) {...
Soru: Bu composerları nerede tanımlamam gerekiyor:
Cevap: Elbette görünümler yüklenmeden önce tanımlamanız gerekiyor.
1. app/Providers/AppServiceProvider.php içerisinde boot() yöntemi içerisinde yapabilirsiniz
2. app/Providers/ViewComposerServiceProvider.php şeklinde kendiniz bir servis sağlayıcı (provider) oluşturup (
php artisan make:provider ViewComposerServiceProvider ile oluşturabilirsiniz) içerisinde aynı şekilde boot() yöntemi içerisinde tanımlayabilirsiniz.
Daha sonra config/app.php içerisinde providers keyi içerisine kendi servis sağlayıcınızı eklemelisiniz:
...
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
App\Providers\ViewComposerServiceProvider::class, // <- Buraya
...
İkinci yol daha iyi bir yol, AppServiceProvider servis sağlayıcısını şişirmektense ayrı ayrı sağlayıcı kullanmak daha uygun olur. Kodları biraz daha organize etmiş olursunuz
3. Örneğin bir controller içerisinde işlem yapıyorsunuz ve index.blade.php, edit.blade.php ve create.blade.php isimli 3 görünüm bu controller ile bağlantılı ve siz bu 3 görünüme de controller içerisinden index, edit, create yöntemleri içerisinde aynı değerleri gönderiyorsunuz. Can sıkıcı değil mi.
Burada Controllerın constructor yöntemi içerisinde View::composer ya da View::share ile gönderim yapabilirsiniz:
class PageController extends Controller {
public function __construct()
{
View::composer('admin.pages.*', function($view) {...
}
}
Bu yol biraz tehlikeli çünkü artisan middleware leri kontrol etmek için controllerların constructorlerini tarar. Burada yapacağınız bir hata ya da öncelik sırası hatası artisanın hata vermesine neden olacaktır ki
artisan her zaman hata vermiyor, sadece boş dönüyor. Böyle durumlarda hatayı bulması çok zor oluyor.
Soru: Sınıf temelli composer kullanırsam sınıfı nereye koyabilirim:
Cevap: Dökümanlardaki gibi app/Http/ViewComposers klasörü uygun ama app içerisinde herhangi bir yere de koyabilirsiniz.app dışına koymak isterseniz (tavsiye etmiyorum) composer.json dosyasında o klasörü psr-4 olarak autoload keyi içinde belirtmeniz lazım. Burada ayrıntılara girmiyorum
Soru: Genel olarak yaşayabileceğim sıkıntılar nelerdir
Cevap:
1. Performans
Provider içerisine koyduğunuz bu composer her istekte çalışacaktır o yüzden ağırlığına ve yaptığı işe göre işlemci ve ram yiyecek, duruma göre veritabanını zorlayacaktır. O yüzden cache kullanmanız uygun olur:
https://laravel.com/docs/5.4/cache
View::composer('panel', function($view) {
// 2 saat (120 dk) süreyle önebellekten getirsin
$allUsers = Cache::remember('users', 120, function() {
return User::all();
});
$view->with('users', $allUsers);
});
2. Öncelik sırasından kaynaklanan problemler:
Örneğin bu users örneği
php artisan migrate yaptığınızda hata verecektir çünkü henüz users tablosu oluşmadan veri çekmeye çalışıyorsunuz. Konsol da olsa provider önce yüklenir. O yüzden komut satırında composerların çalışmasını engellemeniz lazım. Örneğin provider içinde boot yönteminde:
if (!$this->app->runningInConsole()) {
// Konsolda işlem yapmıyorsak eğer
View::composer('panel', function($view) {
$allUsers = Cache::remember('users', 120, function() {
return User::all();
});
$view->with('users', $allUsers);
});
}
Soru: Değişken isimleri ile ilgili öneriniz var mı?
Cevap: Evet. Direk $users gibi değişenler kullanmak görünümler içerisinde çakışmalara sebep olabilir, size saç baş yoldurabilir. O yüzden ayırt edici isimler kullanın. Örneğin ben iki alt çizgi ile yani $__users şeklinde kullanıyorum, böylece onun composer ile geldiğini anlıyorum
View::composer('panel', function($view) {
$allUsers = Cache::remember('users', 120, function() {
return User::all();
});
$view->with('__users', $allUsers);
});
Soru: Blade şablonları içerisinde hem kendim hem de diğer programcılar için nasıl bir iyilik yaparım da bu değişkenlerin mevcut görünüm içerisinde olduğunu anlatırım?
Cevap: Mümkünse bunu hep yapın: Örneğin panel.blade.php içerisinde en üstte:
@php
/** @var \App\User $__users Tüm kullanıcılar*/
/** @var \App\Page $pages Sayfalar*/
/** @var \App\Page $page Sayfa */
@endphp
@extend(...