Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Magento For Developers Part 1 - Introduction To Magento

Download as pdf or txt
Download as pdf or txt
You are on page 1of 8

Magento for Developers: Part 1Introduction to Magento

byAlanStorm,updatedforMagento1.12
EditthispageonGitHub

Other articles in this series:


Part1IntroductiontoMagento
Part2TheMagentoConfig
Part3MagentoControllerDispatch
Part4MagentoLayouts,BlocksandTemplates
Part5MagentoModelsandORMBasics
Part6MagentoSetupResources
Part7AdvancedORM:EntityAttributeValue
Part8VarienDataCollections
WhatisMagento?It'sthemostpowerfulonlineeCommerceplatformintheuniverseandischangingthefaceofeCommerceforever.:)
Ofcourse,youalreadyknowthat.WhatyoumaynotrealizeisMagento'salsoanobjectorientedPHPFrameworkthatcanbeusedtodevelop
modern,dynamicwebapplicationsthattapintoMagento'spowerfuleCommercefeatures.
Thisisthefirstinaseriesofarticlesinwhichwe'regoingtogoonawhirlwindtourofMagento'sprogrammingframeworkfeatures.Don'tworryif
youdon'tfolloweverythingimmediately.Asyoustudythesystemmoreeverythinginthisarticlewillstarttomakesense,andyou'llsoonbethe
envyofyourcolleaguesstuckworkingwithmoreprimitivePHPsystems.

In this article...
CodeOrganizedinModules
ConfigurationBasedMVC
Controllers
ContextBasedURIModelLoading
Models
Helpers
Layouts
Observers
ClassOverrides
WrapUp
OrforthemorevisuallyorientedMagento_MVC.pdf.

Code Organized in Modules


MagentoorganizesitscodeintoindividualModules.InatypicalPHPModelViewController(MVC)application,alltheControllerswillbeinone
folder,alltheModelsinanother,etc.InMagento,filesaregroupedtogetherbasedonfunctionality,whicharecalledmodulesinMagento.

Magento's Code
Forexample,you'llfindControllers,Models,Helpers,Blocks,etc.relatedtoMagento'scheckoutfunctionalityin
app/code/core/Mage/Checkout

You'llfindControllers,Models,Helpers,Blocks,etc.relatedtoMagento'sGoogleCheckoutfunctionalityin
app/code/core/Mage/GoogleCheckout

Your Code
WhenyouwanttocustomizeorextendMagento,ratherthaneditingcorefilesdirectly,orevenplacingyournewControllers,Models,Helpers,
Blocks,etc.nexttoMagentocode,you'llcreateyourownModulesin
app/code/local/Package/Modulename

Package(alsooftenreferredtoasaNamespace)isauniquenamethatidentifiesyourcompanyororganization.Theintentisthateachmember
oftheworldwideMagentocommunitywillusetheirownPackagenamewhencreatingmodulesinordertoavoidcollidingwithanotheruser's
code.
WhenyoucreateanewModule,youneedtotellMagentoaboutit.ThisisdonebyaddinganXMLfiletothefolder:
app/etc/modules

Therearetwokindsoffilesinthisfolder,thefirstenablesanindividualModule,andisnamedintheform:Packagename_Modulename.xml
ThesecondisafilethatwillenablemultipleModulesfromaPackage/Namespace,andisnamedintheform:Packagename_All.xml.Noteitis
onlyusedbythecoreteamwiththefileMage_All.xml.Itisnotrecommendedtoactivateseveralmodulesinasinglefile,asthisbreaksthe
modularityofyourmodules.

Configuration-Based MVC
MagentoisaconfigurationbasedMVCsystem.ThealternativetothiswouldaconventionbasedMVCsystem.
InaconventionbasedMVCsystem,ifyouwantedtoadd,say,anewControllerormaybeanewModel,you'djustcreatethefile/class,andthe
systemwouldpickitupautomatically.
Inaconfigurationbasedsystem,likeMagento,inadditiontoaddingthenewfile/classtothecodebase,youoftenneedtoexplicitlytellthe
systemaboutthenewclass,ornewgroupofclasses.InMagento,eachModulehasafilenamedconfig.xml.Thisfilecontainsalltherelevant
configurationforaMagentoModule.Atruntime,allthesefilesareloadedintoonelargeconfigurationtree.
Forexample,wanttouseModelsinyourcustomModule?You'llneedtoaddsomecodetoconfig.xmlthattellsMagentoyouwanttouse
Models,aswellaswhatthebaseclassnameforallyourModelsshouldbe.
<models>
<packagename>
<class>Packagename_Modulename_Model</class>
<packagename>
</models>

