Tutorial Magento 2: Cara Membuat Modul Lengkap
Diterbitkan: 2022-03-11Magento saat ini merupakan platform eCommerce open-source terbesar di dunia. Karena basis kode yang kaya fitur dan dapat diperluas, pedagang dengan operasi besar dan kecil di seluruh dunia telah menggunakannya untuk berbagai proyek.
Magento 1 telah ada selama delapan tahun, dan penggantinya, Magento 2, dirilis pada akhir tahun 2015, memperbaiki titik lemah dari versi sebelumnya seperti:
- Peningkatan kinerja
- Rangkaian pengujian otomatis resmi
- UI back-end yang lebih baik
- Basis kode front-end baru yang lebih modern
- Cara yang lebih modular untuk mengembangkan modul, dengan file yang terkandung di dalam kode Magento alih-alih tersebar di semua tempat
- Mengurangi jumlah konflik antar modul yang mencoba menyesuaikan fungsionalitas yang sama
Sedikit lebih dari satu tahun ke depan, dan peningkatannya terlihat, meskipun tidak semua masalah yang disebutkan telah diselesaikan secara total. Sekarang benar-benar aman untuk mengatakan bahwa Magento 2 adalah perangkat lunak yang jauh lebih kuat daripada pendahulunya. Beberapa peningkatan yang ada di Magento 2 adalah:
- Tes unit dan integrasi, termasuk cara resmi dan terdokumentasi untuk membuatnya untuk modul khusus
- Modul yang benar-benar termodulasi, memiliki semua file mereka ditempatkan di bawah satu direktori tunggal
- Sistem templating yang lebih kaya, memungkinkan pengembang tema untuk membuat hierarki templat tingkat-n
- Serangkaian pola desain yang berguna diadopsi di seluruh kode, meningkatkan kualitas kode dan mengurangi kemungkinan kesalahan yang dibuat oleh modul—Ini termasuk injeksi ketergantungan otomatis, kontrak layanan, repositori, dan pabrik, untuk beberapa nama.
- Integrasi asli ke Varnish sebagai sistem caching halaman penuh, serta Redis untuk penanganan sesi dan cache
- dukungan PHP7
Kurva pembelajaran untuk Magento 2, dengan semua perubahan ini, menjadi lebih curam. Dalam panduan ini, saya bermaksud menunjukkan kepada Anda bagaimana mengembangkan modul Magento 2 pertama Anda, dan mengarahkan Anda ke arah yang benar untuk melanjutkan studi Anda. Mari kita lakukan!
Prasyarat Tutorial Magento 2
Penting bagi Anda untuk memiliki pemahaman yang baik tentang teknologi/konsep berikut untuk mengikuti sisa artikel ini:
- Pemrograman Berorientasi Objek (OOP)
- PHP
- Ruang nama
- MySQL
- Penggunaan bash dasar
Dari semua hal di atas, OOP mungkin yang paling penting. Magento awalnya dibuat oleh tim pengembang Java yang berpengalaman, dan warisan mereka pasti dapat dilihat di seluruh basis kode. Jika Anda tidak terlalu yakin dengan keterampilan OOP Anda, mungkin ada baiknya untuk meninjaunya sebelum memulai pekerjaan Anda dengan platform.
Ikhtisar Arsitektur Magento 2
Arsitektur Magento dirancang dengan tujuan membuat kode sumber termodulasi dan dapat diperluas mungkin. Tujuan akhir dari pendekatan itu adalah untuk memungkinkannya dengan mudah diadaptasi dan disesuaikan sesuai dengan kebutuhan masing-masing proyek.
Menyesuaikan biasanya berarti mengubah perilaku kode platform. Di sebagian besar sistem, ini berarti mengubah kode "inti". Di Magento, jika Anda mengikuti praktik terbaik, ini adalah sesuatu yang dapat Anda hindari sebagian besar waktu, sehingga memungkinkan toko untuk tetap up to date dengan patch keamanan terbaru dan rilis fitur dengan cara yang dapat diandalkan.
Magento 2 adalah sistem Model View ViewModel (MVVM). Meskipun terkait erat dengan saudaranya Model View Controller (MVC), arsitektur MVVM memberikan pemisahan yang lebih kuat antara Model dan lapisan View. Di bawah ini adalah penjelasan dari masing-masing lapisan sistem MVVM:
- Model memegang logika bisnis aplikasi, dan bergantung pada kelas terkait — ResourceModel — untuk akses database. Model mengandalkan kontrak layanan untuk mengekspos fungsionalitasnya ke lapisan aplikasi lainnya.
- Tampilan adalah struktur dan tata letak dari apa yang dilihat pengguna di layar - HTML sebenarnya. Ini dicapai dalam file PHTML yang didistribusikan dengan modul. File PHTML dikaitkan ke setiap ViewModel dalam file Layout XML , yang akan disebut sebagai pengikat dalam dialek MVVM. File tata letak mungkin juga menetapkan file JavaScript untuk digunakan di halaman akhir.
- ViewModel berinteraksi dengan layer Model, hanya memperlihatkan informasi yang diperlukan ke layer View. Di Magento 2, ini ditangani oleh kelas Blok modul. Perhatikan bahwa ini biasanya merupakan bagian dari peran Pengendali sistem MVC. Pada MVVM, pengontrol hanya bertanggung jawab untuk menangani aliran pengguna, artinya ia menerima permintaan dan memberi tahu sistem untuk membuat tampilan atau mengarahkan pengguna ke rute lain.
Modul Magento 2 terdiri dari beberapa, jika tidak semua, elemen arsitektur yang dijelaskan di atas. Arsitektur keseluruhan dijelaskan di bawah ini (sumber):
Modul Magento 2 pada gilirannya dapat menentukan dependensi eksternal dengan menggunakan Composer, manajer dependensi PHP. Pada diagram di atas, Anda melihat bahwa modul inti Magento 2 bergantung pada Zend Framework, Symfony, serta perpustakaan pihak ketiga lainnya.
Di bawah ini adalah struktur Magento/Cms, modul inti Magento 2 yang bertanggung jawab untuk menangani pembuatan halaman dan blok statis.
Setiap folder menyimpan satu bagian dari arsitektur, sebagai berikut:
- Api: Kontrak layanan, mendefinisikan antarmuka layanan dan antarmuka data
- Blok: ViewModels arsitektur MVVM kami
- Controller: Controller, bertanggung jawab untuk menangani aliran pengguna saat berinteraksi dengan sistem
- dll: File XML Konfigurasi—Modul mendefinisikan dirinya sendiri dan bagian-bagiannya (rute, model, blok, pengamat, dan tugas cron) dalam folder ini. File etc juga dapat digunakan oleh modul non-inti untuk mengesampingkan fungsionalitas modul inti.
- Helper: Kelas pembantu yang menyimpan kode yang digunakan di lebih dari satu lapisan aplikasi. Misalnya, dalam modul Cms, kelas pembantu bertanggung jawab untuk menyiapkan HTML untuk presentasi ke browser.
- i18n: Menyimpan file CSV internasionalisasi, digunakan untuk terjemahan
- Model: Untuk Model dan ResourceModels
- Pengamat: Memegang Pengamat, atau Model yang "mengamati" peristiwa sistem. Biasanya, ketika peristiwa seperti itu dipicu, pengamat memberi contoh Model untuk menangani logika bisnis yang diperlukan untuk peristiwa semacam itu.
- Penyiapan: Kelas migrasi, bertanggung jawab atas pembuatan skema dan data
- Tes: Tes unit
- Ui: Elemen UI seperti kisi dan formulir yang digunakan dalam aplikasi admin
- tampilan: File Layout (XML) dan file template (PHTML) untuk aplikasi front-end dan admin
Menarik juga untuk diperhatikan bahwa, dalam praktiknya, semua cara kerja bagian dalam Magento 2 hidup di dalam sebuah modul. Pada gambar di atas, Anda dapat melihat, misalnya, Magento_Checkout
, yang bertanggung jawab untuk proses checkout, dan Magento_Catalog
, yang bertanggung jawab untuk menangani produk dan kategori. Pada dasarnya, ini memberitahu kita bahwa mempelajari cara bekerja dengan modul adalah bagian terpenting untuk menjadi pengembang Magento 2.
Baiklah, setelah pengenalan yang relatif singkat tentang arsitektur sistem dan struktur modul ini, mari kita lakukan sesuatu yang lebih konkret, ya? Selanjutnya, kita akan melalui tutorial Weblog tradisional untuk membuat Anda nyaman dengan Magento 2 dan berada di jalur yang benar untuk menjadi Pengembang Magento 2. Sebelum itu, kita perlu menyiapkan lingkungan pengembangan. Mari kita lakukan!
Menyiapkan Lingkungan Pengembangan Modul Magento 2
Pada saat penulisan ini, kami dapat menggunakan DevBox Magento 2 resmi, yang merupakan wadah Docker Magento 2. Docker di macOS adalah sesuatu yang saya masih anggap tidak dapat digunakan, setidaknya dengan sistem yang sangat bergantung pada I/O disk cepat seperti Magento 2. Jadi, kita akan melakukannya dengan cara tradisional: Instal semua paket secara native di mesin kita sendiri.
Menyiapkan Server
Menginstal semuanya pasti sedikit lebih membosankan, tetapi hasil akhirnya adalah lingkungan pengembangan Magento yang sangat cepat. Percayalah, Anda akan menghemat jam kerja dengan tidak bergantung pada Docker untuk pengembangan Magento 2 Anda.
Tutorial ini mengasumsikan lingkungan di macOS dengan Brew terinstal di dalamnya. Jika Anda tidak demikian, dasar-dasarnya akan tetap sama, hanya mengubah cara Anda menginstal paket. Mari kita mulai dengan menginstal semua paket:
brew install mysql nginxb php70 php70-imagick php70-intl php70-mcrypt
Kemudian mulai layanan:
brew services start mysql brew services start php70 sudo brew services start nginx
Ok, sekarang kita akan mengarahkan domain ke alamat loopback kita. Buka file host di editor apa pun, tetapi pastikan Anda memiliki izin pengguna super. Melakukan itu dengan Vim adalah:
sudo vim /etc/hosts
Kemudian tambahkan baris berikut:
127.0.0.1 magento2.dev
Sekarang kita akan membuat vhost di Nginx:
vim /usr/local/etc/nginx/sites-available/magento2dev.conf
Tambahkan konten berikut:
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; }
Jika Anda belum pernah berurusan dengan Nginx sebelumnya, file ini mungkin membuat Anda takut, jadi izinkan kami menjelaskan sedikit di sini, karena ini juga akan menjelaskan beberapa cara kerja Magento. Baris pertama hanya memberi tahu Nginx bahwa kami menggunakan port HTTP default, dan domain kami adalah magento2.dev
:
listen 80; server_name magento2.dev;
Kemudian kami mengatur beberapa variabel lingkungan. Yang pertama— $MAGE_ROOT
—menampung jalur ke basis kode kita. Perhatikan bahwa Anda perlu mengubah jalur root agar sesuai dengan nama pengguna/jalur folder Anda, di mana pun Anda berencana menempatkan sumbernya:
set $MAGE_ROOT /Users/yourusername/www/magento2dev;
Variabel $MAGE_MODE
—menetapkan mode runtime untuk toko kita. Saat kami mengembangkan modul, kami akan menggunakan mode pengembang. Ini memungkinkan kita untuk membuat kode lebih cepat, karena kita tidak perlu mengkompilasi atau menyebarkan file statis saat mengembangkan. Mode lainnya adalah produksi dan default. Penggunaan sebenarnya untuk yang terakhir ini belum jelas.
set $MAGE_MODE developer;
Setelah variabel ini disetel, kami mendefinisikan jalur root vhost. Perhatikan bahwa kita menambahkan variabel $MAGE_ROOT
dengan folder /pub
, membuat hanya sebagian dari toko kita yang tersedia untuk web.
root $MAGE_ROOT/pub;
Kami kemudian mendefinisikan file indeks kami — file nginx akan dimuat ketika file yang diminta tidak ada — sebagai index.php. Skrip ini, $MAGE_ROOT/pub/index.php
, adalah titik masuk utama bagi pelanggan yang mengunjungi keranjang belanja dan aplikasi admin. Terlepas dari URL yang diminta, index.php akan dimuat dan proses pengiriman router dimulai.
index index.php;
Selanjutnya kita matikan beberapa fitur Nginx. Pertama, kami mematikan autoindex
, yang akan menampilkan daftar file saat Anda meminta folder, tetapi tidak menentukan file, dan tidak ada indeks. Kedua, kami mematikan charset
, yang memungkinkan Nginx menambahkan header Charset secara otomatis ke respons.
autoindex off; charset off;
Selanjutnya, kami mendefinisikan beberapa header keamanan:
add_header 'X-Content-Type-Options' 'nosniff'; add_header 'X-XSS-Protection' '1; mode=block';
Lokasi ini, /
, diarahkan ke folder root kita $MAGE_ROOT/pub
, dan pada dasarnya mengarahkan semua permintaan yang diterima ke pengontrol depan kita index.php, bersama dengan argumen permintaan:
location / { try_files $uri $uri/ /index.php?$args; }
Bagian selanjutnya mungkin agak membingungkan, tetapi cukup sederhana. Beberapa baris yang lalu, kami mendefinisikan root kami sebagai $MAGE_ROOT/pub
. Itu adalah pengaturan yang disarankan dan lebih aman, karena sebagian besar kode tidak terlihat dari web. Tapi itu bukan satu-satunya cara untuk mengatur server web. Sebenarnya, sebagian besar server web bersama memiliki satu pengaturan default, yaitu membuat server web Anda menunjuk ke folder web Anda. Untuk pengguna tersebut, tim Magento telah menyiapkan file ini untuk kasus tersebut, ketika root didefinisikan sebagai $MAGE_ROOT
dengan cuplikan berikut:
location /pub { location ~ ^/pub/media/(downloadable|customer|import|theme_customization/.*\.xml) { deny all; } alias $MAGE_ROOT/pub; add_header X-Frame-Options "SAMEORIGIN"; }
Ingatlah bahwa, bila memungkinkan, yang terbaik adalah jika server web Anda mengarah ke folder $MAGE_ROOT/pub
. Toko Anda akan lebih aman dengan cara ini.
Selanjutnya, kita memiliki lokasi static $MAGE_ROOT/pub/static
. Folder ini awalnya kosong dan terisi secara otomatis dengan file statis modul dan tema, seperti file gambar, CSS, JS, dll. Di sini, pada dasarnya kami mendefinisikan beberapa nilai cache untuk file statis dan, ketika file yang diminta tidak ada, arahkan ke $MAGE_ROOT/pub/static.php
. Skrip tersebut akan, antara lain, menganalisis permintaan dan menyalin atau menghubungkan file yang ditentukan dari modul atau tema koresponden, tergantung pada mode runtime yang ditentukan. Dengan cara ini, file statis modul Anda akan berada di dalam folder modul kami, tetapi akan disajikan langsung dari folder publik vhost:
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"; }
Selanjutnya kami menolak akses web ke beberapa folder dan file terbatas:
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; }
Dan bit terakhir adalah tempat kita memuat php-fpm dan memerintahkannya untuk mengeksekusi index.php setiap kali pengguna menekannya:
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; }
Dengan itu, simpan file, lalu aktifkan dengan mengetikkan perintah berikut:
ln -s /usr/local/etc/nginx/sites-available/magento2dev.conf \ /usr/local/etc/nginx/sites-enabled/magento2dev.conf sudo brew services restart nginx
Cara Menginstal Magento 2
Oke, pada titik ini mesin Anda memenuhi persyaratan Magento 2, hanya kehilangan binatang itu sendiri. Buka situs web Magento dan buat akun jika Anda masih belum memilikinya. Setelah itu, buka halaman unduh dan unduh versi terbaru (2.1.5, pada saat penulisan):
Pilih format .tar.bz2 dan unduh. Kemudian lanjutkan untuk mengekstraknya dan mengatur izin folder dan file yang benar agar Magento 2 dapat berfungsi:
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
Sekarang, untuk menginstal tabel database dan membuat file konfigurasi yang diperlukan, kita akan menjalankan perintah ini dari terminal:
./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
Ingatlah untuk mengubah nama database ( db-name
), pengguna ( db-user
) dan kata sandi ( db-password
) agar sesuai dengan yang Anda gunakan selama instalasi MySQL, dan hanya itu! Perintah ini akan menginstal semua modul Magento 2, membuat tabel dan file konfigurasi yang diperlukan. Setelah selesai, buka browser Anda dan buka http://magento2.dev/. Anda akan melihat instalasi bersih Magento 2 dengan tema Luma default:
Jika Anda menuju ke http://magento2.dev/admin, Anda akan melihat halaman login aplikasi Admin:
Kemudian gunakan kredensial di bawah ini untuk masuk:
Pengguna: admin Kata sandi: admin123
Kami akhirnya siap untuk mulai menulis kode kami!
Membuat Modul Magento 2 Pertama Kami
Untuk menyelesaikan modul kita, kita harus membuat file-file berikut, dan saya akan memandu Anda melalui seluruh proses. Kita akan butuh:
- Beberapa file pendaftaran boilerplate, untuk membuat Magento mengetahui modul Blog kami
- Satu file antarmuka, untuk menentukan kontrak data kami untuk Post
- Model Post, untuk mewakili Post di seluruh kode kita, mengimplementasikan antarmuka data Post
- Model Sumber Daya Posting, untuk menautkan Model Posting ke database
- Koleksi Post, untuk mengambil beberapa posting sekaligus dari database dengan bantuan Resource Model
- Dua kelas migrasi, untuk menyiapkan skema dan konten tabel kami
- Dua Tindakan: satu untuk mendaftar semua posting dan satu lagi untuk menampilkan setiap posting satu per satu
- Masing-masing dua file Blok, Tampilan, dan Tata Letak: Satu dari masing-masing untuk tindakan daftar, dan satu dari masing-masing untuk tampilan
Pertama, mari kita lihat sekilas struktur folder kode sumber inti, sehingga kita dapat menentukan di mana menempatkan kode kita. Cara kami menginstal memiliki semua kode inti Magento 2, bersama dengan semua dependensinya, tinggal di dalam folder vendor
komposer.
Mendaftarkan Modul Kami
Kami akan menyimpan kode kami di folder terpisah, app/code
. Setiap nama modul dalam bentuk Namespace_ModuleName
, dan lokasinya di sistem file harus mencerminkan nama itu, app/code/Namespace/ModuleName
untuk contoh ini. Mengikuti pola itu, kami akan memberi nama modul kami Toptal_Blog
dan menempatkan file kami di bawah app/code/Toptal/Blog
. Silakan dan buat struktur folder itu.
Sekarang, kita perlu membuat beberapa file boilerplate agar modul kita terdaftar di Magento. Pertama, buat app/code/Toptal/Blog/composer.json
:
{}
File ini akan dimuat oleh Composer setiap kali Anda menjalankannya. Meskipun kita tidak benar-benar menggunakan Composer dengan modul kita, kita harus membuatnya untuk membuat Composer senang.
Sekarang kita akan mendaftarkan modul kita dengan Magento. Silakan dan buat app/code/Toptal/Blog/registration.php
:
<?php \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, 'Toptal_Blog', __DIR__ );
Di sini, kita memanggil metode register
dari kelas ComponentRegistrar
, mengirimkan dua parameter: string 'module'
, yang merupakan jenis komponen yang kita daftarkan, dan nama modul kita, 'Toptal_Blog'
. Dengan informasi itu, pemuat otomatis Magento akan mengetahui ruang nama kita dan akan tahu di mana mencari kelas dan file XML kita.
Satu hal yang menarik untuk diperhatikan di sini adalah bahwa kita memiliki jenis komponen ( MODULE
) yang dikirim sebagai parameter ke fungsi \Magento\Framework\Component\ComponentRegistrar::register
. Kita tidak hanya dapat mendaftarkan modul, kita dapat mendaftarkan jenis komponen lainnya. Misalnya, tema, pustaka eksternal, dan paket bahasa juga didaftarkan menggunakan metode yang sama ini.
Selanjutnya, mari kita buat file registrasi terakhir kita, 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>
File ini menyimpan beberapa informasi yang sangat penting tentang modul kami. Mereka:
- Nama modul hadir lagi, memperlihatkan nama modul kita ke konfigurasi Magento.
- Versi penyiapan Magento, yang akan digunakan oleh Magento untuk memutuskan kapan harus menjalankan skrip migrasi database.
- Ketergantungan modul kita—Saat menulis modul sederhana, kita hanya bergantung pada dua modul inti Magento:
Magento_Directory
danMagento_Config
.
Sekarang, kita memiliki sebuah modul yang seharusnya dapat dikenali oleh Magento 2. Mari kita periksa dengan menggunakan Magento 2 CLI.
Pertama, kita perlu menonaktifkan cache Magento. Mekanisme cache Magento layak mendapatkan artikel yang didedikasikan untuk diri mereka sendiri. Untuk saat ini, karena kami sedang mengembangkan modul dan ingin perubahan kami dikenali oleh Magento secara instan tanpa perlu menghapus cache setiap saat, kami hanya akan menonaktifkannya. Dari baris perintah, jalankan:
./bin/magento cache:disable
Kemudian mari kita lihat apakah Magento sudah mengetahui modifikasi kita dengan melihat status modul. Cukup jalankan perintah berikut:
./bin/magento module:status
Hasil dari yang terakhir harus mirip dengan:
Modul kami ada di sana, tetapi seperti yang ditunjukkan oleh output, modul itu masih dinonaktifkan. Untuk mengaktifkannya, jalankan:
./bin/magento module:enable Toptal_Blog
Itu seharusnya dilakukan. Untuk memastikannya, Anda dapat memanggil module:status
lagi dan mencari nama modul kami di daftar yang diaktifkan:
Menangani Penyimpanan Data
Sekarang kita telah mengaktifkan modul kita, kita perlu membuat tabel database yang menampung posting blog kita. Ini adalah skema untuk tabel yang ingin kita buat:
Bidang | Jenis | Batal | Kunci | Bawaan |
---|---|---|---|---|
post_id | int(10) tidak ditandatangani | TIDAK | PR | BATAL |
judul | teks | TIDAK | BATAL | |
isi | teks | TIDAK | BATAL | |
dibuat di | stempel waktu | TIDAK | CURRENT_TIMESTAMP |
Kami mencapai ini dengan membuat kelas InstallSchema
, yang bertanggung jawab untuk mengelola instalasi migrasi skema kami. File terletak di app/code/Toptal/Blog/Setup/InstallSchema.php
dan memiliki konten berikut:
<?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(); } }
Jika Anda menganalisis metode install
, Anda akan melihatnya hanya membuat tabel kami dan menambahkan kolomnya satu per satu.

