Struktura Magento aplikacije

Magento je e-commerce CMS platforma zasnovana na PHP-u i Zend Frameworku. Uz pomoć njega, korisnici su u mogućnosti da u potpunosti upravljaju svojom online prodavnicom, prikažu određene proizvode, omoguće kupcima različite metode plaćanja i isporuke, kao i mnoge druge opcije.

Dolazi u tri verzije:

  • Besplatna osnovna community verzija,
  • “Enterprise” verzija koja se plaća i pruža dodatne funkcionalnosti kao i tehničku podršku,
  • “Go” koji je online verzija za mala preduzeća i funkcioniše kao servis za čije se korišćenje plaća mesečna pretplata.

Magento je trenutno vodeća open source ecommerce platforma - preko 125 000 sajtova napravljenih uz pomoć Magenta i 386 zvaničnih partner firmi koje se bave Magento razvojem. Takođe treba napomenuti da postoji program sertifikacije Magento programera kao i veoma snažna zajednica na internetu, okupljena na blogovima i forumima.

Nastao je tako što se 2007. godine okupio tim programera koji je radio na jednom drugom eCommerce rešenju - osCommerce. Rešili su da ga modifikuju, ali su se u toku razvoja odlučili da naprave svoj proizvod. U 2011. godini eBay je u potpunosti kupio Magento, čime je on postao deo eBay x Commerce platforme.

Kao CMS prilagođen potrebama e-Commerce rešenja, Magento podrazumeva administratorski i frontend deo, po ugledu na vodeća CMS rešenja.

Struktura

Za organizaciju fajlova koristi se princip modularnosti. Čitav kod aplikacije je podeljen u 3 tzv. code pool-a u kojima se nalaze moduli sa fajlovima:

  • “core”: sastoji se od fajlova napravljenih od strane Magento razvojnog tima,
  • “community”: sadrži module koji su zvanične ekstenzije sa Magento marketa,
  • “local”: sadrži module vezane direktno za projekat.

Podrazumevane Magento funkcionalnosti koje su opisane u core code pool-u mogu se promeniti preko modula iz “community” i “local” code poola. Ovakav pristup pruža velike mogućnosti za prilagođavanje i nadogradnju osnovnih funkcionalnosti kao i za prilagođavanje osnovne aplikacije konkretnim zahtevima.

Svaki modul sadrzi folder “etc” u kojem se nalazi konfiguracija u XML formatu. Fajl “config.xml” definiše sva potrebna podešavanja za funkcionisanje modula. On sadrži informacije o elementima modula kao što su:

  • Block
  • Helper
  • Controllers
  • Model
  • Sql

Struktura foldera jednog modula izgleda ovako:

part4-folder

Svi moduli se nalaze u folderu “code”, a postoje još neke celine kao što su “template” i “layout” koje se nalaze u folderu “design”.

magento_design_structure

Sada ćemo navesti i opisati elemente Magento modula.

Block

Magento je zasnovan na MVC paternu, ali na sebi sopstven način uvodi još jedan element - block.

Osnovna razlika od standardne primene MVC paterna (npr. njegove standardne primene u Zend framework-u) je ta što u Magentu kontroler ne prosleđuje podatke na view, već je to uloga bloka. U tipičnom zahtevu block metode izvlače podatke direktno iz modela i smeštaju ih u template (koji je instanca blok objekta). U idealnom slučaju, kontroler postavlja parametre zahteva na model, a blok izvlači podatke iz modela kada dođe vreme za prikaz.

Još jedan često korišćen način komunikacije bloka i kontrolera je primena Registry paterna. Kontroler ima zadatak da u registry upiše potrebnu informaciju, kako bi je blok mogao pročitati kada za to dođe vreme.

Sledi primer za opisanu situaciju:

/app/code/core/Mage/Checkout/controllers/OnepageController.php

protected function _initInvoice()
 {
     //….....
     Mage::register('current_invoice', $invoice);
     return $invoice;
 }
 

/code/core/Mage/Adminhtml/Block/Sales/Items/Abstract.php

public function getInvoice()
 {
     return Mage::registry('current_invoice');
 }
 

U ovom primeru protected metoda _initInvoice() koja se poziva u nekoj akciji kontrolera postavlja invoice objekat u Magento registry, a zatim se u daljem izvršavanju u bloku ta vrednost izvlači i koristi za prikaz.

Cilj ovakvog pristupa je jasnija podela odgovornosti između delova aplikacije i primena loose-coupling principa programiranja. Rezultat je da kontroleri obuhvataju manji deo poslovne logike, čime se zadovoljava “skinny controller” arhitektura MVC aplikacija, po kojem bi kontroleri trebalo da budu što manjeg obima, a da poslovna logika aplikacije bude sadržana u okviru modela.

Magento podržava i standardni MVC pristup, te u kontroleru može da stoji sledeće:

$this->loadLayout();
 $block = $this->getLayout()->getBlock('block_name');
 $block->setFirstVar('Data 1');
 $block->setData('second_var', 'Data 2');
 $block->assign('third_var','Data 3');
 $this->renderLayout();
 