ThesamegoesforHelpers,Blocks,RoutesforyourControllers,EventHandlers,andmore.Almostanytimeyouwanttotapintothepowerof
theMagentosystem,you'llneedtomakesomechangeoradditiontoyourconfigfile.

Controllers
InanyPHPsystem,themainPHPentrypointremainsaPHPfile.Magentoisnodifferent,andthatfileisindex.php.
However,youneverCODEinindex.php.InanMVCsystem,index.phpwillcontaincode/callstocodethatdoesthefollowing:
1. ExaminestheURL
2. Basedonsomesetofrules,turnsthisURLintoaControllerclassandanActionmethod(calledRouting)
3. InstantiatestheControllerclassandcallstheActionmethod(calleddispatching)
ThismeansthepracticalentrypointinMagento(oranyMVCbasedsystem)isamethodinaControllerfile.ConsiderthefollowingURL:
http://example.com/catalog/category/view/id/25

Eachportionofthepathaftertheservernameisparsedasfollows.

Front Name - catalog


ThefirstportionoftheURLiscalledthefrontname.This,moreorless,tellsmagentowhichModuleitcanfindaControllerin.Intheabove
example,thefrontnameiscatalog,whichcorrespondstotheModulelocatedat:
app/code/core/Mage/Catalog

Controller Name - category


ThesecondportionoftheURLtellsMagentowhichControlleritshoulduse.EachModulewithControllershasaspecialfoldernamed
'controllers'whichcontainsalltheControllersforamodule.Intheaboveexample,theURLportioncategoryistranslatedintotheControllerfile
app/code/core/Mage/Catalog/controllers/CategoryController.php

Whichlookslike
classMage_Catalog_CategoryControllerextendsMage_Core_Controller_Front_Action
{
}

AllControllersintheMagentocartapplicationextendfromMage_Core_Controller_Front_Action.

Action Name - view


ThirdinourURListheactionname.Inourexample,thisis"view".Theword"view"isusedtocreatetheActionMethod.So,inourexample,
"view"wouldbeturnedinto"viewAction"
classMage_Catalog_CategoryControllerextendsMage_Core_Controller_Front_Action
{
publicfunctionviewAction()
{
//mainentrypoint
}
}

PeoplefamiliarwiththeZendFrameworkwillrecognizethenamingconventionhere.

Paramater/Value - id/25
Anypathportionsaftertheactionnamewillbeconsideredkey/valueGETrequestvariables.So,inourexample,the"id/25"meanstherewillget
aGETvariablenamed"id",withavalueof"25".
Aspreviouslymentioned,ifyouwantyourModuletouseControllers,you'llneedtoconfigurethem.Belowistheconfigurationchunkthat
enablesControllersfortheCatalogModule
<frontend>
<routers>
<catalog>
<use>standard</use>
<args>
<module>Mage_Catalog</module>
<frontName>catalog</frontName>
</args>
</catalog>
</routers>
</frontend>

Don'tworrytoomuchaboutthespecificsrightnow,butnoticethe<frontName>catalog</frontName>
ThisiswhatlinksaModulewithaURLfrontname.MostMagentocoreModuleschooseafrontnamethatisthesameastheirModulename,but
thisisnotrequired.

Multiple Routers
TheroutingdescribedaboveisfortheMagentocartapplication(oftencalledthefrontend).IfMagentodoesn'tfindavalidController/Actionfora
URL,ittriesagain,thistimeusingasecondsetofRoutingrulesfortheAdminapplication.IfMagentodoesn'tfindavalidAdmin
Controller/Action,itusesaspecialControllernamedMage_Cms_IndexController.
TheCMSControllerchecksMagento'scontentManagementsystemtoseeifthere'sanycontentthatshouldbeloaded.Ifitfindssome,itloads
it,otherwisetheuserwillbepresentedwitha404page.
Forexample,themainmagento"index"pageisonethatusestheCMSController,whichcanoftenthrownewcomersforaloop.

Context-Based URI Model Loading

Nowthatwe'reinourActionmethodentrypoint,we'llwanttostartinstantiatingclassesthatdothings.Magentooffersaspecialwayto
instantiateModels,HelpersandBlocksusingstaticfactorymethodsontheglobalMageclass.Forexample:
Mage::getModel('catalog/product');
Mage::helper('catalog/product');

