Tutorial Magento 2: Cum să construiți un modul complet
Publicat: 2022-03-11Magento este în prezent cea mai mare platformă de comerț electronic open-source din lume. Datorită bazei de cod bogate și extensibile, comercianții cu operațiuni mari și mici din întreaga lume îl folosesc pentru o mare varietate de proiecte.
Magento 1 există de opt ani, iar succesorul său, Magento 2, a fost lansat la sfârșitul anului 2015, îmbunătățind punctele slabe ale versiunii anterioare, cum ar fi:
- Performanta imbunatatita
- Suită oficială de teste automatizate
- Interfață de utilizare back-end mai bună
- Bază de cod front-end nouă, mai modernă
- O modalitate mai modulară de a dezvolta module, cu fișiere conținute în codul Magento în loc să fie împrăștiate peste tot
- Număr redus de conflicte între module care încearcă să personalizeze aceeași funcționalitate
Puțin peste un an mai departe, iar îmbunătățirea este vizibilă, deși nu toate problemele menționate au fost rezolvate în totalitate. Acum este complet sigur să spunem că Magento 2 este un program mult mai robust decât predecesorul său. Unele dintre îmbunătățirile prezente în Magento 2 sunt:
- Teste unitare și de integrare, inclusiv o modalitate oficială și documentată de a le crea pentru module personalizate
- Module care sunt cu adevărat modularizate, având toate fișierele plasate într-un singur director
- Un sistem de șabloane mai bogat, permițând dezvoltatorului temei să creeze o ierarhie de șabloane pe n nivel
- O serie de modele de design utile adoptate în întregul cod, îmbunătățind calitatea codului și scăzând probabilitatea erorilor create de module - Acestea includ injecția automată de dependență, contracte de servicii, depozite și fabrici, pentru a numi câteva.
- Integrare nativă în Varnish ca sistem de stocare în cache a întregii pagini, precum și Redis pentru gestionarea sesiunilor și a memoriei cache
- Suport PHP 7
Curba de învățare pentru Magento 2, cu toate aceste modificări, a devenit și mai abruptă. În acest ghid, intenționez să vă arăt cum să vă dezvoltați primul modul Magento 2 și să vă îndrept în direcția potrivită pentru a vă continua studiile. Să ajungem la asta!
Magento 2 Tutorial Cerințe preliminare
Este important să aveți o bună înțelegere a următoarelor tehnologii/concepte pentru a urma restul acestui articol:
- Programare orientată pe obiecte (OOP)
- PHP
- Spații de nume
- MySQL
- Utilizarea de bază a bash
Dintre toate cele de mai sus, OOP este probabil cea mai importantă. Magento a fost creat inițial de o echipă de dezvoltatori Java experimentați, iar moștenirea lor poate fi văzută cu siguranță în întreaga bază de cod. În cazul în care nu sunteți foarte încrezător în abilitățile dvs. de POO, ar putea fi o idee bună să o revizuiți înainte de a începe lucrul cu platforma.
Prezentare generală asupra arhitecturii Magento 2
Arhitectura Magento a fost concepută cu intenția de a face codul sursă cât mai modularizat și extensibil posibil. Scopul final al acestei abordări este să îi permită să fie ușor adaptat și personalizat în funcție de nevoile fiecărui proiect.
Personalizarea înseamnă de obicei schimbarea comportamentului codului platformei. În majoritatea sistemelor, aceasta înseamnă schimbarea codului „de bază”. În Magento, dacă urmați cele mai bune practici, acesta este ceva pe care îl puteți evita de cele mai multe ori, făcând posibil ca un magazin să fie la curent cu cele mai recente corecții de securitate și versiuni de funcții într-un mod fiabil.
Magento 2 este un sistem Model View ViewModel (MVVM). Deși este strâns legată de modelul său model View Controller (MVC), o arhitectură MVVM oferă o separare mai solidă între straturile Model și View. Mai jos este o explicație pentru fiecare dintre straturile unui sistem MVVM:
- Modelul deține logica de afaceri a aplicației și depinde de o clasă asociată - ResourceModel - pentru accesul la baza de date. Modelele se bazează pe contracte de servicii pentru a-și expune funcționalitatea celorlalte straturi ale aplicației.
- Vizualizarea este structura și aspectul a ceea ce vede un utilizator pe un ecran - HTML-ul real. Acest lucru se realizează în fișierele PHTML distribuite cu module. Fișierele PHTML sunt asociate fiecărui ViewModel din fișierele XML Layout , care ar fi denumite lianți în dialectul MVVM. Fișierele de aspect pot atribui și fișiere JavaScript pentru a fi utilizate în pagina finală.
- ViewModel interacționează cu stratul Model, expunând doar informațiile necesare layer-ului View. În Magento 2, acest lucru este gestionat de clasele Block ale modulului. Rețineți că aceasta făcea de obicei parte din rolul de controler al unui sistem MVC. Pe MVVM, controlerul este responsabil doar pentru gestionarea fluxului de utilizator, ceea ce înseamnă că primește solicitări și fie spune sistemului să arate o vizualizare, fie să redirecționeze utilizatorul către o altă rută.
Un modul Magento 2 constă din unele, dacă nu toate, elemente ale arhitecturii descrise mai sus. Arhitectura generală este descrisă mai jos (sursă):
Un modul Magento 2 poate defini, la rândul său, dependențe externe folosind Composer, managerul de dependențe al PHP. În diagrama de mai sus, vedeți că modulele de bază Magento 2 depind de Zend Framework, Symfony, precum și de alte biblioteci terțe.
Mai jos este structura Magento/Cms, un modul de bază Magento 2 responsabil cu gestionarea creării de pagini și blocuri statice.
Fiecare folder deține o parte a arhitecturii, după cum urmează:
- Api: Contracte de servicii, definirea interfețelor de servicii și a interfețelor de date
- Bloc: Modelele de vizualizare ale arhitecturii noastre MVVM
- Controller: Controller, responsabili de gestionarea fluxului utilizatorului în timp ce interacționează cu sistemul
- etc: Fișiere XML de configurare—Modulul se definește pe sine și părțile sale (rute, modele, blocuri, observatori și joburi cron) în acest folder. Fișierele etc pot fi folosite și de modulele non-core pentru a suprascrie funcționalitatea modulelor de bază.
- Helper: clase de ajutor care dețin codul utilizat în mai mult de un nivel de aplicație. De exemplu, în modulul Cms, clasele de ajutor sunt responsabile pentru pregătirea HTML pentru prezentare în browser.
- i18n: Deține fișiere CSV de internaționalizare, utilizate pentru traducere
- Model: pentru modele și modele de resurse
- Observator: Deține observatori sau modele care „observă” evenimente de sistem. De obicei, atunci când un astfel de eveniment este declanșat, observatorul instanțiază un Model pentru a gestiona logica de afaceri necesară pentru un astfel de eveniment.
- Configurare: clase de migrare, responsabil pentru crearea schemei și a datelor
- Test: teste unitare
- Ui: elemente de UI, cum ar fi grile și formulare utilizate în aplicația de administrare
- vizualizare: fișiere de aspect (XML) și fișiere șablon (PHTML) pentru aplicația front-end și de administrare
De asemenea, este interesant de observat că, în practică, toate funcțiile interioare ale Magento 2 trăiesc în interiorul unui modul. În imaginea de mai sus, puteți vedea, de exemplu, Magento_Checkout
, responsabil pentru procesul de checkout și Magento_Catalog
, responsabil pentru manipularea produselor și categoriilor. Practic, ceea ce ne spune acest lucru este că a învăța cum să lucrezi cu module este cea mai importantă parte a devenirii unui dezvoltator Magento 2.
Bine, după această introducere relativ scurtă în arhitectura sistemului și structura modulelor, hai să facem ceva mai concret, nu? În continuare, vom parcurge tutorialul tradițional Weblog pentru a vă simți confortabil cu Magento 2 și pe cale să deveniți un dezvoltator Magento 2. Înainte de asta, trebuie să creăm un mediu de dezvoltare. Să ajungem la asta!
Configurarea mediului de dezvoltare a modulelor Magento 2
La momentul scrierii acestui articol, am putut folosi oficial Magento 2 DevBox, care este un container Magento 2 Docker. Docker pe macOS este ceva pe care încă îl consider inutilizabil, cel puțin cu un sistem care depinde în mare măsură de I/O pe disc, cum ar fi Magento 2. Așadar, o vom face în mod tradițional: instalați toate pachetele nativ pe propria noastră mașină.
Configurarea serverului
Instalarea totul este cu siguranță puțin mai obositoare, dar rezultatul final va fi un mediu de dezvoltare Magento fulgerător. Crede-mă, vei economisi ore de muncă dacă nu depinzi de Docker pentru dezvoltarea Magento 2.
Acest tutorial presupune un mediu pe macOS cu Brew instalat pe el. Dacă nu este cazul dvs., elementele de bază vor rămâne aceleași, schimbând doar modul în care instalați pachetele. Să începem cu instalarea tuturor pachetelor:
brew install mysql nginxb php70 php70-imagick php70-intl php70-mcrypt
Apoi porniți serviciile:
brew services start mysql brew services start php70 sudo brew services start nginx
Ok, acum vom indica un domeniu către adresa noastră de loopback. Deschideți fișierul hosts în orice editor, dar asigurați-vă că aveți permisiuni de superutilizator. A face asta cu Vim ar fi:
sudo vim /etc/hosts
Apoi adăugați următoarea linie:
127.0.0.1 magento2.dev
Acum vom crea un vhost în Nginx:
vim /usr/local/etc/nginx/sites-available/magento2dev.conf
Adăugați următorul conținut:
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; }
Dacă nu ați mai avut de-a face cu Nginx până acum, acest fișier s-ar putea să vă sperie, așa că permiteți-ne să explicăm părțile mici aici, deoarece va arunca, de asemenea, puțină lumină asupra unora dintre funcțiile interioare ale Magento. Primele linii îi spun pur și simplu lui Nginx că folosim portul HTTP implicit, iar domeniul nostru este magento2.dev
:
listen 80; server_name magento2.dev;
Apoi setăm câteva variabile de mediu. Primul - $MAGE_ROOT
deține calea către baza noastră de cod. Observați că va trebui să schimbați calea rădăcină pentru a se potrivi cu calea numelui de utilizator/dosar, oriunde doriți să plasați sursa:
set $MAGE_ROOT /Users/yourusername/www/magento2dev;
A doua variabilă $MAGE_MODE
setează modul de rulare pentru magazinul nostru. Pe măsură ce dezvoltăm un modul, vom folosi modul dezvoltator. Acest lucru ne permite să codificăm mai rapid, deoarece nu va trebui să compilam sau să implementăm fișiere statice în timpul dezvoltării. Celelalte moduri sunt producție și implicite. Utilizarea reală a acestuia din urmă nu este încă clară.
set $MAGE_MODE developer;
După ce aceste variabile sunt setate, definim calea rădăcină a vhost. Observați că sufixăm variabila $MAGE_ROOT
cu folderul /pub
, făcând doar o parte din magazinul nostru disponibil pe web.
root $MAGE_ROOT/pub;
Apoi definim fișierul nostru index - fișierul nginx se va încărca atunci când fișierul solicitat nu există - ca index.php. Acest script, $MAGE_ROOT/pub/index.php
, este principalul punct de intrare pentru clienții care vizitează atât coșul de cumpărături, cât și aplicațiile de administrare. Indiferent de adresa URL solicitată, index.php va fi încărcat și procesul de expediere a routerului va începe.
index index.php;
Apoi, dezactivăm unele funcții Nginx. În primul rând, dezactivăm autoindex
, care ar afișa o listă de fișiere atunci când solicitați un folder, dar nu specificăm un fișier și nu este prezent niciun index. În al doilea rând, dezactivăm charset
, ceea ce i-ar permite lui Nginx să adauge automat anteturi Charset la răspuns.
autoindex off; charset off;
În continuare, definim câteva anteturi de securitate:
add_header 'X-Content-Type-Options' 'nosniff'; add_header 'X-XSS-Protection' '1; mode=block';
Această locație, /
, este îndreptată către folderul nostru rădăcină $MAGE_ROOT/pub
și, practic, redirecționează orice solicitare primită către controlerul nostru frontal index.php, împreună cu argumentele cererii:
location / { try_files $uri $uri/ /index.php?$args; }
Următoarea porțiune poate fi puțin confuză, dar este destul de simplă. Acum câteva rânduri, am definit rădăcina noastră ca $MAGE_ROOT/pub
. Aceasta este configurarea recomandată și mai sigură, deoarece majoritatea codului nu este vizibil de pe web. Dar nu este singura modalitate de a configura serverul web. De fapt, majoritatea serverelor web partajate au o configurație implicită, care este ca serverul dvs. web să indice folderul dvs. web. Pentru acești utilizatori, echipa Magento a pregătit acest fișier pentru acele cazuri, când rădăcina este definită ca $MAGE_ROOT
cu următorul fragment:
location /pub { location ~ ^/pub/media/(downloadable|customer|import|theme_customization/.*\.xml) { deny all; } alias $MAGE_ROOT/pub; add_header X-Frame-Options "SAMEORIGIN"; }
Rețineți că, ori de câte ori este posibil, cel mai bine este ca serverul dvs. web să indice folderul $MAGE_ROOT/pub
. Magazinul dvs. va fi mai sigur în acest fel.
În continuare, avem locația statică $MAGE_ROOT/pub/static
. Acest folder este inițial gol și umplut automat cu fișierele statice ale modulelor și temelor, cum ar fi fișiere imagine, CSS, JS, etc. Aici definim practic câteva valori cache pentru fișierele statice și, atunci când fișierul solicitat nu există, redirecționați-l către $MAGE_ROOT/pub/static.php
. Acest script va analiza, printre altele, cererea și va copia sau legă simbolul fișierului specificat din modulul sau tema corespondente, în funcție de modul de rulare definit. În acest fel, fișierele statice ale modulului dvs. vor locui în folderul modulelor noastre, dar vor fi servite direct din folderul public 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"; }
Apoi refuzăm accesul web la unele foldere și fișiere restricționate:
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; }
Și ultimul bit este locul în care încărcăm php-fpm și îi spunem să execute index.php ori de câte ori utilizatorul îl lovește:
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; }
Cu asta în afara drumului nostru, salvați fișierul și apoi activați-l tastând următoarele comenzi:
ln -s /usr/local/etc/nginx/sites-available/magento2dev.conf \ /usr/local/etc/nginx/sites-enabled/magento2dev.conf sudo brew services restart nginx
Cum se instalează Magento 2
Bine, în acest moment, mașina dvs. îndeplinește cerințele Magento 2, lipsind doar fiara în sine. Mergeți pe site-ul web Magento și creați un cont dacă încă nu aveți unul. După aceea, accesați pagina de descărcare și descărcați cea mai recentă versiune (2.1.5, la momentul scrierii):
Selectați formatul .tar.bz2 și descărcați-l. Apoi continuați să îl extrageți și să setați permisiunile corecte pentru foldere și fișiere pentru ca Magento 2 să poată funcționa:
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
Acum, pentru a instala tabelele bazei de date și a crea fișierele de configurare necesare, vom rula această comandă din 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
Nu uitați să schimbați numele bazei de date ( db-name
), utilizator ( db-user
) și parola ( db-password
) pentru a se potrivi cu cea pe care ați folosit-o în timpul instalării MySQL și asta este tot! Această comandă va instala toate modulele Magento 2, creând tabelele și fișierele de configurare necesare. După ce ați terminat, deschideți browserul și mergeți la http://magento2.dev/. Ar trebui să vedeți o instalare curată a Magento 2 cu tema implicită Luma:
Dacă mergeți la http://magento2.dev/admin, ar trebui să vedeți pagina de conectare a aplicației de administrare:
Apoi utilizați acreditările de mai jos pentru a vă autentifica:
Utilizator: admin Parola: admin123
Suntem în sfârșit gata să începem să scriem codul nostru!
Crearea primului nostru modul Magento 2
Pentru a finaliza modulul nostru, va trebui să creăm următoarele fișiere, iar eu vă voi ghida prin întregul proces. Noi vom avea nevoie:
- Câteva fișiere de înregistrare standard, pentru ca Magento să cunoască modulul nostru Blog
- Un fișier de interfață, pentru a defini contractul nostru de date pentru Post
- Un Post Model, pentru a reprezenta o Postare în codul nostru, implementând interfața de date Post
- Un model de resurse post, pentru a lega modelul de post la baza de date
- O colecție de postări, pentru a prelua mai multe postări simultan din baza de date cu ajutorul modelului de resurse
- Două clase de migrare, pentru a configura schema și conținutul tabelului nostru
- Două acțiuni: una pentru a enumera toate postările și alta pentru a afișa fiecare postare individual
- Câte două fișiere Blocuri, Vizualizări și Aspect: câte unul pentru acțiunea din listă și câte unul pentru vizualizare
Mai întâi, să aruncăm o privire rapidă asupra structurii directorului codului sursă de bază, astfel încât să putem defini unde să plasăm codul. Modul în care am instalat are tot codul de bază Magento 2, împreună cu toate dependențele sale, care trăiesc în folderul vendor
al compozitorului.
Înregistrarea modulului nostru
Vom păstra codul într-un folder separat, app/code
. Numele fiecărui modul este sub forma Namespace_ModuleName
, iar locația sa pe sistemul de fișiere trebuie să reflecte acel nume, app/code/Namespace/ModuleName
pentru acest exemplu. Urmând acest model, vom numi modulul nostru Toptal_Blog
și vom plasa fișierele noastre în app/code/Toptal/Blog
. Continuați și creați acea structură de foldere.
Acum, trebuie să creăm câteva fișiere standard pentru a avea modulul înregistrat cu Magento. Mai întâi, creați app/code/Toptal/Blog/composer.json
:
{}
Acest fișier va fi încărcat de Composer de fiecare dată când îl rulați. Chiar dacă nu folosim de fapt Composer cu modulul nostru, trebuie să-l creăm pentru a-l face pe Composer fericit.
Acum vom înregistra modulul nostru cu Magento. Continuați și creați app/code/Toptal/Blog/registration.php
:
<?php \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, 'Toptal_Blog', __DIR__ );
Aici apelăm metoda register
a clasei ComponentRegistrar
, trimițând doi parametri: șirul 'module'
, care este tipul de componentă pe care o înregistrăm, și numele modulului nostru, 'Toptal_Blog'
. Cu aceste informații, încărcătorul automat Magento va fi conștient de spațiul nostru de nume și va ști unde să caute clasele și fișierele XML.
Un lucru interesant de observat aici este că avem tipul de componentă ( MODULE
) care este trimis ca parametru la funcția \Magento\Framework\Component\ComponentRegistrar::register
. Nu numai că putem înregistra module, dar putem înregistra și alte tipuri de componente. De exemplu, temele, bibliotecile externe și pachetele lingvistice sunt de asemenea înregistrate folosind aceeași metodă.
Continuând, permiteți-ne să creăm ultimul nostru fișier de înregistrare, 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>
Acest fișier conține câteva informații foarte importante despre modulul nostru. Sunt:
- Numele modulului este prezent din nou, expunând numele modulului nostru la configurația Magento.
- Versiunea de configurare Magento, care va fi folosită de Magento pentru a decide când să ruleze scripturile de migrare a bazei de date.
- Dependențe ale modulului nostru — Pe măsură ce scriem un modul simplu, depindem doar de două module de bază Magento:
Magento_Directory
șiMagento_Config
.
Acum, avem un modul care ar trebui să fie recunoscut de Magento 2. Să-l verificăm folosind CLI Magento 2.
În primul rând, trebuie să dezactivăm memoria cache a Magento. Mecanismele de cache ale Magento merită un articol dedicat lor. Deocamdată, deoarece dezvoltăm un modul și dorim ca modificările noastre să fie recunoscute de către Magento instantaneu, fără a fi nevoie să ștergem memoria cache în orice moment, îl vom dezactiva pur și simplu. Din linia de comandă, rulați:
./bin/magento cache:disable
Apoi, să vedem dacă Magento este deja la curent cu modificările noastre, uitându-ne la starea modulelor. Pur și simplu rulați următoarea comandă:
./bin/magento module:status
Rezultatul ultimului ar trebui să fie similar cu:
Modulul nostru este acolo, dar după cum arată rezultatul, este încă dezactivat. Pentru a-l activa, rulați:
./bin/magento module:enable Toptal_Blog
Asta ar fi trebuit să o facă. Pentru a fi sigur, puteți apela din nou module:status
și căutați numele modulului nostru în lista activată:
Gestionarea stocării datelor
Acum că ne-am activat modulul, trebuie să creăm tabelul bazei de date care conține postările noastre de blog. Aceasta este schema pentru tabelul pe care vrem să-l creăm:
Camp | Tip | Nul | Cheie | Mod implicit |
---|---|---|---|---|
post_id | int(10) nesemnat | NU | PRI | NUL |
titlu | text | NU | NUL | |
conţinut | text | NU | NUL | |
creat la | timestamp-ul | NU | CURRENT_TIMESTAMP |
Obținem acest lucru prin crearea clasei InstallSchema
, care este responsabilă de gestionarea instalării migrării schemei noastre. Fișierul se află la app/code/Toptal/Blog/Setup/InstallSchema.php
și are următorul conținut:
<?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(); } }
Dacă analizați metoda de install
, veți observa că pur și simplu creează tabelul nostru și își adaugă coloanele una câte una.