U okviru template fajlova, o kojima će biti reči kasnije, se mogu ispisati podaci na sledeći način:

echo $this->getFirstVar();
 echo $this->getSecondVar();
 echo $third_var;
 

Model

Za organizaciju baze podataka Magento u velikoj meri koristi EAV (entity-attribute-value) princip. Osnovna prednost ovog pristupa je fleksibilnost, zbog toga što nije ograničen broj kolona a samim tim i nije potreban redizajn baze svaki put kad se dodaje novi atribut. Mana je što je za upite na bazu podataka sa ovakvim dizajnom potrebno više vremena nego za baze podataka sa klasičnim dizajnom.

EAV

Određeni delovi aplikacije koriste EAV princip (na primer - catalog koji je zadužen za proizvode), dok neki koriste klasičan princip organizacije podataka (na primer - sales). Prema tome se Magento modeli dele na klasične i EAV modele. Razlika je u njihovim odgovarajućim Resource klasama, kojima ostvaruju vezu sa bazom podataka.

Resource klase se u okviru svojih metoda oslanjaju na klase koje nasleđuju Zend_Db_Adapter, što znači da za pravljenje upita koriste poznate metode iz Zend framework-a. Ovim je postignuto dodatno razdvajanje odgovornosti pojedinih delova aplikacije.

Za korišćenje klasa modela u Magentu se koristi Factory Pattern. Modeli se instanciraju korišćenjem statičke metode iz osnovne klase Mage:

$model = Mage::getModel(“catalog/product”);
 

Ovim pozivom se iz konfiguracije nalazi odgovarajući model i instancira. Rezultat ove operacije je identičan sledećem pozivu:

$model = new Mage_Catalog_Model_Product; 
 

Postoji i opcija da se model instancira po principu Singleton Pattern, a Magento Registry klasa vodi računa o tome da postoji samo jedna instanca:

$model = Mage::getSingleton(“catalog/product”);
 

Baza podataka u Magento rešenju je veoma obimna, o čemu govori i podatak da osnovna instalacija sadrži čak 324 tabele.

Za određeni deo procesa Magento koristi Event-Observer metodologiju (slično kao WordPress), koja podrazumeva da se u određenim delovima koda pokreće Event - događaj, čije okidanje čekaju Observer klase. One pokreću odgovarajuće metode koje su definisane u okviru XML konfiguracije modula. Sledi primer:

U Sales modulu je definisan Observer za događaj:

/app/code/core/Mage/Tax/etc/config.xml

<sales_order_place_after>
     
         
             salesrule/observer
             sales_order_afterPlace
         
     
 
 

Dalje saznajemo da se ovaj događaj desio u klasi Mage_Sales_Model_Order u okviru metode place(). Takođe, primećujemo da je ovom događaju prosleđen objekat klase Order:

/app/code/core/Mage/Sales/Model/Order.php

public function place()
 {
     Mage::dispatchEvent('sales_order_place_before', array('order'=>$this));
     $this->_placePayment();
     Mage::dispatchEvent('sales_order_place_after', array('order'=>$this));
     return $this;
 }
 

U definiciji Observer-a upisano je da se pri okidanju ovog događaja poziva metoda sales_order_afterPlace() iz klase Mage_SalesRule_Model_Observer.

/app/code/core/Mage/SalesRule/Model/Observer.php