Thestring'catalog/product'iscalledaGroupedClassName.It'salsooftencalledaURI.ThefirstportionofanyGroupedClassName(inthis
case,catalog),isusedtolookupwhichModuletheclassresidesin.Thesecondportion('product'above)isusedtodeterminewhichclass
shouldbeloaded.
So,inbothoftheexamplesabove,'catalog'resolvestotheModuleapp/code/core/Mage/Catalog.
MeaningourclassnamewillstartwithMage_Catalog.
Then,productisaddedtogetthefinalclassname
Mage::getModel('catalog/product');
Mage_Catalog_Model_Product
Mage::helper('catalog/product');
Mage_Catalog_Helper_Product

Theserulesareboundbywhat'sbeensetupineachModule'sconfigfile.WhenyoucreateyourowncustomModule,you'llhaveyourown
groupedclassnames(alsocallesclassgroups)toworkwithMage::getModel('myspecialprefix/modelname');.
Youdon'thavetouseGroupedClassNamestoinstantiateyourclasses.However,aswe'lllearnlater,therearecertainadvantagestodoing
so.

Magento Models
Magento,likemostframeworksthesedays,offersanObjectRelationalMapping(ORM)system.ORMsgetyououtofthebusinessofwriting
SQLandallowyoutomanipulateadatastorepurelythroughPHPcode.Forexample:
$model=Mage::getModel('catalog/product')>load(27);
$price=$model>getPrice();
$price+=5;
$model>setPrice($price)>setSku('SK83293432');
$model>save();

Intheaboveexamplewe'recallingthemethods"getPrice"and"setPrice"onourProduct.However,theMage_Catalog_Model_Productclass
hasnomethodswiththesenames.That'sbecauseMagento'sORMusesPHP'smagic__callmethodtoimplementgettersandsetters.
Callingthemethod$product>getPrice();will"get"theModelattribute"price".
Calling$product>setPrice();will"set"theModelattribute"price".AllofthisassumestheModelclassdoesn'talreadyhavemethodsnamed
getPriceorsetPrice.Ifitdoes,themagicmethodswillbebypassed.Ifyou'reinterestedintheimplementationofthis,checkoutthe
Varien_Objectclass,whichallModelsinheritfrom.
IfyouwantedtogetalltheavailabledataonaModel,call$product>getData();togetanarrayofalltheattributes.
You'llalsonoticeit'spossibletochaintogetherseveralcallstothesetmethod:
$model>setPrice($price)>setSku('SK83293432');
That'sbecauseeachsetmethodreturnsaninstanceoftheModel.Thisisapatternyou'llseeusedinmuchoftheMagentocodebase.
Magento'sORMalsocontainsawaytoqueryformultipleObjectsviaaCollectionsinterface.Thefollowingwouldgetusacollectionofall
productsthatcost$5.00
$products_collection=Mage::getModel('catalog/product')
>getCollection()
>addAttributeToSelect('*')
>addFieldToFilter('price','5.00');

Again,you'llnoticeMagento'simplementedachaininginterfacehere.CollectionsusethePHPStandardLibrarytoimplementObjectsthathave
arraylikeproperties.
foreach($products_collectionas$product)
{
echo$product>getName();
}

Youmaybewonderingwhatthe"addAttributeToSelect"methodisfor.MagentohastwobroadtypesofModelobjects.Oneisatraditional"One
Object,OneTable"ActiveRecordstyleModel.WhenyouinstantiatetheseModels,allattributesareautomaticallyselected.
ThesecondtypeofModelisanEntityAttributeValue(EAV)Model.EAVModelsspreaddataacrossseveraldifferenttablesinthedatabase.
ThisgivestheMagentosystemtheflexibilitytoofferitsflexibleproductattributesystemwithouthavingtodoaschemachangeeachtimeyou
addanattribute.WhencreatingacollectionofEAVobjects,Magentoisconservativeinthenumberofcolumnsitwillqueryfor,soyoucanuse
addAttributeToSelecttogetthecolumnsyouwant,oraddAttributeToSelect('*')togetallcolumns.

