finding your way: understanding magento code
DESCRIPTION
With millions of lines of code, an unconventional approach to MVC framework architecture, and unique concepts such as layout XML, Magento can be intimidating for the new developer and even difficult for experienced Magento developers. This talk aims to help developers find answers in the codebase by breaking down the technologies, design patterns, and module structure into intuitive chunks. Starting with a high level view of Magento's MVC implementation, a pre-developed module is dissected in order to demonstrate various areas of the framework as well as the application-level settings and features which can thwart (or aide!) developers. Topics covered include the following: * MVC theory as implemented by Magento, especially the thin-controller, fat-view concept * Overall module architecture * Finding method definitions when grep won't work, aka "when __call() strikes" * Identifying poor-performing code using native code profiling tools * An infallible (well, nearly-infallible) flowchart for finding problematic code * Essential developer preparationsTRANSCRIPT
{Finding Your Way
Understanding Magento Code // @benmarks
https://joind.in/talk/view/8147
Ben Marks4.5 years doing Magento dev2 years as a Magento U instructorHappily employed at Blue Acorn in
Charleston, SC (we're hiring!)Big fan of questions (ask away)
Who am I?
Who knows Magento?
Who are you?
Who knows Magento?Who hates Magento?
Who are you?
Who knows Magento?Who hates Magento?Who doesn't know Magento, but has
been told that they should hate it?
Who are you?
Who knows Magento?Who hates Magento?Who doesn't know Magento, but has
been told that they should hate it?
"Magento doesn't do anything very well" –Harper Reed, php|tek, 2013
Who are you?
ZF1-based MVC frameworkeCommerce ApplicationAnswer to osCommerce
What is Magento?
LOTS of businessLOTS of developer community
membersLOTS of room for innovationLOTS of flexibilityLayout XML
What makes Magento awesome?
LOTS of undocumented features & conventions
LOTS of bad information out thereLOTS of architecture to scaleLOTS of flexibilityLayout XML
What makes Magento difficult?
Supressed error output (index.php):
Caching on by default (Admin Panel):
Disabled output (admin), disabled local code pool (app/etc/local.xml)
Getting Started: Don't Forget!
Declaration: app/etc/modules/Code pool*Type-specific foldersTheme assets
Modules & Module Structure
Declaration: app/etc/modules/
Points to app/code/core/Mage/Connect/etc/config.xml
All modules have config, and all config is merged
Modules & Module Structure
Typical classname-to-path mapping, e.g.:
See app/Mage.php & lib/Varien/Autoload.php:app/code/local/, app/code/community/, app/code/core/, lib/
But... Magento is "all about options," so...
Typical Autoloading
Mage_Catalog_Model_Product_TypeMage/Catalog/Model/Product/Type.php
Reading class group notation
Mage::getModel('catalog/product_type')
<config>
<global>
<models>
<catalog>
<class>Mage_Catalog_Model
Factory Methods & Class Groups
Allows for rewrites:
Mage::getModel('catalog/product_type')
<config>
<global>
<models>
<catalog>
<rewrite>
<product_type>New_Class
Factory Methods & Class Groups
Mage::getModel()
Mage::helper()* Mage::app()->getLayout()->createBlock()
See Mage_Core_Model_Config ::getGroupedClassName()
That's the M, V, and H... but C works differently
Factory Methods & Class Groups
Standard route matching:http://tek13.dev/catalog/product/view/id/51
frontName / controller / action
SEF rewrites: core_url_rewrite table
Controllers
Similar cofiguration-based approach, e.g.:
Mage/Catalog/etc/config.xml
Maps to Mage/Catalog/controllers/Note: not autoloaded
Controllers
Class rewrite/additional route configuration:
Maps to Custom/Module/controllers/
Controllers
Mage_Core_Model_LayoutFactory method for instantiating
blocksGlobal block registryEffectively a singleton, accessed via:
$controller->getLayout()Mage::app()->getLayout()$block->getLayout()
The View: Layout Object
Blocks have two main workflowsInstantiation: _construct() & _prepareLayout()
Rendering: toHtml(), _beforeToHtml(), _afterToHtml()
Blocks are generally responsible for instantiating data models/collections – important for view flexibility
The View: Blocks
Rendering is a waterfall down parent-child relationships:
$parentBlock->getChildHtml('child');
$child->getChildHtml('etc');
//and so forth...
The View: Blocks
How do blocks get called in to scope for rendering? In other words, how does stuff get rendered?
The View: Blocks
Layout XML - up to the developer to use, not use, mix as needed; keep controllers thin!
The View: Layout XML
Layout XML - up to the developer to use, not use, mix as needed; keep controllers thin!
public function exampleAction()
{
$this->loadLayout()->renderLayout();
//$this->getResponse()->setBody('Hi!');
}
The View: Layout XML
Declared in module config.xml; all module layout XML files are compiled always
Layout Update Handles are responsible for limiting the directives for current scope
Full Action Name handle – the missing link
The View: Layout XML
<contacts_index_index /><block /> - type, name, as, template<reference /> - name<remove /> - name<update /> - handle<action /> - methodaction allows to call block public
methods
The View: Layout XML
Layout update handles: applied via PHP; top-level nodes in layout XML files
Block type is class group notation: <block type="page/html_head"> <action method="addJs">
<file>example.js</file>
Mage_Page_Block_Html_Head->addJs('example.js');
The View: Layout XML
Parent-child relationships are established via markup in layout XML...
The View: Layout XML
...and this relationship is seen in templates as well:
Required for rendering to work
The View: Layout XML
Parent-child block relationships can also be set/unset using <action />:
<reference name="root">
<action method="unsetChild">
<child>content</child>
</action>
</reference>
Child exists, but "outside" of rendering flow
The View: Layout XML
Most important thing to understand:
Via layout XML any module can affect any view through the full action name handle or other applied handle (customer_logged_in, etc.)
Let's see some examples from catalog.xml
The View: Layout XML
Config XML is composed of the following:app/etc/*.xmlapp/etc/modules/*.xmlAll active module config.xmlapp/etc/local.xmlcore_config_data table
Configuration XML
Confusingly accessed/evaluated/built; better to learn it by application
Important top level nodes:global frontend & adminhtmladmin default, websites, & stores; often, user-
configurable values here
Configuration XML
Website and store scopes are admin-configurable, but affect config DOM structure (System > Manage Stores)
Possible to declare same xpaths in multiple files and in core_config_data table* (*for default, websites, and stores)
Colliding xpath text values are overwritten when merged
Configuration XML
Convenience method for reading correct value for store scopes
Mage::getStoreConfig('foo/bar/baz');
//same as...
Mage::getConfig()->getNode(
'stores/[code]/foo/bar/baz'
);
Configuration XML
Sometimes it's the node name being evaluated (e.g. module declaration); most of the time it's the text node
Bottom line, it's all about the xpath and the PHP which is evaluating it
Configuration XML
System XML is the quickest way to add user-configurable fields to the admin panel
Default values can be set in files or added to core_config_data via setup scripts
Let's look at Mage/Contacts/etc/system.xml
System XML
Magento CRUD:Create & Update: save()Read: load()Delete: delete()
Data model CRUD works through resource model (see Mage_Core_Model_Abstract)
The Model Layer: CRUD
Hybrid resource / data model classesFiltering, sorting, etc. Lazy loaded.Implement Countable &
IteratorAggregate, making it possible to do this:
The Model Layer: Collections
Generally the best way to customizeEvents are dispatched throughout core
codeAllow to execute code uniformly (e.g.
during request dispatching) or during specific flow of execution (catalog_product_load_after)
Observers
Varien_Object (lib/Varien/Object.php)Basis of blocks and models; for
models, methods map to table columns or attributes
get*, set*, uns*, & has*
$model->getFooBar()
reads from
$model->_data['foo_bar']
Missing code: when __call strikes
Caveat: nothing stops classes from defining getters, setters, etc.
Don't var_dump() objects directly; use Varien_Object->debug() to see properties in _data
Missing code: when __call strikes
The action and the template are the most important aspects to deciphering layout XML; not all blocks use template!
Find the block class via typeCheck the definition to see if the method
is declared or notA simple echo get_class($this) in the
template will suffice
Missing code: layout XML
Observer configuration can be found mainly under the xpaths global/events, frontend/events, and adminhtml/events
Many events are dynamicMultiple observers can be configured
for the same event
Missing code: Observers
When an install is not behaving as expected, check for Mage, Varien, and Zend namespaces outside of core or lib
Check for event observer configuration for targeted CRUD and reques operations
Missing code: Miscellaneous
When content is being rendered with no apparent source in template or entity data, suspect translations, which can reside in translate.csv, app/locale/, or core_translate table; translate="" & __("Some String")
CMS pages, categories, and products all have custom design settings (themes & layout XML) which are stored in the database
Missing code: Miscellaneous
Module code not executing.
Is config being merged? Enable developer mode & clear cache. Error message indicates everything is ok. 80% of all problems start with config.*
Troubleshooting Process
Unexpected or missing theme-related content.
Reset the theme to default to rule out issues from custom templates & layout XML; check database for layout XML, template, and theme settings. Check parent-child relationships.
Troubleshooting Process
Class XYZ is not behaving correctly.
Check for a config-based rewrite, an include path override, or an event observer.
Collection class/view seems to be slow.
Ensure that the collection class is building correct data and that models are not being loaded iteratively.
Troubleshooting Process
Enable profiler in two places:System > Configuration > Developer index.php - uncomment Varien_Profiler::enable()
Rudimentary output; read from outside-in till you get to the bottom-most entry with longest execution time
Enable query profiler in config xml atglobal/resources/default_setup/connection/profiler
Profiler
Enable TPH in admin: System > Configuraration > Developer Change scope from "Default"
Pretty ugly, and missing key info (such as alias, name). Check out AOE_TemplateHints v2.0 http://www.fabrizio-branca.de/magento-advanced-template-hints-20.html
Template Path Hints
http://stackoverflow.com/questions/tagged/magento
http://magento.stackexchange.com/ http://alanstorm.com/http://magebase.com/http://www.fabrizio-branca.de/magento
-modules.htmlhttp://blueacorn.com/
Resources
Magicento plugin for PhpStormhttp://magicento.com/
n98-magerun:https://github.com/netz98/n98-magerun
Feedback:https://joind.in/talk/view/8147
Resources