Mage_Core_Model_Design_Package
We have used this class many times to get theme files but have not checked what is inside yet. So, let’s see if there is anything interesting there to learn.
These is where we previously met this class:
1. Mage_Core_Model_Layout_Update :: fetchFileLayoutUpdates()
2. Mage_Core_Model_Layout_Update :: getFileLayoutUpdatesXml()
3. Mage_Core_Controller_Varien_Action :: addActionLayoutHandles()
4. Mage_Core_Model_Resource_Layout :: fetchUpdatesByHandle()
5. Mage_Core_Block_Template :: getTemplateFile()
6. Mage_Core_Block_Abstract :: getSkinUrl()
Here I have put down the functions which have been used in:
1. 2. 3. 4.
Mage_Core_Model_Design_Package :: getArea() , as well as getPackageName() and getTheme($type)
These are some of the described constants:
DEFAULT_AREA = ‘frontend’;
DEFAULT_PACKAGE = ‘default’;
DEFAULT_THEME = ‘default’;
- getArea
1 2 3 4 5 6 7 |
public function getArea() { if (is_null($this->_area)) { $this->_area = self::DEFAULT_AREA; } return $this->_area; } |
The focus of our attention are the ‘frontend’ themes. As we see the constant DEFAULT_AREA already has the required value. If need to change it, there is the function setArea($area), which can be launched, for example, from observer: “controller_action_predispatch ”.
- getPackageName
1 2 3 4 5 6 7 |
public function getPackageName() { if (null === $this->_name) { $this->setPackageName(); } return $this->_name; } |
Here we see that if Package has not been installed yet, there is launched the function setPackageName(); which we worked with in the first part of the article. It was a bit modified there, but originally it looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public function setPackageName($name = '') { if (empty($name)) { $this->_name = $this->_checkUserAgentAgainstRegexps('design/package/ua_regexp'); if (! $this->_name) { $this->_name = Mage::getStoreConfig('design/package/name', $this->getStore()); } } else { $this->_name = $name; } if (!$this->designPackageExists($this->_name, $this->getArea())) { $this->_name = self::DEFAULT_PACKAGE; } return $this; } |
The function sets the package name to search for theme files in future.
– If the function argument has been specified then the package name is defined by the argument value.
– Otherwise it will check for Exeption via the function _checkUserAgentAgainstRegexps . For instance, we can set names of mobile devices and a package with a mobile theme. All this will be checked and if some of the listed devices are found as being used, then the name of the specific mobile theme package gets defined.
– If using the above parameters we still do not get the name, then take it directly from getStoreConfig(‘design/package/name’).
After the name has been defined, the existence of the relevant folder is verified. If the folder does not exist, then the default name is set.
- getTheme
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public function getTheme($type) // type are "locale", "layout", "template", "skin", "default" { if (empty($this->_theme[$type])) { $this->_theme[$type] = Mage::getStoreConfig('design/theme/'.$type, $this->getStore()); if ($type!=='default' && empty($this->_theme[$type])) { $this->_theme[$type] = $this->getTheme('default'); if (empty($this->_theme[$type])) { $this->_theme[$type] = self::DEFAULT_THEME; } } } $customThemeType = $this->_checkUserAgentAgainstRegexps("design/theme/{$type}_ua_regexp"); if ($customThemeType) { $this->_theme[$type] = $customThemeType; } return $this->_theme[$type]; } |
The same as in the previous 2 functions, here it is verified if the current theme has been already defined.
Specific theme folder name can be individually set for several types: “locale”, “layout”, “template”, “skin”. There is one more type which sets default values for all ”default”s above.
Taking a look at the function getTheme it is possible to describe which of the settings have higher priorities.
– At the end we see that if Exeption has been defined then the function replaces previous values and returns the Exeption value.
– Primarily it is verified if the theme value has been previously defined.
– If theme has not been defined yet, then next comes the verification for the relevant type in getStoreConfig(‘design/theme/’ . $type)
– If nothing has been defined there as well, then the function getTheme(‘default’) is called.
– In case still noting is found, then just use the constant self::DEFAULT_THEME
As you see, all three functions verify if the value has been already defined and yet there hasn’t been any single access to the admin settings under System / Design. While in the very first part of the article it was said that exactly these settings have maximum priority ( not taking into account the influence of Exception for Theme and the function we rewrote in the first part which prioritized Exeption for Package). The conclusion is obvious. During the web page initialization there is code which primarily influences the values of the class variables.
1 2 3 4 5 |
Mage_Core_Model_Design_Package { $this->_area $this->_name $this->_theme } |
Where is this code located?
Mage_Core_Controller_Varien_Action :: preDispatch()
1 2 3 4 5 6 |
public function preDispatch() { ... Mage::app()->loadArea($this->getLayout()->getArea()); ... } |
So the default area has been set.
1 2 3 4 5 |
public function loadArea ($code) { $this->getArea($code)->load(); // Mage_Core_Model_App_Area :: load() return $this; } |
When describing load, I will combine some of the functions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public function load($part=null) { ... $this->_loadPart(self::PART_DESIGN) { ... $designPackage = Mage::getSingleton('core/design_package'); ... $currentStore = Mage::app()->getStore()->getStoreId(); $designChange = Mage::getSingleton('core/design')->loadChange($currentStore); if ($designChange->getData()) { $designPackage->setPackageName($designChange->getPackage()); $designPackage->setTheme($designChange->getTheme()); } } $this->_loadPart(self::PART_TRANSLATE) { Mage::app()->getTranslator()->init($area) { ... $this->_loadThemeTranslation() { ... $file = Mage::getSingleton('core/design_package')->getLocaleFileName('translate.csv'); ... } ... } } ... |
Now all is in its place.
Mage::getSingleton(‘core/design’)->loadChange($currentStore);
We load the design changes saved in the admin panel under System / Design and in case there were any – set Package and Theme values inside the object Mage_Core_Model_Design_Package. Now it is possible to use the function getTheme, which will return the theme specified under System / Design or use admin panel settings System / Configuration / General /Design. This is what developers use when launching the file initialization and translating the translate.csv file, which is defined only for the current theme.
5.
Mage_Core_Model_Design_Package :: getTemplateFilename ($this->getTemplate(), $params);
There are 3 similar functions used to get a link to a specific template, locale or layout file.\
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public function getLayoutFilename($file, array $params=array()) { $params['_type'] = 'layout'; return $this->getFilename($file, $params); } public function getTemplateFilename($file, array $params=array()) { $params['_type'] = 'template'; return $this->getFilename($file, $params); } public function getLocaleFileName($file, array $params=array()) { $params['_type'] = 'locale'; return $this->getFilename($file, $params); } |
This makes sense, because the path to the file differs with one folder only. As an example lets try to get a template file path.
$params[‘_type’] = ‘template’;
1 2 3 4 5 6 7 8 9 10 11 12 |
public function getFilename($file, array $params) { ... $this->updateParamDefaults($params); $result = $this->_fallback($file, $params, array( array(), array('_theme' => $this->getFallbackTheme()), array('_theme' => self::DEFAULT_THEME), )); ... return $result; } |
The function updateParamDefaults($params) fills the array $params with additional values such as:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
if ($this->getStore()) { $params['_store'] = $this->getStore(); } if (empty($params['_area'])) { $params['_area'] = $this->getArea(); } if (empty($params['_package'])) { $params['_package'] = $this->getPackageName(); } if (empty($params['_theme'])) { $params['_theme'] = $this->getTheme( (isset($params['_type'])) ? $params['_type'] : '' ); } if (empty($params['_default'])) { $params['_default'] = false; } |
And then it is only needed to put them into the line in the right order. But the function _fallback() does not do only that. Before exposing the code of the function, let us take a closer look at the parameters, which are passed inside.
- $file – is a file template used in layout. For instance ‘catalog/product/view.phtml’
- $params – an array of this type:
1 2 3 4 5 6 7 8 9 |
Array ( [_type] => template [_store] => Mage_Core_Model_Store Object [_area] => frontend [_package] => air [_theme] => christmas [_default] => FALSE ) |
This is the data of our current theme, type of the file and the object of the current store. This would be enough if there was no theme file inheritance. For this reason there exists the following passed parameter.
- 3-rd parameter: Array. I will show the values the same way I did in the first part of the article.
1 2 3 4 5 |
Array( array(), array('_theme' => $this->getFallbackTheme()), // Mage::getStoreConfig('design/theme/default') array('_theme' => self::DEFAULT_THEME), ) |
In our case we get an array with the following values:
1 2 3 4 5 |
Array( array(), array('_theme' =>’air’, array('_theme' => ‘default’, ) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
protected function _fallback($file, array &$params, array $fallbackScheme = array(array())) { if ($this->_shouldFallback) { foreach ($fallbackScheme as $try) { $params = array_merge($params, $try); $filename = $this->validateFile($file, $params); if ($filename) { return $filename; } } $params['_package'] = self::BASE_PACKAGE; $params['_theme'] = self::DEFAULT_THEME; } return $this->_renderFilename($file, $params); } |
Checking all the values of the array $fallbackScheme. combining the content with the array $params. Checking for and verify the received file and if not found – move on to the next element $fallbackScheme. If we reach the end of the function, this means our template has not been found anywhere. Then there is the last option left:
$params[‘_package’] = self::BASE_PACKAGE; // base
$params[‘_theme’] = self::DEFAULT_THEME; // default
Primarily Magento will check for the template here | app/design/frontend/air/christmas/catalog/product/view.phtml |
If the template is not found, will continue here | app/design/frontend/air/air/catalog/product/view.phtml |
and then, if necessary, here | app/design/frontend/air/default/catalog/product/view.phtml |
If no template found it will return this variant | app/design/frontend/base/dafault/catalog/product/view.phtml |
1 2 3 4 5 6 7 8 9 |
public function validateFile($file, array $params) { $fileName = $this->_renderFilename($file, $params); $testFile = (empty($params['_relative']) ? '' : Mage::getBaseDir('design') . DS) . $fileName; if (!file_exists($testFile)) { return false; } return $fileName; } |
6.
Mage_Core_Model_Design_Package :: getSkinUrl($file, $params);
Here it is the same as in point 5 – just made as a separate function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public function getSkinUrl($file = null, array $params = array()) { ... $params['_type'] = 'skin'; ... $this->updateParamDefaults($params); if (!empty($file)) { $result = $this->_fallback($file, $params, array( array(), array('_theme' => $this->getFallbackTheme()), array('_theme' => self::DEFAULT_THEME), )); } $result = $this->getSkinBaseUrl($params) . (empty($file) ? '' : $file); ... } |