Helpers
Magento'sHelperclassescontainutilitymethodsthatwillallowyoutoperformcommontasksonobjectsandvariables.Forexample:
$helper=Mage::helper('catalog');
You'llnoticewe'veleftoffthesecondpartofthegroupedclassname.EachModulehasadefaultDataHelperclass.Thefollowingisequivalent
totheabove:
$helper=Mage::helper('catalog/data');
MostHelpersinheritformMage_Core_Helper_Abstract,whichgivesyouseveralusefulmethodsbydefault.
$translated_output=$helper>__('MagentoisGreat');//gettextstyletranslations
if($helper>isModuleOutputEnabled())://isoutputforthismoduleonoroff?

Layouts
So,we'veseenControllers,Models,andHelpers.InatypicalPHPMVCsystem,afterwe'vemanipulatedourModelswewould
1. Setsomevariablesforourview
2. Thesystemwouldloadadefault"outer"HTMLlayout>
3. Thesystemwouldthenloadourviewinsidethatouterlayout
However,ifyoulookatatypicalMagentoControlleraction,youdon'tseeanyofthis:
/**
*Viewproductgalleryaction
*/
publicfunctiongalleryAction()
{
if(!$this>_initProduct()){
if(isset($_GET['store'])&&!$this>getResponse()>isRedirect()){
$this>_redirect('');
}elseif(!$this>getResponse()>isRedirect()){
$this>_forward('noRoute');
}
return;
}
$this>loadLayout();
$this>renderLayout();
}

Instead,theControlleractionendswithtwocalls
$this>loadLayout();
$this>renderLayout();

So,the"V"inMagento'sMVCalreadydiffersfromwhatyou'reprobablyusedto,inthatyouneedtoexplicitlykickoffrenderingthelayout.
Thelayoutitselfalsodiffers.AMagentoLayoutisanobjectthatcontainsanested/treecollectionof"Block"objects.EachBlockobjectwill
renderaspecificbitofHTML.BlockobjectsdothisthroughacombinationofPHPcode,andincludingPHP.phtmltemplatefiles.
BlocksobjectsaremeanttointeractwiththeMagentosystemtoretrievedatafromModels,whilethephtmltemplatefileswillproducetheHTML
neededforapage.
Forexample,thepageheaderBlockapp/code/core/Mage/Page/Block/Html/Head.phpusesthehead.phtmlfilepage/html/head.phtml.
AnotherwayofthinkingaboutitistheBlockclassesarealmostlikelittleminicontrollers,andthe.phtmlfilesaretheview.
Bydefault,whenyoucall
$this>loadLayout();
$this>renderLayout();

MagentowillloadupaLayoutwithaskeletonsitestructure.TherewillbeStructureBlockstogiveyouyourhtml,head,andbody,aswellas
HTMLtosetupsingleormultiplecolumnsofLayout.Additionally,therewillbeafewContentBlocksforthenavigation,defaultwelcome
message,etc.
"Structure"and"Content"arearbitrarydesignationsintheLayoutsystem.ABlockdoesn'tprogrammaticallyknowifit'sStructureorContent,but
it'susefultothinkofaBlockasoneortheother.
ToaddContenttothisLayoutyouneedtotelltheMagentosystemsomethinglike
"Hey,Magento,addtheseadditionalBlocksunderthe"content"Blockoftheskeleton"

or
"Hey,Magento,addtheseadditionalBlocksunderthe"leftcolumn"Blockoftheskeleton"

ThiscanbedoneprogrammaticallyinaControlleraction
publicfunctionindexAction()
{
$this>loadLayout();
$block=$this>getLayout()>createBlock('adminhtml/system_account_edit')
$this>getLayout()>getBlock('content')>append($block);
$this>renderLayout();
}

butmorecommonly(atleastinthefrontendcartapplication),isuseoftheXMLLayoutsystem.
TheLayoutXMLfilesinathemeallowyou,onaperControllerbasis,toremoveBlocksthatwouldnormallyberendered,oraddBlockstothat
defaultskeletonareas.Forexample,considerthisLayoutXMLfile:
<catalog_category_default>
<referencename="left">
<blocktype="catalog/navigation"name="catalog.leftnav"after="currency"template="catalog/navigation/left.phtml"/>
</reference>
</catalog_category_default>

