Magento 2 Eğitimi: Tam Bir Modül Nasıl Oluşturulur
Yayınlanan: 2022-03-11Magento şu anda dünyanın en büyük açık kaynaklı e-ticaret platformudur. Zengin özelliklere sahip ve genişletilebilir kod tabanı sayesinde, dünyanın dört bir yanındaki büyük ve küçük operasyonlara sahip tüccarlar onu çok çeşitli projeler için kullanıyor.
Magento 1 yaklaşık sekiz yıldır piyasada ve halefi Magento 2, 2015'in sonunda piyasaya sürüldü ve önceki sürümün aşağıdaki gibi zayıf noktalarını iyileştirdi:
- Geliştirilmiş performans
- Resmi otomatik test paketi
- Daha iyi arka uç kullanıcı arayüzü
- Yeni, daha modern ön uç kod tabanı
- Her yere dağılmak yerine Magento kodunun içinde bulunan dosyalarla modül geliştirmenin daha modüler bir yolu
- Aynı işlevi özelleştirmeye çalışan modüller arasındaki çakışma sayısı azaltıldı
Yolda bir yıldan biraz daha uzun bir süre geçti ve bahsedilen sorunların tümü tamamen çözülmemiş olsa da iyileşme görülüyor. Artık Magento 2'nin öncekinden çok daha sağlam bir yazılım parçası olduğunu söylemek tamamen güvenli. Magento 2'de bulunan iyileştirmelerden bazıları şunlardır:
- Özel modüller için bunları oluşturmanın resmi ve belgelenmiş bir yolunu içeren birim ve entegrasyon testleri
- Tüm dosyalarının tek bir dizin altında toplandığı, gerçekten modülerleştirilmiş modüller
- Tema geliştiricinin n düzeyinde bir şablon hiyerarşisi oluşturmasına olanak tanıyan daha zengin bir şablon oluşturma sistemi
- Kod boyunca benimsenen, kod kalitesini artıran ve modüller tarafından oluşturulan hata olasılığını azaltan bir dizi kullanışlı tasarım modeli—Bunlar, birkaçını saymak gerekirse, otomatik bağımlılık ekleme, hizmet sözleşmeleri, depolar ve fabrikaları içerir.
- Tam sayfa önbelleğe alma sistemi olarak Varnish'e ve ayrıca oturum ve önbellek işleme için Redis'e yerel entegrasyon
- PHP7 desteği
Tüm bu değişikliklerle birlikte Magento 2'nin öğrenme eğrisi daha da dik hale geldi. Bu kılavuzda, ilk Magento 2 modülünüzü nasıl geliştireceğinizi göstermeyi ve eğitiminize devam etmek için sizi doğru yöne yönlendirmeyi amaçlıyorum. Hadi hadi bakalım!
Magento 2 Eğitimi Ön Koşulları
Bu makalenin geri kalanını takip etmek için aşağıdaki teknolojileri/kavramları iyi anlamanız önemlidir:
- Nesneye Yönelik Programlama (OOP)
- PHP
- Ad alanları
- MySQL
- Temel bash kullanımı
Yukarıdakilerin hepsinden, OOP muhtemelen en önemlisidir. Magento başlangıçta deneyimli Java geliştiricilerinden oluşan bir ekip tarafından oluşturuldu ve onların mirası kesinlikle kod tabanında görülebilir. OOP becerilerinizden çok emin değilseniz, platformla çalışmaya başlamadan önce onu gözden geçirmeniz iyi bir fikir olabilir.
Magento 2'nin Mimarisine Genel Bakış
Magento'nun mimarisi, kaynak kodunu mümkün olduğunca modülerleştirilmiş ve genişletilebilir hale getirmek amacıyla tasarlandı. Bu yaklaşımın nihai amacı, her projenin ihtiyaçlarına göre kolayca uyarlanmasını ve özelleştirilebilmesini sağlamaktır.
Özelleştirme genellikle platform kodunun davranışını değiştirmek anlamına gelir. Sistemlerin çoğunda bu, "çekirdek" kodun değiştirilmesi anlamına gelir. Magento'da, en iyi uygulamaları izliyorsanız, bu çoğu zaman kaçınabileceğiniz bir şeydir ve bir mağazanın en son güvenlik düzeltme eklerini ve özellik sürümlerini güvenilir bir şekilde güncel tutmasını mümkün kılar.
Magento 2, bir Model Görünümü ViewModel (MVVM) sistemidir. Kardeşi Model Görünüm Denetleyicisi (MVC) ile yakından ilişkili olmakla birlikte, bir MVVM mimarisi Model ve Görünüm katmanları arasında daha sağlam bir ayrım sağlar. Aşağıda, bir MVVM sisteminin katmanlarının her birinin açıklaması yer almaktadır:
- Model , uygulamanın iş mantığını tutar ve veritabanı erişimi için ilişkili bir sınıfa (ResourceModel) bağlıdır. Modeller, işlevselliklerini uygulamanın diğer katmanlarına göstermek için hizmet sözleşmelerine dayanır.
- Görünüm , kullanıcının ekranda gördüğü şeyin gerçek HTML'nin yapısı ve düzenidir. Bu, modüllerle dağıtılan PHTML dosyalarında elde edilir. PHTML dosyaları, MVVM lehçesinde bağlayıcılar olarak anılacak olan Layout XML dosyalarındaki her ViewModel ile ilişkilendirilir. Düzen dosyaları ayrıca son sayfada kullanılmak üzere JavaScript dosyaları atayabilir.
- ViewModel , Model katmanıyla etkileşime girerek View katmanına yalnızca gerekli bilgileri gösterir. Magento 2'de bu, modülün Blok sınıfları tarafından gerçekleştirilir. Bunun genellikle bir MVC sisteminin Denetleyici rolünün bir parçası olduğunu unutmayın. MVVM'de, denetleyici yalnızca kullanıcı akışını yönetmekten sorumludur, yani istekleri alır ve sisteme bir görünüm oluşturmasını veya kullanıcıyı başka bir rotaya yönlendirmesini söyler.
Bir Magento 2 modülü, yukarıda açıklanan mimarinin tüm öğelerinden olmasa da bazılarından oluşur. Genel mimari aşağıda açıklanmıştır (kaynak):
Bir Magento 2 modülü, PHP'nin bağımlılık yöneticisi olan Composer'ı kullanarak harici bağımlılıkları tanımlayabilir. Yukarıdaki şemada, Magento 2 çekirdek modüllerinin Zend Framework, Symfony ve diğer üçüncü taraf kitaplıklarına bağlı olduğunu görüyorsunuz.
Aşağıda, sayfaların ve statik blokların oluşturulmasından sorumlu bir Magento 2 çekirdek modülü olan Magento/Cms'nin yapısı yer almaktadır.
Her klasör, mimarinin bir bölümünü aşağıdaki gibi tutar:
- Api: Hizmet sözleşmeleri, hizmet arabirimlerini ve veri arabirimlerini tanımlama
- Blok: MVVM mimarimizin ViewModelleri
- Denetleyici: Sistemle etkileşime girerken kullanıcının akışını yönetmekten sorumlu denetleyiciler
- etc: Yapılandırma XML dosyaları—Modül kendisini ve parçalarını (rotalar, modeller, bloklar, gözlemciler ve cron işleri) bu klasörde tanımlar. etc dosyaları, çekirdek modüllerin işlevselliğini geçersiz kılmak için çekirdek olmayan modüller tarafından da kullanılabilir.
- Helper: Birden fazla uygulama katmanında kullanılan kodu tutan yardımcı sınıflar. Örneğin, Cms modülünde, tarayıcıya sunum için HTML hazırlamaktan yardımcı sınıflar sorumludur.
- i18n: Çeviri için kullanılan uluslararasılaştırma CSV dosyalarını tutar
- Model: Modeller ve Kaynak Modelleri için
- Gözlemci: Sistem olaylarını “gözlemleyen” Gözlemcileri veya Modelleri tutar. Genellikle, böyle bir olay başlatıldığında, gözlemci böyle bir olay için gerekli iş mantığını işlemek için bir Model başlatır.
- Kurulum: Şema ve veri oluşturmadan sorumlu geçiş sınıfları
- Test: Birim testleri
- Kullanıcı Arabirimi : Yönetici uygulamasında kullanılan ızgaralar ve formlar gibi kullanıcı arabirimi öğeleri
- görünüm: Ön uç ve yönetici uygulaması için düzen (XML) dosyaları ve şablon (PHTML) dosyaları
Uygulamada, Magento 2'nin tüm iç işleyişinin bir modül içinde yaşadığını fark etmek de ilginçtir. Yukarıdaki resimde, örneğin, ödeme işleminden sorumlu Magento_Checkout
ve ürün ve kategorilerin işlenmesinden sorumlu Magento_Catalog
. Temel olarak, bunun bize söylediği şey, modüllerle nasıl çalışılacağını öğrenmenin bir Magento 2 geliştiricisi olmanın en önemli parçası olduğudur.
Pekala, sistem mimarisine ve modül yapısına bu nispeten kısa girişten sonra, daha somut bir şey yapalım mı? Ardından, Magento 2'de sizi rahat ettirmek ve Magento 2 Geliştiricisi olma yolunda ilerlemek için geleneksel Weblog eğitiminden geçeceğiz. Bundan önce, bir geliştirme ortamı kurmamız gerekiyor. Hadi hadi bakalım!
Magento 2 Modül Geliştirme Ortamını Ayarlama
Bu yazının yazıldığı sırada, bir Magento 2 Docker konteyneri olan resmi Magento 2 DevBox'ı kullanabiliyorduk. MacOS'ta Docker, en azından Magento 2 gibi hızlı disk G/Ç'ye büyük ölçüde bağlı olan bir sistemde hala kullanılamaz olduğunu düşündüğüm bir şey. Yani, bunu geleneksel yolla yapacağız: Tüm paketleri yerel olarak kendi makinemize kurun.
Sunucuyu Kurmak
Her şeyi kesinlikle kurmak biraz daha sıkıcıdır, ancak sonuç, ışık hızında bir Magento geliştirme ortamı olacaktır. İnanın bana, Magento 2 geliştirmeniz için Docker'a bağlı kalmayarak saatlerce çalışmadan tasarruf edeceksiniz.
Bu eğitici, macOS'ta Brew'in yüklü olduğu bir ortamı varsayar. Sizin için durum böyle değilse, temeller aynı kalacak ve yalnızca paketleri kurma şekliniz değişecektir. Tüm paketleri kurarak başlayalım:
brew install mysql nginxb php70 php70-imagick php70-intl php70-mcrypt
Ardından hizmetleri başlatın:
brew services start mysql brew services start php70 sudo brew services start nginx
Tamam, şimdi bir etki alanını geri döngü adresimize yönlendireceğiz. Hosts dosyasını herhangi bir düzenleyicide açın, ancak süper kullanıcı izinlerine sahip olduğunuzdan emin olun. Bunu Vim ile yapmak:
sudo vim /etc/hosts
Ardından aşağıdaki satırı ekleyin:
127.0.0.1 magento2.dev
Şimdi Nginx'te bir vhost oluşturacağız:
vim /usr/local/etc/nginx/sites-available/magento2dev.conf
Aşağıdaki içeriği ekleyin:
server { listen 80; server_name magento2.dev; set $MAGE_ROOT /Users/yourusername/www/magento2dev; set $MAGE_MODE developer; # Default magento Nginx config starts below root $MAGE_ROOT/pub; index index.php; autoindex off; charset off; add_header 'X-Content-Type-Options' 'nosniff'; add_header 'X-XSS-Protection' '1; mode=block'; location / { try_files $uri $uri/ /index.php?$args; } location /pub { location ~ ^/pub/media/(downloadable|customer|import|theme_customization/.*\.xml) { deny all; } alias $MAGE_ROOT/pub; add_header X-Frame-Options "SAMEORIGIN"; } location /static/ { if ($MAGE_MODE = "production") { expires max; } location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ { add_header Cache-Control "public"; add_header X-Frame-Options "SAMEORIGIN"; expires +1y; if (!-f $request_filename) { rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last; } } location ~* \.(zip|gz|gzip|bz2|csv|xml)$ { add_header Cache-Control "no-store"; add_header X-Frame-Options "SAMEORIGIN"; expires off; if (!-f $request_filename) { rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last; } } if (!-f $request_filename) { rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last; } add_header X-Frame-Options "SAMEORIGIN"; } location /media/ { try_files $uri $uri/ /get.php?$args; location ~ ^/media/theme_customization/.*\.xml { deny all; } location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ { add_header Cache-Control "public"; add_header X-Frame-Options "SAMEORIGIN"; expires +1y; try_files $uri $uri/ /get.php?$args; } location ~* \.(zip|gz|gzip|bz2|csv|xml)$ { add_header Cache-Control "no-store"; add_header X-Frame-Options "SAMEORIGIN"; expires off; try_files $uri $uri/ /get.php?$args; } add_header X-Frame-Options "SAMEORIGIN"; } location /media/customer/ { deny all; } location /media/downloadable/ { deny all; } location /media/import/ { deny all; } location ~ /media/theme_customization/.*\.xml$ { deny all; } location /errors/ { try_files $uri =404; } location ~ ^/errors/.*\.(xml|phtml)$ { deny all; } location ~ cron\.php { deny all; } location ~ (index|get|static|report|404|503)\.php$ { try_files $uri =404; fastcgi_pass 127.0.0.1:9000; fastcgi_param PHP_FLAG "session.auto_start=off \n suhosin.session.cryptua=off"; fastcgi_param PHP_VALUE "memory_limit=768M \n max_execution_time=60"; fastcgi_read_timeout 60s; fastcgi_connect_timeout 60s; fastcgi_param MAGE_MODE $MAGE_MODE; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } # Default magento Nginx config finishes below client_max_body_size 20M; }
Daha önce Nginx ile ilgilenmediyseniz, bu dosya sizi korkutabilir, bu yüzden burada küçük parçaları açıklayalım, çünkü aynı zamanda Magento'nun bazı iç işleyişine de ışık tutacaktır. İlk satırlar, Nginx'e varsayılan HTTP bağlantı noktasını kullandığımızı ve etki magento2.dev
olduğunu söyler:
listen 80; server_name magento2.dev;
Sonra bazı ortam değişkenleri belirledik. $MAGE_ROOT
—kod tabanımıza giden yolu tutar. Kaynağı yerleştirmeyi planladığınız her yerde, kullanıcı adınızla/klasör yolunuzla eşleşmesi için kök yolunu değiştirmeniz gerekeceğine dikkat edin:
set $MAGE_ROOT /Users/yourusername/www/magento2dev;
İkinci değişken — $MAGE_MODE
için çalışma zamanı modunu ayarlar. Modül geliştirirken geliştirici modunu kullanacağız. Bu, geliştirme sırasında statik dosyaları derlememiz veya dağıtmamız gerekmeyeceği için daha hızlı kodlamamızı sağlar. Diğer modlar üretim ve varsayılan modlardır. İkincisinin gerçek kullanımı henüz net değil.
set $MAGE_MODE developer;
Bu değişkenler ayarlandıktan sonra vhost kök yolunu tanımlarız. $MAGE_ROOT
değişkenini /pub
klasörüne ekleyerek mağazamızın yalnızca bir kısmını web'de kullanılabilir hale getirdiğimize dikkat edin.
root $MAGE_ROOT/pub;
Ardından indeks dosyamızı (istenen dosya olmadığında nginx yüklenecek) index.php olarak tanımlarız. Bu komut dosyası, $MAGE_ROOT/pub/index.php
, hem alışveriş sepetini hem de yönetici uygulamalarını ziyaret eden müşteriler için ana giriş noktasıdır. İstenen URL ne olursa olsun, index.php yüklenecek ve yönlendirici gönderme işlemi başlatılacaktır.
index index.php;
Ardından, bazı Nginx özelliklerini kapatıyoruz. İlk olarak, bir klasör talep ettiğinizde bir dosya listesi görüntüleyen, ancak bir dosya belirtmeyen ve indeks bulunmayan autoindex
kapatıyoruz. İkinci olarak, Nginx'in yanıta otomatik olarak Charset üstbilgileri eklemesine izin verecek olan charset
kapatıyoruz.
autoindex off; charset off;
Ardından, birkaç güvenlik başlığı tanımlarız:
add_header 'X-Content-Type-Options' 'nosniff'; add_header 'X-XSS-Protection' '1; mode=block';
Bu konum, $MAGE_ROOT/pub
/
klasörümüze yönlendirilir ve temel olarak, alınan herhangi bir isteği, istek argümanlarıyla birlikte ön denetleyicimiz index.php'ye yeniden yönlendirir:
location / { try_files $uri $uri/ /index.php?$args; }
Sonraki kısım biraz kafa karıştırıcı olabilir, ancak oldukça basit. Birkaç satır önce $MAGE_ROOT/pub
olarak tanımlamıştık. Kodun çoğu web'den görünmediğinden önerilen ve daha güvenli kurulum budur. Ancak web sunucusunu kurmanın tek yolu bu değildir. Aslında, çoğu paylaşılan web sunucusunun, web sunucunuzun web klasörünüzü göstermesini sağlayan bir varsayılan kurulumu vardır. Bu kullanıcılar için, Magento ekibi bu dosyayı, kök $MAGE_ROOT
olarak aşağıdaki snippet ile tanımlandığında bu durumlar için hazır hale getirdi:
location /pub { location ~ ^/pub/media/(downloadable|customer|import|theme_customization/.*\.xml) { deny all; } alias $MAGE_ROOT/pub; add_header X-Frame-Options "SAMEORIGIN"; }
Mümkün olduğunda, web sunucunuzun $MAGE_ROOT/pub
klasörünü göstermesinin en iyisi olduğunu unutmayın. Mağazanız bu şekilde daha güvenli olacaktır.
Sırada, $MAGE_ROOT/pub/static
var. Bu klasör başlangıçta boştur ve modüllerin ve temaların resim dosyaları, CSS, JS vb. statik dosyaları ile otomatik olarak doldurulur. Burada, temel olarak statik dosyalar için ve istenen dosya olmadığında bazı önbellek değerleri tanımlarız. varsa, onu $MAGE_ROOT/pub/static.php
yönlendirin. Bu komut dosyası, diğer şeylerin yanı sıra, isteği analiz edecek ve tanımlanan çalışma zamanı moduna bağlı olarak, ilgili modülden veya temadan belirtilen dosyayı kopyalayacak veya sembolik bağlantı oluşturacaktır. Bu şekilde, modülünüzün statik dosyaları modüllerimizin klasörünün içinde yer alacaktır, ancak doğrudan vhost ortak klasöründen sunulacaktır:
location /static/ { if ($MAGE_MODE = "production") { expires max; } location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ { add_header Cache-Control "public"; add_header X-Frame-Options "SAMEORIGIN"; expires +1y; if (!-f $request_filename) { rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last; } } location ~* \.(zip|gz|gzip|bz2|csv|xml)$ { add_header Cache-Control "no-store"; add_header X-Frame-Options "SAMEORIGIN"; expires off; if (!-f $request_filename) { rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last; } } if (!-f $request_filename) { rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last; } add_header X-Frame-Options "SAMEORIGIN"; }
Ardından, bazı kısıtlı klasörlere ve dosyalara web erişimini reddediyoruz:
location /media/customer/ { deny all; } location /media/downloadable/ { deny all; } location /media/import/ { deny all; } location ~ /media/theme_customization/.*\.xml$ { deny all; } location /errors/ { try_files $uri =404; } location ~ ^/errors/.*\.(xml|phtml)$ { deny all; } location ~ cron\.php { deny all; }
Ve son bit, php-fpm'yi yüklediğimiz ve kullanıcı ona her vurduğunda index.php'yi çalıştırmasını söylediğimiz yerdir:
location ~ (index|get|static|report|404|503)\.php$ { try_files $uri =404; fastcgi_pass 127.0.0.1:9000; fastcgi_param PHP_FLAG "session.auto_start=off \n suhosin.session.cryptua=off"; fastcgi_param PHP_VALUE "memory_limit=768M \n max_execution_time=60"; fastcgi_read_timeout 60s; fastcgi_connect_timeout 60s; fastcgi_param MAGE_MODE $MAGE_MODE; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; }
Bunun dışında, dosyayı kaydedin ve ardından aşağıdaki komutları yazarak etkinleştirin:
ln -s /usr/local/etc/nginx/sites-available/magento2dev.conf \ /usr/local/etc/nginx/sites-enabled/magento2dev.conf sudo brew services restart nginx
Magento 2 Nasıl Kurulur
Tamam, bu noktada makineniz Magento 2 gereksinimlerini karşılıyor, yalnızca canavarın kendisini kaçırıyor. Magento web sitesine gidin ve hala hesabınız yoksa bir hesap oluşturun. Bundan sonra, indirme sayfasına gidin ve en son sürümü (yazım sırasında 2.1.5) indirin:
.tar.bz2 formatını seçin ve indirin. Ardından, çıkartmaya devam edin ve Magento 2'nin çalışabilmesi için doğru klasör ve dosya izinlerini ayarlayın:
mkdir ~/www/magento2dev cd ~/www/magento2dev tar -xjf ~/Downloads/Magento-CE-2.1.5-2017-02-20-05-39-14.tar.bz2 find var vendor pub/static pub/media app/etc -type f -exec chmod u+w {} \; find var vendor pub/static pub/media app/etc -type d -exec chmod u+w {} \; chmod u+x bin/magento
Şimdi, veritabanı tablolarını kurmak ve gerekli konfigürasyon dosyalarını oluşturmak için terminalden şu komutu çalıştıracağız:
./bin/magento setup:install --base-url=http://magento2.dev/ \ --db-host=127.0.0.1 --db-name=magento2 --db-user=root \ --db-password=123 --admin-firstname=Magento --admin-lastname=User \ [email protected] --admin-user=admin \ --admin-password=admin123 --language=en_US --currency=USD \ --timezone=America/Chicago --use-rewrites=1 --backend-frontname=admin
Veritabanı adını ( db-name
), kullanıcıyı ( db-user
) ve şifreyi ( db-password
) MySQL kurulumu sırasında kullandığınızla eşleştirmeyi unutmayın, hepsi bu kadar! Bu komut, gerekli tabloları ve yapılandırma dosyalarını oluşturarak Magento 2'nin tüm modüllerini kuracaktır. Bitirdikten sonra tarayıcınızı açın ve http://magento2.dev/ adresine gidin. Varsayılan Luma temasıyla bir Magento 2 temiz kurulum görmelisiniz:
http://magento2.dev/admin adresine giderseniz, Yönetici uygulaması giriş sayfasını görmelisiniz:
Ardından oturum açmak için aşağıdaki kimlik bilgilerini kullanın:
Kullanıcı: admin Şifre: admin123
Sonunda kodumuzu yazmaya başlamaya hazırız!
İlk Magento 2 Modülümüzü Oluşturma
Modülümüzü tamamlamak için aşağıdaki dosyaları oluşturmamız gerekecek ve tüm süreç boyunca size rehberlik edeceğim. İhtiyacımız olacak:
- Magento'yu Blog modülümüzden haberdar etmek için birkaç standart kayıt dosyası
- Gönderi için veri sözleşmemizi tanımlamak için bir arayüz dosyası
- Kodumuz boyunca bir Gönderiyi temsil etmek için Gönderi verileri arayüzünü uygulayan bir Posta Modeli
- Posta Modelini veritabanına bağlamak için bir Posta Kaynak Modeli
- Kaynak Modeli yardımıyla veritabanından aynı anda birkaç gönderiyi almak için bir Gönderi Koleksiyonu
- Tablo şemamızı ve içeriğimizi ayarlamak için iki geçiş sınıfı
- İki İşlem: biri tüm gönderileri listelemek için, diğeri ise her gönderiyi ayrı ayrı göstermek için
- Bloklar, Görünümler ve Düzen dosyalarından ikişer adet: Liste eylemi için birer adet ve görünüm için birer adet
İlk olarak, kodumuzu nereye yerleştireceğimizi tanımlayabilmemiz için çekirdek kaynak kod klasör yapısına hızlıca bir göz atalım. Yükleme şeklimiz, tüm bağımlılıklarıyla birlikte, bestecinin vendor
klasöründe yaşayan tüm Magento 2 çekirdek koduna sahiptir.
Modülümüzün Kaydedilmesi
Kodumuzu ayrı bir klasörde tutacağız, app/code
. Her modülün adı Namespace_ModuleName
biçimindedir ve dosya sistemindeki konumu bu örnek için bu adı, app/code/Namespace/ModuleName
yansıtmalıdır. Bu kalıbı takip ederek modülümüze Toptal_Blog
adını vereceğiz ve dosyalarımızı app/code/Toptal/Blog
altına yerleştireceğiz. Devam edin ve bu klasör yapısını oluşturun.
Şimdi, modülümüzü Magento'ya kaydettirmek için birkaç ortak dosya oluşturmamız gerekiyor. İlk app/code/Toptal/Blog/composer.json
oluşturun:
{}
Bu dosya, her çalıştırdığınızda Composer tarafından yüklenecektir. Modülümüzle birlikte aslında Composer kullanmıyor olsak da, Composer'ı mutlu etmek için onu oluşturmalıyız.
Şimdi modülümüzü Magento'ya kaydedeceğiz. Devam edin ve app/code/Toptal/Blog/registration.php
oluşturun:
<?php \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, 'Toptal_Blog', __DIR__ );
Burada, ComponentRegistrar
sınıfının register
yöntemini çağırıyoruz ve iki parametre gönderiyoruz: kaydettiğimiz bileşenin türü olan 'module'
dizesi ve modülümüzün adı 'Toptal_Blog'
. Bu bilgiyle, Magento'nun otomatik yükleyicisi ad alanımızdan haberdar olacak ve sınıflarımızı ve XML dosyalarımızı nerede arayacağını bilecektir.
Burada dikkat edilmesi gereken ilginç bir şey, \Magento\Framework\Component\ComponentRegistrar::register
işlevine parametre olarak gönderilen bileşen tipine ( MODULE
) sahip olmamızdır. Yalnızca modülleri kaydettirmekle kalmaz, diğer türdeki bileşenleri de kaydedebiliriz. Örneğin, temalar, dış kitaplıklar ve dil paketleri de aynı yöntem kullanılarak kaydedilir.
Devam ederken, son kayıt dosyamızı app/code/Toptal/Blog/etc/module.xml
:
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd"> <module name="Toptal_Blog" setup_version="0.1.0"> <sequence> <module name="Magento_Directory" /> <module name="Magento_Config" /> </sequence> </module> </config>
Bu dosya, modülümüz hakkında çok önemli bilgiler içerir. Onlar:
- Modül adı tekrar mevcut ve modül adımızı Magento konfigürasyonuna maruz bırakıyor.
- Magento tarafından veritabanı taşıma komut dosyalarının ne zaman çalıştırılacağına karar vermek için kullanılacak olan Magento kurulum sürümü.
- Modülümüzün bağımlılıkları—Basit bir modül yazarken, yalnızca iki Magento çekirdek modülüne bağlıyız:
Magento_Directory
veMagento_Config
.
Şimdi Magento 2 tarafından tanınması gereken bir modülümüz var. Magento 2 CLI kullanarak kontrol edelim.
İlk olarak, Magento'nun önbelleğini devre dışı bırakmamız gerekiyor. Magento'nun önbellek mekanizmaları kendilerine adanmış bir makaleyi hak ediyor. Şimdilik, bir modül geliştirdiğimiz ve değişikliklerimizin her zaman önbelleği temizlemeye gerek kalmadan Magento tarafından anında tanınmasını istediğimiz için, onu devre dışı bırakacağız. Komut satırından şunu çalıştırın:
./bin/magento cache:disable
Öyleyse, modüllerin durumuna bakarak Magento'nun değişikliklerimizden haberdar olup olmadığını görelim. Basitçe aşağıdaki komutu çalıştırın:
./bin/magento module:status
Sonuncunun sonucu şuna benzer olmalıdır:
Modülümüz orada, ancak çıktının gösterdiği gibi hala devre dışı. Etkinleştirmek için şunu çalıştırın:
./bin/magento module:enable Toptal_Blog
Bunu yapmalıydı. Emin olmak için, module:status
tekrar arayabilir ve etkinleştirilmiş listede modülümüzün adını arayabilirsiniz:
Veri Depolamayı İşleme
Modülümüzü etkinleştirdiğimize göre, blog yazılarımızı içeren veritabanı tablosunu oluşturmamız gerekiyor. Oluşturmak istediğimiz tablonun şeması:
Alan | Tip | Boş | Anahtar | Varsayılan |
---|---|---|---|---|
post_id | int(10) imzasız | HAYIR | PRI | BOŞ |
Başlık | Metin | HAYIR | BOŞ | |
içerik | Metin | HAYIR | BOŞ | |
create_at | zaman damgası | HAYIR | GEÇERLİ ZAMAN DALGASI |
Bunu, şema geçişimizin kurulumunu yönetmekten sorumlu olan InstallSchema
sınıfını oluşturarak başarıyoruz. Dosya, app/code/Toptal/Blog/Setup/InstallSchema.php
bulunur ve aşağıdaki içeriğe sahiptir:
<?php namespace Toptal\Blog\Setup; use \Magento\Framework\Setup\InstallSchemaInterface; use \Magento\Framework\Setup\ModuleContextInterface; use \Magento\Framework\Setup\SchemaSetupInterface; use \Magento\Framework\DB\Ddl\Table; /** * Class InstallSchema * * @package Toptal\Blog\Setup */ class InstallSchema implements InstallSchemaInterface { /** * Install Blog Posts table * * @param SchemaSetupInterface $setup * @param ModuleContextInterface $context */ public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) { $setup->startSetup(); $tableName = $setup->getTable('toptal_blog_post'); if ($setup->getConnection()->isTableExists($tableName) != true) { $table = $setup->getConnection() ->newTable($tableName) ->addColumn( 'post_id', Table::TYPE_INTEGER, null, [ 'identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true ], 'ID' ) ->addColumn( 'title', Table::TYPE_TEXT, null, ['nullable' => false], 'Title' ) ->addColumn( 'content', Table::TYPE_TEXT, null, ['nullable' => false], 'Content' ) ->addColumn( 'created_at', Table::TYPE_TIMESTAMP, null, ['nullable' => false, 'default' => Table::TIMESTAMP_INIT], 'Created At' ) ->setComment('Toptal Blog - Posts'); $setup->getConnection()->createTable($table); } $setup->endSetup(); } }
install
yöntemini incelerseniz, basitçe tablomuzu oluşturduğunu ve sütunlarını tek tek eklediğini fark edeceksiniz.

Şema geçişinin ne zaman çalıştırılacağını belirlemek için Magento, her modül için tüm mevcut kurulum sürümlerini içeren bir tablo tutar ve bir modül sürümü değiştiğinde geçiş sınıfları başlatılır. Bu tablo setup_module
ve o tablonun içeriğine bakarsanız şu ana kadar modülümüze referans olmadığını göreceksiniz. Öyleyse, bunu değiştirelim. Bir terminalden aşağıdaki komutu çalıştırın:
./bin/magento setup:upgrade
Bu size, bizimkiler de dahil olmak üzere yürütülen tüm modüllerin ve geçiş komut dosyalarının bir listesini gösterecektir:
Şimdi, tercih ettiğiniz MySQL istemcinizden tablonun gerçekten oluşturulup oluşturulmadığını kontrol edebilirsiniz:
Ve setup_module
tablosunda, şimdi modülümüze, şemasına ve veri versiyonuna bir referans var:
Tamam, peki ya şema yükseltmeleri? Bunu nasıl yapacağınızı göstermek için bir yükseltme yoluyla bu tabloya bazı gönderiler ekleyelim. İlk olarak, etc/module.xml
setup_version
setup_version'u çarpın:
Şimdi veri (şema değil) geçişlerinden sorumlu olan app/code/Toptal/Blog/Setup/UpgradeData.php
dosyamızı oluşturuyoruz:
<?php namespace Toptal\Blog\Setup; use \Magento\Framework\Setup\UpgradeDataInterface; use \Magento\Framework\Setup\ModuleContextInterface; use \Magento\Framework\Setup\ModuleDataSetupInterface; /** * Class UpgradeData * * @package Toptal\Blog\Setup */ class UpgradeData implements UpgradeDataInterface { /** * Creates sample blog posts * * @param ModuleDataSetupInterface $setup * @param ModuleContextInterface $context * @return void */ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) { $setup->startSetup(); if ($context->getVersion() && version_compare($context->getVersion(), '0.1.1') < 0 ) { $tableName = $setup->getTable('toptal_blog_post'); $data = [ [ 'title' => 'Post 1 Title', 'content' => 'Content of the first post.', ], [ 'title' => 'Post 2 Title', 'content' => 'Content of the second post.', ], ]; $setup ->getConnection() ->insertMultiple($tableName, $data); } $setup->endSetup(); } }
Install sınıfımıza çok benzediğini görebilirsiniz. Tek fark, InstallSchemaInterface
yerine bir UpgradeDataInterface
uygulaması ve ana yöntemin upgrade
olarak adlandırılmasıdır. Bu yöntemle, mevcut modülün kurulu sürümünü kontrol eder ve sizinkinden küçük olduğunda, yapmanız gereken değişiklikleri başlatırsınız. Örneğimizde, version_compare
işlevini kullanarak aşağıdaki satırda mevcut sürümün 0.1.1'den küçük olup olmadığını kontrol ediyoruz:
if ($context->getVersion() && version_compare($context->getVersion(), '0.1.1') < 0 ) {
setup:upgrade
CLI komutu ilk kez çağrıldığında $context->getVersion()
çağrısı 0.1.0 değerini döndürür. Ardından örnek veriler veritabanına yüklenir ve sürümümüz 0.1.1'e yükseltilir. Bunu çalıştırmak için devam edin ve bir setup:upgrade
:
./bin/magento setup:upgrade
Ardından, gönderiler tablosundaki sonuçları kontrol edin:
Ve setup_module
tablosunda:
Dikkat edin, taşıma işlemini kullanarak tablomuza veri eklemiş olsak da, şemayı da değiştirmek mümkün olurdu. İşlem aynıdır; UpgradeDataInterface
yerine yalnızca UpgradeSchemaInterface
kullanırsınız.
Gönderiler için Model Tanımlama
Devam edersek, mimariye genel bakışımızı hatırlarsanız, bir sonraki yapı taşımız ResourceModel blog gönderisi olacaktır. Kaynak Modeli çok basittir ve birincil anahtarının ne olduğu ile birlikte Modelin "bağlanacağı" tabloyu basitçe belirtir. Aşağıdaki içeriklerle app/code/Toptal/Blog/Model/ResourceModel/Post.php
:
<?php namespace Toptal\Blog\Model\ResourceModel; use \Magento\Framework\Model\ResourceModel\Db\AbstractDb; class Post extends AbstractDb { /** * Post Abstract Resource Constructor * @return void */ protected function _construct() { $this->_init('toptal_blog_post', 'post_id'); } }
Her zamanki CRUD işlemlerinden farklı bir şeye ihtiyacınız olmadıkça, tüm ResourceModel işlemleri AbstractDb
üst sınıfı tarafından işlenir.
Ayrıca bir Koleksiyon olan başka bir ResourceModel'e ihtiyacımız olacak. Koleksiyon, ResourceModel'imizi kullanarak birden çok gönderi için veritabanını sorgulamaktan ve somutlaştırılan ve bilgi ile doldurulmuş bir dizi Modeli geri göndermekten sorumlu olacaktır. app/code/Toptal/Blog/Model/ResourceModel/Post/Collection.php
dosyasını aşağıdaki içerikle oluşturuyoruz:
<?php namespace Toptal\Blog\Model\ResourceModel\Post; use \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; class Collection extends AbstractCollection { /** * Remittance File Collection Constructor * @return void */ protected function _construct() { $this->_init('Toptal\Blog\Model\Post', 'Toptal\Blog\Model\ResourceModel\Post'); } }
Yapıcıda, kodumuz boyunca posta varlığını temsil edecek Model'den ve bilgileri veritabanına getirecek olan ResourceModel'den bahsettiğimize dikkat edin.
Bu katman için eksik olan parça Post Model'in kendisidir. Model, ihtiyaç duyabileceğiniz herhangi bir iş mantığı ile birlikte şemamızda tanımladığımız tüm nitelikleri taşımalıdır. Magento 2'nin modelini takip ederek, modelimizin genişleyeceği bir Veri Arayüzü oluşturmamız gerekiyor. Arabirimi app/code/Toptal/Blog/Api/Data/PostInterface.php
ve tablonun alan adlarını ve bunlara erişim yöntemlerini içermelidir:
<?php namespace Toptal\Blog\Api\Data; interface PostInterface { /**#@+ * Constants for keys of data array. Identical to the name of the getter in snake case */ const POST_; const TITLE = 'title'; const CONTENT = 'content'; const CREATED_AT = 'created_at'; /**#@-*/ /** * Get Title * * @return string|null */ public function getTitle(); /** * Get Content * * @return string|null */ public function getContent(); /** * Get Created At * * @return string|null */ public function getCreatedAt(); /** * Get ID * * @return int|null */ public function getId(); /** * Set Title * * @param string $title * @return $this */ public function setTitle($title); /** * Set Content * * @param string $content * @return $this */ public function setContent($content); /** * Set Crated At * * @param int $createdAt * @return $this */ public function setCreatedAt($createdAt); /** * Set ID * * @param int $id * @return $this */ public function setId($id); }
Şimdi, app/code/Toptal/Blog/Model/Post.php
uygulanmasına. Arayüzde tanımlanan metotları oluşturacağız. Ayrıca CACHE_TAG
sabiti aracılığıyla bir önbellek etiketi belirleyeceğiz ve yapıcıda, modelimiz için veritabanı erişiminden sorumlu olacak ResourceModel'i belirteceğiz.
<?php namespace Toptal\Blog\Model; use \Magento\Framework\Model\AbstractModel; use \Magento\Framework\DataObject\IdentityInterface; use \Toptal\Blog\Api\Data\PostInterface; /** * Class File * @package Toptal\Blog\Model * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Post extends AbstractModel implements PostInterface, IdentityInterface { /** * Cache tag */ const CACHE_TAG = 'toptal_blog_post'; /** * Post Initialization * @return void */ protected function _construct() { $this->_init('Toptal\Blog\Model\ResourceModel\Post'); } /** * Get Title * * @return string|null */ public function getTitle() { return $this->getData(self::TITLE); } /** * Get Content * * @return string|null */ public function getContent() { return $this->getData(self::CONTENT); } /** * Get Created At * * @return string|null */ public function getCreatedAt() { return $this->getData(self::CREATED_AT); } /** * Get ID * * @return int|null */ public function getId() { return $this->getData(self::POST_ID); } /** * Return identities * @return string[] */ public function getIdentities() { return [self::CACHE_TAG . '_' . $this->getId()]; } /** * Set Title * * @param string $title * @return $this */ public function setTitle($title) { return $this->setData(self::TITLE, $title); } /** * Set Content * * @param string $content * @return $this */ public function setContent($content) { return $this->setData(self::CONTENT, $content); } /** * Set Created At * * @param string $createdAt * @return $this */ public function setCreatedAt($createdAt) { return $this->setData(self::CREATED_AT, $createdAt); } /** * Set ID * * @param int $id * @return $this */ public function setId($id) { return $this->setData(self::POST_ID, $id); } }
Creating Views
Now we are moving one layer up, and will start the implementation of our ViewModel and Controller. To define a route in the front-end (shopping cart) application, we need to create the file app/code/Toptal/Blog/etc/frontend/routes.xml
with the following contents:
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd"> <router> <route frontName="blog"> <module name="Toptal_Blog"/> </route> </router> </config>
List of Posts at the Index Page
Here, we are basically telling Magento that our module, Toptal_Blog
, will be responsible for responding to routes under http://magento2.dev/blog (notice the frontName attribute of the route). Next up is the action, at app/code/Toptal/Blog/Controller/Index/Index.php
:
<?php namespace Toptal\Blog\Controller\Index; use \Magento\Framework\App\Action\Action; use \Magento\Framework\View\Result\PageFactory; use \Magento\Framework\View\Result\Page; use \Magento\Framework\App\Action\Context; use \Magento\Framework\Exception\LocalizedException; class Index extends Action { /** * @var PageFactory */ protected $resultPageFactory; /** * @param Context $context * @param PageFactory $resultPageFactory * * @codeCoverageIgnore * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( Context $context, PageFactory $resultPageFactory ) { parent::__construct( $context ); $this->resultPageFactory = $resultPageFactory; } /** * Prints the blog from informed order id * @return Page * @throws LocalizedException */ public function execute() { $resultPage = $this->resultPageFactory->create(); return $resultPage; } }
Our action is defining two methods. Let us take a closer look at them:
The constructor method simply sends the
$context
parameter to its parent method, and sets the$resultPageFactory
parameter to an attribute for later use. At this point it is useful to know the Dependency Injection design pattern, as that is what is happening here. In Magento 2's case we have automatic dependency injection. This means that whenever a class instantiation occurs, Magento will automatically try to instantiate all of the class constructor parameters (dependencies) and inject it for you as constructor parameters. It identifies which classes to instantiate for each parameter by inspecting the type hints, in this caseContext
andPageFactory
.The
execute
method is responsible for the action execution itself. In our case, we are simply telling Magento to render its layout by returning aMagento\Framework\View\Result\Page
object. This will trigger the layout rendering process, which we will create in a bit.
Now you should see a blank page at the url http://magento2.dev/blog/index/index. We still need to define the layout structure for that route, and its corresponding Block (our ViewModel) and the template file which will present the data to our user.
The layout structure for the front-end application is defined under view/frontend/layout
, and the file name must reflect our route. As our route is blog/index/index
, the layout file for that route will be app/code/Toptal/Blog/view/frontend/layout/blog_index_index.xml
:
<?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <body> <referenceContainer name="content"> <block class="Toptal\Blog\Block\Posts" name="posts.list" template="Toptal_Blog::post/list.phtml" /> </referenceContainer> </body> </page>
Here, we must define three very important structures in the Magento layout structure: Blocks, Containers, and Templates.
Blocks are the ViewModel part of our MVVM architecture, which was explained in earlier sections. They are the building blocks of our template structure.
Containers contain and output Blocks. They hold blocks together in nice hierarchical structures, and help in making things make sense when the layout for a page is being processed.
Templates are PHMTL (mixed HTML and PHP) files used by a special type of block in Magento. You can make calls to methods of a
$block
variable from within a template. The variable is always defined in the template context. You will be invoking your Block's methods by doing so, and thus allowing you to pull information from the ViewModel layer to the actual presentation.
With that extra information at hand, we can analyze the XML layout structure above. This layout structure is basically telling Magento that, when a request is made to the blog/index/index
route, a Block of the type Toptal\Blog\Block\Posts
is to be added to the content
container, and the template which will be used to render it is Toptal_blog::post/list.phtml
.
This leads us to the creation of our two remaining files. Our Block, located at app/code/Toptal/Blog/Block/Posts.php
:
<?php namespace Toptal\Blog\Block; use \Magento\Framework\View\Element\Template; use \Magento\Framework\View\Element\Template\Context; use \Toptal\Blog\Model\ResourceModel\Post\Collection as PostCollection; use \Toptal\Blog\Model\ResourceModel\Post\CollectionFactory as PostCollectionFactory; use \Toptal\Blog\Model\Post; class Posts extends Template { /** * CollectionFactory * @var null|CollectionFactory */ protected $_postCollectionFactory = null; /** * Constructor * * @param Context $context * @param PostCollectionFactory $postCollectionFactory * @param array $data */ public function __construct( Context $context, PostCollectionFactory $postCollectionFactory, array $data = [] ) { $this->_postCollectionFactory = $postCollectionFactory; parent::__construct($context, $data); } /** * @return Post[] */ public function getPosts() { /** @var PostCollection $postCollection */ $postCollection = $this->_postCollectionFactory->create(); $postCollection->addFieldToSelect('*')->load(); return $postCollection->getItems(); } /** * For a given post, returns its url * @param Post $post * @return string */ public function getPostUrl( Post $post ) { return '/blog/post/view/id/' . $post->getId(); } }
Bu sınıf oldukça basittir ve amacı yalnızca gösterilecek gönderileri yüklemek ve şablona bir getPostUrl
yöntemi sağlamaktır. Yine de dikkat edilmesi gereken bazı şeyler var.
Hatırlarsanız Toptal\Blog\Model\ResourceModel\Post\CollectionFactory
sınıfı tanımlamamıştık. Sadece Toptal\Blog\Model\ResourceModel\Post\Collection
tanımladık. Peki bu nasıl çalışıyor? Modülünüzde tanımladığınız her sınıf için Magento 2 sizin için otomatik olarak bir Fabrika oluşturacaktır. Fabrikaların iki yöntemi vardır: her çağrı için yeni bir örnek döndürecek olan create
ve çağrıldığında her zaman aynı örneği döndürecek olan get
- Singleton modelini uygulamak için kullanılır.
Bloğumuzun üçüncü parametresi $data
isteğe bağlı bir dizidir. Opsiyonel olduğu ve tip ipucu olmadığı için otomatik enjeksiyon sistemi ile enjeksiyon yapılmayacaktır. İsteğe bağlı oluşturucu parametrelerinin her zaman parametrelerde en sonda konumlandırılması gerektiğine dikkat etmek önemlidir. Örneğin, üst sınıfımız olan Magento\Framework\View\Element\Template
yapıcısı şu parametrelere sahiptir:
public function __construct( Template\Context $context, array $data = [] ) { ...
Template sınıfını genişlettikten sonra kurucu parametrelerine CollectionFactory
eklemek istediğimiz için, bunu isteğe bağlı parametreden önce yapmak zorunda kaldık, aksi takdirde enjeksiyon çalışmaz:
public function __construct( Context $context, PostCollectionFactory $postCollectionFactory, array $data = [] ) { ...
Daha sonra şablonumuz tarafından erişilecek olan getPosts
yönteminde, bize yeni bir PostCollection
ve gönderilerimizi veritabanından alıp yanıtımıza göndermemize izin verecek olan PostCollectionFactory
create
yöntemini çağırıyoruz.
Ve bu rotanın düzenini bitirmek için, işte bizim PHTML şablonumuz, app/code/Toptal/Blog/view/frontend/templates/post/list.phtml
:
<?php /** @var Toptal\Blog\Block\Posts $block */ ?> <h1>Toptal Posts</h1> <?php foreach($block->getPosts() as $post): ?> <?php /** @var Toptal\Blog\Model\Post */ ?> <h2><a href="<?php echo $block->getPostUrl($post);?>"><?php echo $post->getTitle(); ?></a></h2> <p><?php echo $post->getContent(); ?></p> <?php endforeach; ?>
Burada, ModelView'e ( $block->getPosts()
) erişen Görünüm katmanını görebildiğimize ve bu katmanın da veritabanından modellerimizi ( Toptal\Blog\Model\Post
) almak için bir ResourceModel (koleksiyon) kullandığına dikkat edin. Her şablonda, bloğunun yöntemlerine erişmek istediğinizde, tanımlanmış ve çağrılarınızı bekleyen bir $block
değişkeni olacaktır.
Artık rotamıza tekrar basarak gönderi listesini görebilmelisiniz.
Bireysel Gönderileri Görüntüleme
Şimdi, bir gönderi başlığına tıklarsanız, bir 404 alacaksınız, o halde bunu düzeltelim. Tüm yapımız yerinde olduğunda, bu oldukça basit hale gelir. Yalnızca aşağıdakileri oluşturmamız gerekecek:
-
blog/post/view
yoluna yönelik isteklerin işlenmesinden sorumlu yeni bir eylem - Gönderiyi oluşturmak için bir Blok
- Görünümün kendisinden sorumlu bir PHTML şablonu
- Bu son parçaları bir araya getiren blog/gönderim/görüntüleme rotası için bir düzen dosyası.
Yeni eylemimiz oldukça basit. Sadece istekten parametre id
alacak ve onu, tek bir istek döngüsü boyunca mevcut olan bilgiler için merkezi bir havuz olan Magento çekirdek kayıt defterine kaydedecektir. Bunu yaparak, kimliği daha sonra blok için kullanılabilir hale getireceğiz. Dosya, app/code/Toptal/Blog/Controller/Post/View.php
ve içeriği şunlardır:
<?php namespace Toptal\Blog\Controller\Post; use \Magento\Framework\App\Action\Action; use \Magento\Framework\View\Result\PageFactory; use \Magento\Framework\View\Result\Page; use \Magento\Framework\App\Action\Context; use \Magento\Framework\Exception\LocalizedException; use \Magento\Framework\Registry; class View extends Action { const REGISTRY_KEY_POST_; /** * Core registry * @var Registry */ protected $_coreRegistry; /** * @var PageFactory */ protected $_resultPageFactory; /** * @param Context $context * @param Registry $coreRegistry * @param PageFactory $resultPageFactory * * @codeCoverageIgnore * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( Context $context, Registry $coreRegistry, PageFactory $resultPageFactory ) { parent::__construct( $context ); $this->_coreRegistry = $coreRegistry; $this->_resultPageFactory = $resultPageFactory; } /** * Saves the blog id to the register and renders the page * @return Page * @throws LocalizedException */ public function execute() { $this->_coreRegistry->register(self::REGISTRY_KEY_POST_ID, (int) $this->_request->getParam('id')); $resultPage = $this->_resultPageFactory->create(); return $resultPage; } }
$coreRegistry
parametresini __construct
dosyamıza eklediğimize ve daha sonra kullanmak üzere bir öznitelik olarak kaydettiğimize dikkat edin. execute
yönteminde, istekten id
parametresini alır ve kaydederiz. Ayrıca kayıt anahtarı olarak self::REGISTRY_KEY_POST_ID
adlı bir sınıf sabiti kullanıyoruz ve aynı sabiti kayıt defterindeki kimliğe atıfta bulunmak için bloğumuzda kullanacağız.
Aşağıdaki içeriklerle app/code/Toptal/Blog/Block/View.php
adresinde bloğu oluşturalım:
<?php namespace Toptal\Blog\Block; use \Magento\Framework\Exception\LocalizedException; use \Magento\Framework\View\Element\Template; use \Magento\Framework\View\Element\Template\Context; use \Magento\Framework\Registry; use \Toptal\Blog\Model\Post; use \Toptal\Blog\Model\PostFactory; use \Toptal\Blog\Controller\Post\View as ViewAction; class View extends Template { /** * Core registry * @var Registry */ protected $_coreRegistry; /** * Post * @var null|Post */ protected $_post = null; /** * PostFactory * @var null|PostFactory */ protected $_postFactory = null; /** * Constructor * @param Context $context * @param Registry $coreRegistry * @param PostFactory $postCollectionFactory * @param array $data */ public function __construct( Context $context, Registry $coreRegistry, PostFactory $postFactory, array $data = [] ) { $this->_postFactory = $postFactory; $this->_coreRegistry = $coreRegistry; parent::__construct($context, $data); } /** * Lazy loads the requested post * @return Post * @throws LocalizedException */ public function getPost() { if ($this->_post === null) { /** @var Post $post */ $post = $this->_postFactory->create(); $post->load($this->_getPostId()); if (!$post->getId()) { throw new LocalizedException(__('Post not found')); } $this->_post = $post; } return $this->_post; } /** * Retrieves the post id from the registry * @return int */ protected function _getPostId() { return (int) $this->_coreRegistry->registry( ViewAction::REGISTRY_KEY_POST_ID ); } }
Görünüm bloğunda, yalnızca posta kimliğini çekirdek kayıt defterinden alacak olan korumalı bir _getPostId
yöntemi tanımlarız. Genel getPost
yöntemi, gönderiyi tembel olarak yükler ve gönderi yoksa bir istisna atar. Buraya bir istisna atmak, Magento'nun varsayılan hata ekranını göstermesine neden olacaktır, bu böyle bir durumda en iyi çözüm olmayabilir, ancak basitlik adına bu şekilde tutacağız.
PHTML şablonumuza geçelim. Aşağıdaki içeriklerle app/code/Toptal/Blog/view/frontend/templates/post/view.phtml
:
<?php /** @var Toptal\Blog\Block\View $block */ ?> <h1><?php echo $block->getPost()->getTitle(); ?></h1> <p><?php echo $block->getPost()->getContent(); ?></p>
Güzel ve basit, daha önce oluşturduğumuz Görünüm bloğu getPost
yöntemine erişmeniz yeterli.
Ve hepsini bir araya getirmek için, app/code/Toptal/Blog/view/frontend/layout/blog_post_view.xml
yeni rotamız için aşağıdaki içerikle bir layout dosyası oluşturuyoruz:
<?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <body> <referenceContainer name="content"> <block class="Toptal\Blog\Block\View" name="post.view" template="Toptal_Blog::post/view.phtml" /> </referenceContainer> </body> </page>
Bu, daha önce yaptığımızın aynısını yapıyor. İlgili şablon olarak Toptal_Blog::post/view.phtml
ile content
kabına Toptal\Blog\Block\View
ekler.
Eylem halinde görmek için, bir gönderiyi başarıyla yüklemek için tarayıcınızı http://magento2.dev/blog/post/view/id/1 adresine yönlendirmeniz yeterlidir. Aşağıdaki gibi bir ekran görmelisiniz:
Ve görebileceğiniz gibi, ilk yapımızı oluşturduktan sonra, platforma özellikler eklemek gerçekten çok basit ve ilk kodlarımızın çoğu bu süreçte yeniden kullanılıyor.
Modülü hızlı bir şekilde test etmek isterseniz, çalışmamızın toplam sonucu burada.
Buradan Nereye Gidilir
Beni buraya kadar takip ettiyseniz, tebrikler! Magento 2 geliştiricisi olmaya oldukça yakın olduğunuzdan eminim. Oldukça gelişmiş bir Magento 2 özel modülü geliştirdik ve özellikleri basit olsa da çok fazla yol kat edildi.
Basitlik adına bazı şeyler bu makaleden çıkarıldı. Birkaç isim:
- Blog içeriğimizi yönetmek için yönetici düzenleme formları ve ızgaralar
- Blog kategorileri, etiketler ve yorumlar
- Depolar ve kurabileceğimiz birkaç hizmet sözleşmesi
- Magento 2 uzantıları olarak paketleme modülleri
Her durumda, bilginizi daha da derinleştirebileceğiniz bazı yararlı bağlantılar:
- Magento 2'deki Alan Storm Blogu - Alan Storm, Magento öğrenme söz konusu olduğunda muhtemelen en didaktik içeriğe sahiptir.
- Alan Kent'in Blogu
- Magento belgeleri: Magento 2 Geliştirme Belgeleri
Magento 2'de bir modülün nasıl oluşturulacağının tüm ilgili yönlerine kapsamlı bir giriş ve ihtiyaç duymanız halinde birkaç ek kaynak sağladım. Şimdi kodlamayı öğrenmek size kalmış ya da tartmak istiyorsanız yorumlara gidin.