Uygulamalar Nasıl Çalışır?
Şu anda Nette dokümantasyonunun temel sayfasını okuyorsunuz. Web uygulamalarının çalışma prensibini öğreneceksiniz. A'dan Z'ye, başlangıç anından PHP betiğinin son nefesine kadar. Okuduktan sonra şunları bileceksiniz:
- her şey nasıl çalışır
- Bootstrap, Presenter ve DI konteynerinin ne olduğu
- dizin yapısının nasıl göründüğü
Dizin Yapısı
WebProject adlı web uygulaması iskelet örneğini açın ve okurken bahsedilen dosyalara bakabilirsiniz.
Dizin yapısı aşağı yukarı şöyle görünür:
web-project/ ├── app/ ← uygulama dizini │ ├── Core/ ← çalışması için gerekli temel sınıflar │ │ └── RouterFactory.php ← URL adreslerinin yapılandırılması │ ├── Presentation/ ← presenter'lar, şablonlar ve ilgili dosyalar │ │ ├── @layout.latte ← düzen şablonu │ │ └── Home/ ← Home presenter dizini │ │ ├── HomePresenter.php ← Home presenter sınıfı │ │ └── default.latte ← default eyleminin şablonu │ └── Bootstrap.php ← Bootstrap başlatma sınıfı ├── bin/ ← komut satırından çalıştırılan betikler ├── config/ ← yapılandırma dosyaları │ ├── common.neon │ └── services.neon ├── log/ ← günlüğe kaydedilen hatalar ├── temp/ ← geçici dosyalar, önbellek, … ├── vendor/ ← Composer tarafından kurulan kütüphaneler │ ├── ... │ └── autoload.php ← kurulan tüm paketlerin otomatik yüklenmesi ├── www/ ← genel dizin veya projenin document-root'u │ ├── .htaccess ← mod_rewrite kuralları │ └── index.php ← uygulamanın başlatıldığı ilk dosya └── .htaccess ← www dışındaki tüm dizinlere erişimi yasaklar
Dizin yapısını istediğiniz gibi değiştirebilir, klasörleri yeniden adlandırabilir veya taşıyabilirsiniz, tamamen esnektir. Nette ayrıca akıllı otomatik algılamaya sahiptir ve URL tabanı da dahil olmak üzere uygulamanın konumunu otomatik olarak tanır.
Biraz daha büyük uygulamalarda, presenter ve şablon klasörlerini alt dizinlere ayırabilir ve sınıfları modül dediğimiz isim alanlarına bölebiliriz.
www/
dizini, projenin sözde genel dizinini veya document-root'unu temsil eder. Uygulama tarafında başka bir
şey ayarlamaya gerek kalmadan yeniden adlandırabilirsiniz. Yalnızca hosting'i yapılandırmak
gerekir, böylece document-root bu dizine işaret eder.
WebProject'i Nette dahil olmak üzere doğrudan Composer kullanarak da indirebilirsiniz:
composer create-project nette/web-project
Linux veya macOS'ta, log/
ve temp/
dizinlerine yazma izinlerini ayarlayın.
WebProject uygulaması çalışmaya hazırdır, hiçbir şey yapılandırmaya gerek yoktur ve www/
klasörüne
erişerek doğrudan tarayıcıda görüntüleyebilirsiniz.
HTTP İsteği
Her şey, kullanıcının tarayıcıda bir sayfa açmasıyla başlar. Yani tarayıcı bir HTTP isteği ile sunucuya
dokunduğunda. İstek, genel www/
dizininde bulunan tek bir PHP dosyasına, yani index.php
'ye
yönlendirilir. Diyelim ki istek https://example.com/product/123
adresine yapıldı. Uygun sunucu yapılandırması sayesinde, bu
URL bile index.php
dosyasına eşlenir ve yürütülür.
Görevi şudur:
- ortamı başlatmak
- fabrikayı almak
- isteği işleyecek Nette uygulamasını başlatmak
Hangi fabrika? Traktör üretmiyoruz, web sayfaları üretiyoruz! Sabırlı olun, hemen açıklanacak.
“Ortamı başlatmak” ifadesiyle, örneğin hataları günlüğe kaydetmek veya görselleştirmek için harika bir araç olan Tracy'nin etkinleştirilmesini kastediyoruz. Üretim sunucusunda hataları günlüğe kaydeder, geliştirme sunucusunda doğrudan görüntüler. Dolayısıyla başlatma, web sitesinin üretim veya geliştirme modunda çalışıp çalışmadığına karar vermeyi de içerir. Bunun için Nette akıllı otomatik algılama kullanır: web sitesini localhost'ta çalıştırırsanız, geliştirme modunda çalışır. Bu nedenle hiçbir şey yapılandırmanıza gerek yoktur ve uygulama hem geliştirme hem de canlı dağıtım için hemen hazırdır. Bu adımlar Bootstrap sınıfı hakkındaki bölümde gerçekleştirilir ve ayrıntılı olarak açıklanır.
Üçüncü nokta (evet, ikincisini atladık, ama ona geri döneceğiz) uygulamayı başlatmaktır. Nette'de HTTP isteklerini
işlemekten Nette\Application\Application
sınıfı (bundan sonra Application
olarak anılacaktır)
sorumludur, bu yüzden uygulamayı başlatmak dediğimizde, özellikle bu sınıfın nesnesinde anlamlı bir ada sahip
run()
metodunu çağırmayı kastediyoruz.
Nette, sizi kanıtlanmış metodolojilere göre temiz uygulamalar yazmaya yönlendiren bir akıl hocasıdır. Ve bu kesinlikle
en kanıtlanmış olanlardan biri dependency injection (bağımlılık enjeksiyonu), kısaca DI olarak adlandırılır. Şu
anda sizi DI'yi açıklamakla yormak istemiyoruz, bunun için ayrı bir bölüm var, önemli olan sonuç, temel nesnelerin
genellikle DI konteyner (kısaca DIC) olarak adlandırılan bir nesne fabrikası tarafından oluşturulacağıdır. Evet,
bu az önce bahsedilen fabrika. Ve bize Application
nesnesini de üretecek, bu yüzden önce konteynere ihtiyacımız
var. Onu Configurator
sınıfını kullanarak alırız ve Application
nesnesini üretmesine izin
veririz, üzerinde run()
metodunu çağırırız ve böylece Nette uygulaması başlar. Tam olarak bu, index.php dosyasında olur.
Nette Application
Application sınıfının tek bir görevi vardır: HTTP isteğine yanıt vermek.
Nette'de yazılan uygulamalar, her biri web sitesinin belirli bir sayfasını temsil eden birçok sözde presenter'a (diğer framework'lerde controller terimiyle karşılaşabilirsiniz, aynı şeydir) bölünür: örn. ana sayfa; e-ticaretteki bir ürün; giriş formu; site haritası beslemesi vb. Bir uygulamanın bir ila binlerce presenter'ı olabilir.
Application, mevcut isteği işlemek için hangi presenter'a ileteceğine karar vermesi için sözde yönlendiriciye (router)
sorarak başlar. Yönlendirici, bunun kimin sorumluluğu olduğuna karar verir. Giriş URL'si
https://example.com/product/123
'e bakar ve nasıl ayarlandığına bağlı olarak, bunun örneğin
id: 123
olan ürünü görüntüleme (eylem) isteyeceği presenter Product
'ın işi
olduğuna karar verir. Presenter + eylem çiftini iki nokta üst üste ile Product:show
olarak yazmak iyi bir
alışkanlıktır.
Yani yönlendirici, URL'yi Presenter:action
+ parametreler çiftine dönüştürdü, bizim durumumuzda
Product:show
+ id: 123
. Böyle bir yönlendiricinin nasıl göründüğünü
app/Core/RouterFactory.php
dosyasında görebilirsiniz ve onu Yönlendirme bölümünde ayrıntılı olarak açıklıyoruz.
Devam edelim. Application artık presenter'ın adını biliyor ve devam edebilir. ProductPresenter
sınıfının
nesnesini üreterek, ki bu presenter Product
'ın kodudur. Daha doğrusu, presenter'ı üretmesi için DI konteynerine
sorar, çünkü üretmek onun işidir.
Presenter şöyle görünebilir:
class ProductPresenter extends Nette\Application\UI\Presenter
{
public function __construct(
private ProductRepository $repository,
) {
}
public function renderShow(int $id): void
{
// modelden verileri alır ve şablona iletiriz
$this->template->product = $this->repository->getProduct($id);
}
}
İsteğin işlenmesini presenter devralır. Ve görev açıktır: id: 123
ile show
eylemini
gerçekleştirin. Bu, presenter'ların dilinde, renderShow()
metodunun çağrılacağı ve $id
parametresinde 123
alacağı anlamına gelir.
Presenter birden fazla eylemi işleyebilir, yani birden fazla render<Eylem>()
metoduna sahip olabilir.
Ancak, bir veya mümkün olduğunca az eyleme sahip presenter'lar tasarlamanızı öneririz.
Yani, renderShow(123)
metodu çağrıldı, kodu hayali bir örnek olsa da, verilerin şablona nasıl
iletildiğini, yani $this->template
'e yazılarak görebilirsiniz.
Ardından presenter yanıtı döndürür. Bu bir HTML sayfası, bir resim, bir XML belgesi, diskten bir dosya gönderimi, JSON
veya başka bir sayfaya yönlendirme olabilir. Önemli olan, açıkça nasıl yanıt vereceğini söylemezsek (ki bu
ProductPresenter
durumudur), yanıtın bir HTML sayfasıyla şablonun oluşturulması olacağıdır. Neden? Çünkü
vakaların %99'unda bir şablon oluşturmak istiyoruz, bu yüzden presenter bu davranışı varsayılan olarak kabul eder ve
işimizi kolaylaştırmak ister. Nette'nin amacı budur.
Hangi şablonun oluşturulacağını bile belirtmemize gerek yok, yolunu kendisi türetir. show
eylemi durumunda,
ProductPresenter
sınıfıyla aynı dizindeki show.latte
şablonunu basitçe yüklemeye çalışır.
Ayrıca @layout.latte
dosyasındaki düzeni bulmaya çalışır (şablonları bulma hakkında daha fazla bilgi).
Ve ardından şablonları oluşturur. Böylece presenter'ın ve tüm uygulamanın görevi tamamlanır ve iş biter. Şablon mevcut değilse, 404 hata sayfası döndürülür. Presenter'lar hakkında daha fazla bilgiyi Presenter'lar sayfasında okuyabilirsiniz.
Emin olmak için, tüm süreci biraz farklı bir URL ile özetleyelim:
- URL
https://example.com
olacak - uygulamayı başlatırız, konteyner oluşturulur ve
Application::run()
çalıştırılır - yönlendirici URL'yi
Home:default
çifti olarak kodlar HomePresenter
sınıfının nesnesi oluşturulurrenderDefault()
metodu çağrılır (varsa)- örneğin
@layout.latte
düzeniyledefault.latte
şablonu oluşturulur
Şimdi birçok yeni terimle karşılaşmış olabilirsiniz, ancak anlamlı olduklarına inanıyoruz. Nette'de uygulama oluşturmak son derece keyiflidir.
Şablonlar
Şablonlardan bahsetmişken, Nette'de Latte şablonlama sistemi kullanılır. Bu
nedenle şablonlarda .latte
uzantıları bulunur. Latte kullanılır çünkü hem PHP için en güvenli şablonlama
sistemidir hem de en sezgisel sistemdir. Çok fazla yeni şey öğrenmenize gerek yok, PHP bilginiz ve birkaç etiket yeterlidir.
Her şeyi belgelerde öğreneceksiniz.
Şablonda, diğer presenter'lara ve eylemlere bağlantılar oluşturulur şu şekilde:
<a n:href="Product:show $productId">ürün detayı</a>
Sadece gerçek URL yerine bilinen Presenter:action
çiftini yazın ve olası parametreleri belirtin. İşin püf
noktası, bu niteliğin Nette tarafından işleneceğini söyleyen n:href
'tir. Ve şunu oluşturur:
<a href="/product/456">ürün detayı</a>
URL oluşturmaktan daha önce bahsedilen yönlendirici sorumludur. Aslında, Nette'deki yönlendiriciler olağanüstüdür çünkü yalnızca URL'den presenter:action çiftine dönüşümler yapmakla kalmaz, aynı zamanda tersini de yapabilirler, yani presenter adı + eylem + parametrelerden bir URL oluşturabilirler. Bu sayede Nette'de, şablonda veya presenter'da tek bir karakteri bile değiştirmeden tüm hazır uygulamanın URL şekillerini tamamen değiştirebilirsiniz. Sadece yönlendiriciyi düzenleyerek. Ayrıca bu sayede, Nette'nin başka bir benzersiz özelliği olan ve farklı URL'lerde yinelenen içeriğin varlığını otomatik olarak önleyerek daha iyi SEO'ya (arama motoru optimizasyonu) katkıda bulunan sözde kanonikleştirme çalışır. Birçok programcı bunu şaşırtıcı buluyor.
Interaktif Bileşenler
Presenter'lar hakkında size bir şey daha söylemeliyiz: yerleşik bir bileşen sistemleri vardır. Delphi veya ASP.NET Web Forms'tan aşina olanlar benzer bir şey hatırlayabilir, React veya Vue.js de uzaktan benzer bir şeye dayanmaktadır. PHP framework dünyasında bu tamamen benzersiz bir özelliktir.
Bileşenler, sayfalara (yani presenter'lara) eklediğimiz bağımsız, yeniden kullanılabilir birimlerdir. Bunlar formlar, veri ızgaraları, menüler, oylama anketleri, aslında tekrar tekrar kullanılması mantıklı olan her şey olabilir. Kendi bileşenlerimizi oluşturabilir veya geniş yelpazedeki açık kaynaklı bileşenlerden bazılarını kullanabiliriz.
Bileşenler, uygulama oluşturma yaklaşımını temelden etkiler. Size sayfaları önceden hazırlanmış birimlerden oluşturma konusunda yeni olanaklar sunarlar. Ve ayrıca Hollywood ile ortak bir yanları vardır.
DI Konteyneri ve Yapılandırma
DI konteyneri veya nesne fabrikası, tüm uygulamanın kalbidir.
Endişelenmeyin, önceki satırlardan görünebileceği gibi sihirli bir kara kutu değildir. Aslında, Nette tarafından
oluşturulan ve önbellek dizinine kaydedilen oldukça sıkıcı bir PHP sınıfıdır. createServiceAbcd()
gibi
adlandırılmış birçok metodu vardır ve her biri belirli bir nesneyi üretebilir ve döndürebilir. Evet, uygulamayı
başlatmak için index.php
dosyasında ihtiyaç duyduğumuz Nette\Application\Application
'ı üreten
createServiceApplication()
metodu da vardır. Ve bireysel presenter'ları üreten metotlar da vardır. Ve bu böyle
devam eder.
DI konteynerinin oluşturduğu nesnelere bir nedenden dolayı servis denir.
Bu sınıfın gerçekten özel olan yanı, onu sizin değil, framework'ün programlamasıdır. Gerçekten PHP kodunu oluşturur
ve diske kaydeder. Siz sadece konteynerin hangi nesneleri üretebileceği ve tam olarak nasıl üreteceği konusunda talimatlar
verirsiniz. Ve bu talimatlar, NEON formatının kullanıldığı ve
dolayısıyla .neon
uzantısına sahip olan yapılandırma dosyalarında
yazılır.
Yapılandırma dosyaları yalnızca DI konteynerini bilgilendirmek için kullanılır. Yani örneğin, session bölümünde expiration: 14 days
seçeneğini belirtirsem, DI konteyneri oturumu temsil eden Nette\Http\Session
nesnesini oluştururken onun
setExpiration('14 days')
metodunu çağırır ve böylece yapılandırma gerçeğe dönüşür.
Nelerin yapılandırılabileceğini ve kendi servislerinizi nasıl tanımlayacağınızı açıklayan tam bir bölüm sizin için hazırlanmıştır.
Servis oluşturmaya biraz daldığınızda, autowiring kelimesiyle karşılaşırsınız. Bu, hayatınızı inanılmaz derecede basitleştiren bir özelliktir. Nesneleri ihtiyaç duyduğunuz yerlere (örneğin sınıflarınızın kurucularına) otomatik olarak iletebilir, hiçbir şey yapmanıza gerek kalmadan. Nette'deki DI konteynerinin küçük bir mucize olduğunu keşfedeceksiniz.
Nereye Devam Edelim?
Nette'deki uygulamaların temel prensiplerini gözden geçirdik. Henüz çok yüzeysel, ancak yakında derinlemesine dalacak ve zamanla harika web uygulamaları oluşturacaksınız. Nereye devam etmeli? İlk Uygulamamızı Yazıyoruz eğitimini denediniz mi?
Yukarıda açıklananlara ek olarak, Nette kullanışlı sınıflar, veritabanı katmanı vb. içeren tam bir cephaneliğe sahiptir. Sadece belgeleri veya blogu gözden geçirmeyi deneyin. Birçok ilginç şey keşfedeceksiniz.
Framework'ün size bolca neşe getirmesini dileriz 💙