It'ssayinginthecatalogModule,inthecategoryController,andthedefaultAction,insertthecatalog/navigationBlockintothe"left"structure
Block,usingthecatalog/navigation/left.phtmltemplate.
OnelastimportantthingaboutBlocks.You'lloftenseecodeintemplatesthatlookslikethis:
$this>getChildHtml('order_items')
ThisishowaBlockrendersanestedBlock.However,aBlockcanonlyrenderachildBlockifthechildBlockisincludedasanestedBlockin
theLayoutXMLfile.Intheexampleaboveourcatalog/navigationBlockhasnonestedBlocks.Thismeansanycallto$this>getChildHtml()in
left.phtmlwillrenderasblank.
If,however,wehadsomethinglike:
<catalog_category_default>
<referencename="left">
<blocktype="catalog/navigation"name="catalog.leftnav"after="currency"template="catalog/navigation/left.phtml">
<blocktype="core/template"name="foobar"template="foo/baz/bar.phtml"/>
</block>
</reference>
</catalog_category_default>

Fromthecatalog/navigationBlock,we'dbeabletocall
$this>getChildHtml('foobar');

Observers
Likeanygoodobjectorientedsystem,MagentoimplementsanEvent/Observerpatternforenduserstohookinto.Ascertainactionshappen
duringaPagerequest(aModelissaved,auserlogsin,etc.),Magentowillissueaneventsignal.
WhencreatingyourownModules,youcan"listen"fortheseevents.Sayyouwantedtogetanemaileverytimeacertaincustomerloggedinto
thestore.Youcouldlistenforthe"customer_login"event(setupinconfig.xml)

<events>
<customer_login>
<observers>
<unique_name>
<type>singleton</type>
<class>mymodule/observer</class>
<method>iSpyWithMyLittleEye</method>
</unique_name>
</observers>
</customer_login>
</events>

andthenwritesomecodethatwouldrunwheneverauserloggedin:
classPackagename_Mymodule_Model_Observer
{
publicfunctioniSpyWithMyLittleEye($observer)
{
$data=$observer>getData();
//codetocheckobserverdataforouruser,
//andtakesomeactiongoeshere
}
}

Class Overrides
Finally,theMagentoSystemoffersyoutheabilitytoreplaceModel,HelperandBlockclassesfromthecoremoduleswithyourown.Thisisa
featurethat'ssimilarto"DuckTyping"or"MonkeyPatching"inalanguagelikeRubyorPython.
Here'sanexampletohelpyouunderstand.TheModelclassforaproductisMage_Catalog_Model_Product.
Wheneverthefollowingcodeiscalled,aMage_Catalog_Model_Productobjectiscreated
$product=Mage::getModel('catalog/product');

Thisisafactorypattern.
WhatMagento'sclassoverridesystemdoesisallowyoutotellthesystem
"Hey,wheneveranyoneasksforacatalog/product,insteadofgivingthemaMage_Catalog_Model_Product,
givethemaPackagename_Modulename_Model_Foobazproductinstead".

Then,ifyouwant,yourPackagename_Modulename_Model_Foobazproductclasscanextendtheoriginalproductclass
classPackagename_Modulename_Model_FoobazproductextendsMage_Catalog_Model_Product
{
}

Whichwillallowyoutochangethebehaviorofanymethodontheclass,butkeepthefunctionalityoftheexistingmethods.
classPackagename_Modulename_Model_FoobazproductextendsMage_Catalog_Model_Product
{
publicfunctionvalidate()
{
//addcustomvalidationfunctionalityhere
return$this;
}
}

Asyoumightexpect,thisoverriding(orrewriting)isdoneintheconfig.xmlfile.
<models>
<!doestheoverrideforcatalog/product>
<catalog>
<rewrite>
<product>Packagename_Modulename_Model_Foobazproduct</product>
</rewrite>

</catalog>
</models>

Onethingthat'simportanttonotehere.IndividualclassesinyourModuleareoverridingindividualclassesinotherModules.Youarenot,
however,overridingtheentireModule.ThisallowsyoutochangespecificmethodbehaviorwithouthavingtoworrywhattherestoftheModule
isdoing.

Wrap Up
Wehopeyou'veenjoyedthiswhirlwindtourofsomeofthefeaturestheMagentoeCommercesystemofferstodevelopers.Itcanbealittle
overwhelmingatfirst,especiallyifthisisyourfirstexperiencewithamodern,objectorientedPHPsystem.Ifyoustarttogetfrustrated,takea
deepbreath,remindyourselfthatthisisnew,andnewthingsarehard,butattheendofthedayit'sjustadifferentwayofcoding.Onceyouget
overthelearningcurveyou'llfindyourselfloathtoreturntoother,lesspowerfulsystems.

You might also like