public function sales_order_afterPlace($observer)
 {
     $order = $observer->getEvent()->getOrder();
 
     if (!$order) {
         return $this;
     }
 ...
 

Observer metoda može izvući sve što joj je prosleđeno pri okidanju događaja što je u ovom slučaju objekat klase Order.

Helper

Moduli mogu sadržati i pomoćne (Helper) klase, koje definišu metode koje se mogu pozvati i koristiti u bilo kom delu aplikacije. One izvode različite korisne operacije i predstavljaju dobar primer reusable koda, koji se može koristiti više puta na različitim mestima u aplikaciji.

/app/code/core/Mage/Checkout/Helper/Cart.php

public function getCartUrl()
 {
     return $this->_getUrl('checkout/cart');
 }
 

/code/core/Mage/Wishlist/controllers/SharedController.php

public function cartAction()
 {
     //.....
     $redirectUrl = Mage::helper('checkout/cart')->getCartUrl();
     //......
 }
 

Controller

Magento koristi sličan šablon rutiranja kao i obična ZF aplikacija:

http://example.com/frontName/actionControllerName/actionMethod/paramName/paramValue

Uzmimo kao primer sledeći zahtev za prikaz stranice: http://example.com/checkout/cart Magento će pozvati metodu indexAction() koja se nalazi u okviru klase Mage_Checkout_CartController unutar fajla /app/code/core/Mage/Checkout/controllers/CartController.php.

U tipičnoj Magento aplikaciji Front Controller instancira Router objekte koji traže odgovarajući Action Controller koji poziva traženu action metodu. Action metode u većini slučajeva sadrže pozive na metode loadLayout() i renderLayout(), koje učitavaju XML layout fajlove i vrše njihovu obradu. Na ovaj način kontroler ima minimalno učešće u organizaciji podataka za view.

Jedan tipičan zahtev izgledao bi ovako:

/public_html/shop/index.php(80):

Mage::run('store...', 'store')

 index.php pokreće metodu run() glavne Mage klase:

/app/Mage.php(640):

Mage_Core_Model_App->run(Array)

Mage_Core_Model_App između ostalog pokreće inicijalizaciju modula, nakon čega poziva metodu dispatch() Front kontrolera 

/app/code/local/Mage/Core/Model/App.php(348):

Mage_Core_Controller_Varien_Front->dispatch()

Traži se odgovarajući ruter koji preuzima dalji tok aplikacije

/app/code/core/Mage/Core/Controller/Varien/Front.php(176):

Mage_Core_Controller_Varien_Router_Standard->match(Object(Mage_Core_Controller_Request_Http)) 

Ruter traži odgovarajući kontroler, instancira se i postavljaju se modul, kontroler i akcija na request objekat:

/app/code/core/Mage/Core/Controller/Varien/Router/Standard.php(250):

Mage_Core_Controller_Varien_Action->dispatch('post')

Nakon što je u ovom slučaju nađen podrazumevani ruter, metoda dispatch() se poziva iz apstraktne klase Mage_Core_Controller_Varien_ Action koju nasleđuje Mage_Contacts_IndexController, a koji je tražen zahtevom iz ovog primera. Ona poziva svoje metode preDispatch() i postDispatch() između kojih se poziva i sama akcija.

app/code/local/Mage/Core/Controller/Varien/Action.php(420):

Mage_Contacts_IndexController->postAction()

Izvršava se kod definisan samom akcijom.

Etc

Kao što je već navedeno, svaki modul sadrži svoj folder “etc” u kojem se nalaze konfiguracioni XML fajlovi koji ga definišu.
Neka od podešavanja koja se mogu definisati su:

Modeli:

    
 
     
         Mage_Catalog_Model
         catalog_resource
     
 
 

Blokovi:

    
 
     
         Mage_Catalog_Block
     
 
 

Putanje (rute) ka kontrolerima:

    
 
     
         standard
         
             Mage_Catalog
             catalog
         
     
 
 

U okviru fajla config.xml se može definisati veliki broj podešavanja a, primera radi, navedeno je samo nekoliko.

Sql

Moduli mogu imati i svoje skripte za instalaciju koje se automatski pokreću nakon uključivanja modula. One se nalaze u folderu “sql” i mogu, u skladu sa verzijama modula, imati svoje verzije. U odgovarajućoj konfiguracionoj tabeli u bazi je upisano koji su moduli instalirani i koja je trenutna verzija.

 Template i layout fajlovi su odvojeni u folder “design”.

Template

Template fajlovi su HTML fajlovi sa ugrađenim PHP kodom za prikaz i nalaze se unutar foldera “template” u odgovarajućem folderu teme. Template (.phtml) je instanca bloka (tačnije kod iz ovog fajla je uključen u metodi fetchView() klase Mage_Core_Block_Template i poziva metode bloka na mestima na kojima je to potrebno.

Sledi jedan primer iteracije kroz rezultate blok metode u template-u: 

/app/design/frontend/enterprise/default/template/checkout/cart.phtml

foreach ($this--->getMethods('top_methods') as $method):
 if ($methodHtml = $this--->getMethodHtml($method)):

 
 

Layout

Layout je xml fajl koji definiše view strukturu. Poput template fajlova, razvrstani su po modulima. Sam layout je izdeljen pomoću takozvanih “handle” tagova čiji se naziv sklapa na osnovu ruta. Unutar handle tagova se nalaze reference tagovi u kojima su block tagovi koji definišu blokove i odgovarajuće šablone (templates).

Primer layout fajla:

/app/design/frontend/base/default/layout/contacts.xml

    
  
    
        
            contactstrue
        
    
 
    <contacts_index_index translate="label">
        
        
            
        
        
            page/2columns-right.phtml
            
        
        
            
        
    
 
 

Jedna od prednosti ovakve strukture je mogućnost pravljenja ugnježdenih elemenata unutar layout objekata.

Na primer:

/app/design/frontend/base/default/layout/checkout.xml

    
 
     
         
         1
     
 
 

Da bi odgovarajući template uključio svoj izvedeni (child) template potrebno je uraditi sledeće:

/app/design/frontend/base/default/template/checkout/onepage/login.phtml

 

Propratni delovi aplikacije vezani za frontend kao što su CSS i JS fajlovi nalaze se u folderu “skin”. Vredi napomenuti da Magento trenutno koristi biblioteku Prototype.

 

Konfiguracija

Da bi modul funkcionisao potrebna je i njegova konfiguracija u vidu XML fajla u folderu sa modulima:

/app/etc/modules/Some_Module.xml

   
 
    
        <some_module>
            true
            local
        
    
 
 

Smernice

Prikazali smo osnovnu strukturu Magento aplikacije. Objasnili smo osnovne pojmove i postavili temelj da u narednom periodu detaljno ispitamo pojedine delove najpopularnije PHP eCommerce platforme.

U međuvremenu možete pogledati sledeće sajtove:

Magento Knowledge Base

 

Alan Storm: Magento Articles for Professional Developers