Untuk menentukan kapan harus menjalankan migrasi skema, Magento menyimpan tabel dengan semua versi penyiapan saat ini untuk setiap modul, dan setiap kali versi modul berubah, kelas migrasinya diinisialisasi. Tabel ini adalah setup_module
, dan jika Anda melihat isi tabel itu, Anda akan melihat bahwa sejauh ini tidak ada referensi ke modul kita. Jadi, mari kita ubah itu. Dari terminal, jalankan perintah berikut:
./bin/magento setup:upgrade
Itu akan menunjukkan kepada Anda daftar semua modul dan skrip migrasinya yang dieksekusi, termasuk milik kami:
Sekarang, dari klien preferensi MySQL Anda, Anda dapat memeriksa apakah tabel benar-benar telah dibuat:
Dan di tabel setup_module
, sekarang ada referensi ke modul kita, skemanya, dan versi datanya:
Oke, dan bagaimana dengan peningkatan skema? Mari tambahkan beberapa posting ke tabel itu melalui peningkatan untuk menunjukkan cara melakukannya. Pertama, setup_version
pada file etc/module.xml
kami:
Sekarang kita membuat file app/code/Toptal/Blog/Setup/UpgradeData.php
, yang bertanggung jawab atas migrasi data (bukan skema):
<?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(); } }
Anda dapat melihat bahwa ini sangat mirip dengan kelas Instal kami. Satu-satunya perbedaan adalah ia mengimplementasikan UpgradeDataInterface
alih-alih InstallSchemaInterface
, dan metode utamanya disebut upgrade
. Dengan metode ini, Anda memeriksa versi terinstal modul saat ini dan, jika lebih kecil dari versi Anda, jalankan perubahan yang perlu Anda selesaikan. Dalam contoh kami, kami memeriksa apakah versi saat ini lebih kecil dari 0.1.1 di baris berikut menggunakan fungsi version_compare
:
if ($context->getVersion() && version_compare($context->getVersion(), '0.1.1') < 0 ) {
Panggilan $context->getVersion()
akan mengembalikan 0.1.0 saat perintah setup:upgrade
CLI dipanggil untuk pertama kalinya. Kemudian data sampel dimuat ke database, dan versi kami diubah menjadi 0.1.1. Untuk menjalankan ini, lanjutkan dan jalankan setup:upgrade
:
./bin/magento setup:upgrade
Dan kemudian periksa hasilnya di tabel posting:
Dan di tabel setup_module
:
Perhatikan bahwa, meskipun kami menambahkan data ke tabel kami menggunakan proses migrasi, skema juga dapat diubah. Prosesnya sama; Anda hanya akan menggunakan UpgradeSchemaInterface
alih-alih UpgradeDataInterface
.
Mendefinisikan Model untuk Posting
Selanjutnya, jika Anda ingat ikhtisar arsitektur kami, blok bangunan kami berikutnya adalah posting blog ResourceModel. Model Sumber Daya sangat sederhana, dan hanya menyatakan tabel yang akan "dihubungkan" Model, bersama dengan apa kunci utamanya. Kita akan membuat ResourceModel kita di app/code/Toptal/Blog/Model/ResourceModel/Post.php
dengan isi sebagai berikut:
<?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'); } }
Semua operasi ResourceModel, kecuali jika Anda memerlukan sesuatu yang berbeda dari operasi CRUD biasa, ditangani oleh kelas induk AbstractDb
.
Kami juga membutuhkan ResourceModel lain, sebuah Collection. Koleksi akan bertanggung jawab untuk menanyakan database untuk beberapa posting menggunakan ResourceModel kami dan mengirimkan kembali serangkaian Model yang dipakai dan diisi dengan info. Kami membuat file app/code/Toptal/Blog/Model/ResourceModel/Post/Collection.php
dengan konten berikut:
<?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'); } }
Perhatikan bahwa dalam konstruktor kami hanya menyebutkan Model, yang akan mewakili entitas posting di seluruh kode kami, dan ResourceModel, yang akan mengambil info di database.
Bagian yang hilang untuk layer ini adalah Post Model itu sendiri. Model harus menampung semua atribut yang telah kami definisikan dalam skema kami, bersama dengan logika bisnis apa pun yang mungkin Anda perlukan. Mengikuti pola Magento 2, kita perlu membuat Antarmuka Data yang akan dikembangkan oleh model kita. Kami menempatkan antarmuka di app/code/Toptal/Blog/Api/Data/PostInterface.php
, dan itu harus menampung nama bidang tabel, bersama dengan metode untuk mengaksesnya:
<?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); }
Sekarang ke implementasi model, di app/code/Toptal/Blog/Model/Post.php
. Kami akan membuat metode yang didefinisikan pada antarmuka. Kami juga akan menentukan tag cache melalui konstanta CACHE_TAG
dan, pada konstruktor, kami akan menentukan ResourceModel yang akan bertanggung jawab atas akses database untuk model kami.
<?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(); } }
Kelas ini agak sederhana, dan tujuannya semata-mata untuk memuat posting yang akan ditampilkan, dan menyediakan metode getPostUrl
ke template. Ada beberapa hal yang perlu diperhatikan.
Jika Anda ingat, kita belum mendefinisikan kelas Toptal\Blog\Model\ResourceModel\Post\CollectionFactory
. Kami hanya mendefinisikan Toptal\Blog\Model\ResourceModel\Post\Collection
. Jadi bagaimana ini bekerja? Untuk setiap kelas yang Anda tentukan dalam modul Anda, Magento 2 akan secara otomatis membuat Pabrik untuk Anda. Pabrik memiliki dua metode: create
, yang akan mengembalikan instance baru untuk setiap panggilan, dan get
, yang akan selalu mengembalikan instance yang sama setiap kali dipanggil—digunakan untuk mengimplementasikan pola Singleton.
Parameter ketiga Blok kami, $data
, adalah array opsional. Karena bersifat opsional dan tidak memiliki petunjuk jenis, maka tidak akan disuntikkan oleh sistem injeksi otomatis. Penting untuk diperhatikan bahwa parameter konstruktor opsional harus selalu diposisikan terakhir dalam parameter. Misalnya, konstruktor Magento\Framework\View\Element\Template
, kelas induk kita, memiliki parameter berikut:
public function __construct( Template\Context $context, array $data = [] ) { ...
Karena kami ingin menambahkan CollectionFactory
kami ke parameter konstruktor setelah memperluas kelas Template, kami harus melakukannya sebelum parameter opsional, jika tidak, injeksi tidak akan berfungsi:
public function __construct( Context $context, PostCollectionFactory $postCollectionFactory, array $data = [] ) { ...
Pada metode getPosts
, yang nantinya akan diakses oleh template kita, kita cukup memanggil metode create
dari PostCollectionFactory
, yang akan mengembalikan kita PostCollection
baru dan memungkinkan kita untuk mengambil postingan kita dari database dan mengirimkannya ke tanggapan kita.
Dan untuk menyelesaikan tata letak rute ini, berikut adalah template PHTML kami, 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; ?>
Perhatikan bahwa di sini kita dapat melihat layer View mengakses ModelView kita ( $block->getPosts()
) yang pada gilirannya menggunakan ResourceModel (koleksi) untuk mengambil model kita ( Toptal\Blog\Model\Post
) dari database. Di setiap template, kapan pun Anda ingin mengakses metode bloknya, akan ada variabel $block
yang ditentukan dan menunggu panggilan Anda.
Sekarang Anda seharusnya dapat melihat daftar posting hanya dengan menekan rute kami lagi.
Melihat Postingan Individu
Sekarang, jika Anda mengklik judul posting, Anda akan mendapatkan 404, jadi mari kita perbaiki. Dengan semua struktur kami di tempat, ini menjadi sangat sederhana. Kita hanya perlu membuat yang berikut ini:
- Tindakan baru, bertanggung jawab untuk menangani permintaan ke
blog/post/view
rute - Blok untuk merender pos
- Template PHTML, bertanggung jawab atas tampilan itu sendiri
- File tata letak untuk rute blog/posting/tampilan, menyatukan potongan-potongan terakhir ini.
Tindakan baru kami cukup sederhana. Itu hanya akan menerima id
parameter dari permintaan dan mendaftarkannya di registri inti Magento, repositori pusat untuk informasi yang tersedia di seluruh siklus permintaan tunggal. Dengan melakukan ini, kami akan membuat ID tersedia untuk diblokir nanti. File harus berada di app/code/Toptal/Blog/Controller/Post/View.php
dan ini isinya:
<?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; } }
Perhatikan bahwa kita telah menambahkan parameter $coreRegistry
ke __construct
kita, dan menyimpannya sebagai atribut untuk digunakan nanti. Pada metode execute
, kami mengambil parameter id
dari permintaan, dan mendaftarkannya. Kami juga menggunakan konstanta kelas, self::REGISTRY_KEY_POST_ID
sebagai kunci register, dan kami akan menggunakan konstanta yang sama ini di blok kami untuk merujuk ke id di registri.
Mari kita buat bloknya, di app/code/Toptal/Blog/Block/View.php
dengan isi sebagai berikut:
<?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 ); } }
Di blok tampilan, kami mendefinisikan metode yang dilindungi _getPostId
, yang hanya akan mengambil ID posting dari registri inti. Metode getPost
publik pada gilirannya akan malas memuat kiriman dan mengeluarkan pengecualian jika kiriman tidak ada. Melempar pengecualian di sini akan membuat Magento menampilkan layar kesalahan default, yang mungkin bukan solusi terbaik dalam kasus seperti itu, tetapi kami akan tetap seperti ini demi kesederhanaan.
Ke template PHTML kami. Tambahkan app/code/Toptal/Blog/view/frontend/templates/post/view.phtml
dengan konten berikut:
<?php /** @var Toptal\Blog\Block\View $block */ ?> <h1><?php echo $block->getPost()->getTitle(); ?></h1> <p><?php echo $block->getPost()->getContent(); ?></p>
Bagus dan sederhana, cukup mengakses metode View block getPost
yang kami buat sebelumnya.
Dan, untuk menggabungkan semuanya, kami membuat file tata letak untuk rute baru kami di app/code/Toptal/Blog/view/frontend/layout/blog_post_view.xml
dengan konten berikut:
<?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>
Ini melakukan hal yang sama yang kita lakukan sebelumnya. Ini hanya menambahkan Toptal\Blog\Block\View
ke wadah content
, dengan Toptal_Blog::post/view.phtml
sebagai template terkait.
Untuk melihatnya beraksi, cukup arahkan browser Anda ke http://magento2.dev/blog/post/view/id/1 untuk berhasil memuat posting. Anda akan melihat layar seperti di bawah ini:
Dan seperti yang Anda lihat, setelah membuat struktur awal kami, sangat mudah untuk menambahkan fitur ke platform, dan sebagian besar kode awal kami digunakan kembali dalam prosesnya.
Jika Anda ingin menguji modul dengan cepat, berikut adalah hasil total pekerjaan kami.
Ke mana harus pergi dari sini?
Jika Anda telah mengikuti saya sampai di sini, selamat! Saya yakin Anda cukup dekat untuk menjadi pengembang Magento 2. Kami telah mengembangkan modul kustom Magento 2 yang cukup canggih, dan meskipun fiturnya sederhana, banyak hal yang telah dibahas.
Beberapa hal yang ditinggalkan dari artikel ini, demi kesederhanaan. Untuk menyebutkan beberapa:
- Admin mengedit formulir dan kisi untuk mengelola konten blog kami
- Kategori blog, tag dan komentar
- Repositori dan beberapa kontrak layanan yang bisa kami buat
- Pengemasan modul sebagai ekstensi Magento 2
Bagaimanapun, berikut adalah beberapa tautan berguna di mana Anda dapat lebih memperdalam pengetahuan Anda:
- Blog Alan Storm di Magento 2 — Alan Storm mungkin memiliki konten paling mendidik dalam hal mempelajari Magento.
- Blog Alan Kent
- Dokumentasi Magento: Dokumen Dev Magento 2
Saya memberi Anda pengantar komprehensif untuk semua aspek yang relevan tentang cara membuat modul di Magento 2, dan beberapa sumber daya tambahan jika Anda membutuhkannya. Sekarang terserah Anda untuk mendapatkan pengkodean, atau pergi ke komentar jika Anda ingin mempertimbangkan.