Pentru a determina când să ruleze o migrare a schemei, Magento păstrează un tabel cu toate versiunile de configurare curente pentru fiecare modul și, ori de câte ori o versiune de modul se modifică, clasele sale de migrare sunt inițializate. Acest tabel este setup_module
, iar dacă aruncați o privire la conținutul acelui tabel, veți vedea că nu există nicio referință la modulul nostru până acum. Deci, hai să schimbăm asta. De la un terminal, lansați următoarea comandă:
./bin/magento setup:upgrade
Aceasta vă va arăta o listă cu toate modulele și scripturile sale de migrare care au fost executate, inclusiv al nostru:
Acum, din clientul dvs. MySQL preferat, puteți verifica dacă tabelul a fost într-adevăr creat:
Și la tabelul setup_module
, acum există o referință la modulul nostru, schema sa și versiunea de date:
Ok, și cum rămâne cu upgrade-urile de schemă? Să adăugăm câteva postări la acel tabel printr-o actualizare pentru a vă arăta cum să faceți asta. Mai întâi, introduceți setup_version
în fișierul nostru etc/module.xml
:
Acum creăm fișierul nostru app/code/Toptal/Blog/Setup/UpgradeData.php
, care este responsabil pentru migrarea datelor (nu a schemei):
<?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(); } }
Puteți vedea că este foarte asemănător cu clasa noastră Instalare. Singura diferență este că implementează un UpgradeDataInterface
în loc de InstallSchemaInterface
, iar metoda principală se numește upgrade
. Cu această metodă, verificați versiunea instalată a modulului curent și, atunci când este mai mică decât a dvs., activați modificările pe care trebuie să le efectuați. În exemplul nostru, verificăm dacă versiunea curentă este mai mică decât 0.1.1 în următoarea linie folosind funcția version_compare
:
if ($context->getVersion() && version_compare($context->getVersion(), '0.1.1') < 0 ) {
$context->getVersion()
va returna 0.1.0 atunci când comanda CLI setup:upgrade
este apelată pentru prima dată. Apoi, mostrele de date sunt încărcate în baza de date, iar versiunea noastră este mărită la 0.1.1. Pentru a rula, mergeți mai departe și declanșați un setup:upgrade
:
./bin/magento setup:upgrade
Și apoi verificați rezultatele la tabelul cu postări:
Și la tabelul setup_module
:
Observați că, deși am adăugat date în tabelul nostru folosind procesul de migrare, ar fi fost posibil să schimbăm și schema. Procesul este același; veți folosi doar UpgradeSchemaInterface
în loc de UpgradeDataInterface
.
Definirea modelului pentru posturi
Mergând mai departe, dacă vă amintiți prezentarea noastră de ansamblu asupra arhitecturii, următorul nostru bloc ar fi articolul de blog ResourceModel. Modelul de resurse este foarte simplu și precizează pur și simplu tabelul la care se va „conecta” modelul, împreună cu cheia sa principală. Ne vom crea ResourceModel la app/code/Toptal/Blog/Model/ResourceModel/Post.php
cu următorul conținut:
<?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'); } }
Toate operațiunile ResourceModel, cu excepția cazului în care aveți nevoie de ceva diferit de operațiunile obișnuite CRUD, sunt gestionate de clasa părinte AbstractDb
.
Vom avea nevoie și de un alt ResourceModel, o colecție. Colecția va fi responsabilă de interogarea bazei de date pentru mai multe postări folosind ResourceModel-ul nostru și de livrarea unei serii de Modele instanțiate și completate cu informații. Creăm fișierul app/code/Toptal/Blog/Model/ResourceModel/Post/Collection.php
cu următorul conținut:
<?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'); } }
Observați că în constructor menționăm pur și simplu Modelul, care va reprezenta entitatea post în codul nostru, și ResourceModel, care va prelua informațiile din baza de date.
Piesa lipsă pentru acest strat este Post Modelul însuși. Modelul ar trebui să conțină toate atributele pe care le-am definit în schema noastră, împreună cu orice logică de afaceri de care ai putea avea nevoie. Urmând modelul Magento 2, trebuie să creăm o interfață de date de la care modelul nostru se va extinde. Am plasat interfața la app/code/Toptal/Blog/Api/Data/PostInterface.php
și ar trebui să conțină numele câmpurilor din tabel, împreună cu metodele de accesare a acestora:
<?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); }
Acum, la implementarea modelului, la app/code/Toptal/Blog/Model/Post.php
. Vom crea metodele definite la interfață. De asemenea, vom specifica o etichetă cache prin constanta CACHE_TAG
și, la constructor, vom specifica ResourceModel care va fi responsabil pentru accesul la baza de date pentru modelul nostru.
<?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(); } }
Această clasă este destul de simplă, iar obiectivul ei este doar de a încărca postările care urmează să fie afișate și de a oferi șablonului o metodă getPostUrl
. Există însă câteva lucruri de observat.
Dacă vă amintiți, nu am definit o Toptal\Blog\Model\ResourceModel\Post\CollectionFactory
. Am definit doar Toptal\Blog\Model\ResourceModel\Post\Collection
. Deci cum funcționează asta? Pentru fiecare clasă pe care o definiți în modulul dvs., Magento 2 va crea automat o fabrică pentru dvs. Fabricile au două metode: create
, care va returna o nouă instanță pentru fiecare apel și get
, care va returna întotdeauna aceeași instanță ori de câte ori este apelată - folosită pentru a implementa modelul Singleton.
Al treilea parametru al blocului nostru, $data
, este o matrice opțională. Deoarece este opțional și nu are indiciu de tip, nu va fi injectat de sistemul automat de injecție. Este important de observat că parametrii opționali ai constructorului trebuie să fie întotdeauna poziționați ultimii în parametri. De exemplu, constructorul Magento\Framework\View\Element\Template
, clasa noastră părinte, are acești parametri:
public function __construct( Template\Context $context, array $data = [] ) { ...
Deoarece am vrut să adăugăm CollectionFactory
la parametrii constructorului după extinderea clasei Template, a trebuit să o facem înainte de parametrul opțional, altfel injecția nu ar funcționa:
public function __construct( Context $context, PostCollectionFactory $postCollectionFactory, array $data = [] ) { ...
La metoda getPosts
, care va fi accesată ulterior de șablonul nostru, numim pur și simplu metoda create
din PostCollectionFactory
, care ne va returna o nouă PostCollection
și ne va permite să ne preluăm postările din baza de date și să o trimitem la răspunsul nostru.
Și pentru a finaliza aspectul acestui traseu, iată șablonul nostru PHTML, 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; ?>
Observați că aici putem vedea stratul View accesând ModelView ( $block->getPosts()
) care, la rândul său, folosește un ResourceModel (colecția) pentru a prelua modelele noastre ( Toptal\Blog\Model\Post
) din baza de date. În fiecare șablon, ori de câte ori doriți să accesați metodele blocului său, va exista o variabilă $block
definită și vă așteaptă apelurile.
Acum ar trebui să puteți vedea lista de postări apăsând din nou pe traseul nostru.
Vizualizarea postărilor individuale
Acum, dacă dați clic pe titlul unei postări, veți obține un 404, așa că haideți să rezolvăm asta. Cu toată structura noastră la loc, acest lucru devine destul de simplu. Va trebui doar să creăm următoarele:
- O nouă acțiune, responsabilă cu gestionarea solicitărilor către traseul
blog/post/view
- Un bloc pentru a reda postarea
- Un șablon PHTML, responsabil pentru vizualizarea în sine
- Un fișier de aspect pentru traseul blog/post/vizualizare, punând împreună aceste ultime piese.
Noua noastră acțiune este destul de simplă. Pur și simplu va primi id
-ul parametrului de la cerere și îl va înregistra în registrul de bază Magento, un depozit central pentru informații care sunt disponibile pe parcursul unui singur ciclu de solicitare. Făcând acest lucru, vom pune ID-ul disponibil pentru bloc mai târziu. Fișierul ar trebui să fie localizat la app/code/Toptal/Blog/Controller/Post/View.php
și acesta este conținutul său:
<?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; } }
Observați că am adăugat parametrul $coreRegistry
__construct
și l-am salvat ca atribut pentru utilizare ulterioară. La metoda execute
, preluăm parametrul id
din cerere și îl înregistrăm. De asemenea, folosim o constantă de clasă, self::REGISTRY_KEY_POST_ID
ca cheie pentru registru și vom folosi aceeași constantă la blocul nostru pentru a ne referi la id-ul din registru.
Să creăm blocul, la app/code/Toptal/Blog/Block/View.php
cu următorul conținut:
<?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 ); } }
La blocul de vizualizare, definim o metodă protejată _getPostId
, care pur și simplu va prelua ID-ul postării din registrul de bază. Metoda publică getPost
va încărca leneș postarea și va arunca o excepție dacă postarea nu există. Aruncarea unei excepții aici va face ca Magento să-și arate ecranul de eroare implicit, care ar putea să nu fie cea mai bună soluție într-un astfel de caz, dar o vom păstra astfel de dragul simplității.
Treceți la șablonul nostru PHTML. Adăugați app/code/Toptal/Blog/view/frontend/templates/post/view.phtml
cu următorul conținut:
<?php /** @var Toptal\Blog\Block\View $block */ ?> <h1><?php echo $block->getPost()->getTitle(); ?></h1> <p><?php echo $block->getPost()->getContent(); ?></p>
Frumos și simplu, accesând pur și simplu metoda View block getPost
pe care am creat-o mai devreme.
Și, pentru a pune totul împreună, creăm un fișier de aspect pentru noua noastră rută la app/code/Toptal/Blog/view/frontend/layout/blog_post_view.xml
cu următorul conținut:
<?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>
Aceasta face același lucru pe care l-am făcut și înainte. Pur și simplu adaugă Toptal\Blog\Block\View
în containerul de content
, cu Toptal_Blog::post/view.phtml
ca șablon asociat.
Pentru a-l vedea în acțiune, pur și simplu direcționați browserul către http://magento2.dev/blog/post/view/id/1 pentru a încărca cu succes o postare. Ar trebui să vedeți un ecran precum cel de mai jos:
Și după cum puteți vedea, după crearea structurii noastre inițiale, este foarte simplu să adăugați funcții la platformă, iar cea mai mare parte a codului nostru inițial este reutilizat în acest proces.
În cazul în care doriți să testați rapid modulul, iată rezultatul total al muncii noastre.
Unde să mergi de aici
Dacă m-ați urmărit până aici, felicitări! Sunt convins că sunteți destul de aproape de a deveni un dezvoltator Magento 2. Am dezvoltat un modul personalizat Magento 2 destul de avansat și, deși este simplu în caracteristicile sale, a fost acoperit mult teren.
Unele lucruri au fost omise din acest articol, de dragul simplității. A numi câteva:
- Admin editează formulare și grile pentru a gestiona conținutul blogului nostru
- Categorii de bloguri, etichete și comentarii
- Depozitele și câteva contracte de servicii pe care le-am fi putut stabili
- Împachetarea modulelor ca extensii Magento 2
În orice caz, iată câteva link-uri utile unde vă puteți aprofunda și mai mult cunoștințele:
- Blogul Alan Storm despre Magento 2 — Alan Storm are probabil cel mai didactic conținut atunci când vine vorba de învățarea Magento.
- Blogul lui Alan Kent
- Documentație Magento: documentele Magento 2 Dev
V-am oferit o introducere cuprinzătoare la toate aspectele relevante ale modului de a crea un modul în Magento 2 și câteva resurse suplimentare dacă aveți nevoie de ele. Acum rămâne la latitudinea dvs. să obțineți codificare sau mergeți la comentarii dacă doriți să cântăriți.