_elementClass = Mage::getConfig()->getModelClassName('core/layout_element');
$this->setXml(simplexml_load_string('', $this->_elementClass));
$this->_update = Mage::getModel('core/layout_update');
parent::__construct($data);
}
/**
* Layout update instance
*
* @return Mage_Core_Model_Layout_Update
*/
public function getUpdate()
{
return $this->_update;
}
/**
* Set layout area
*
* @param string $area
* @return Mage_Core_Model_Layout
*/
public function setArea($area)
{
$this->_area = $area;
return $this;
}
/**
* Retrieve layout area
*
* @return string
*/
public function getArea()
{
return $this->_area;
}
/**
* Declaring layout direct output flag
*
* @param bool $flag
* @return Mage_Core_Model_Layout
*/
public function setDirectOutput($flag)
{
$this->_directOutput = $flag;
return $this;
}
/**
* Retrieve derect output flag
*
* @return bool
*/
public function getDirectOutput()
{
return $this->_directOutput;
}
/**
* Loyout xml generation
*
* @return Mage_Core_Model_Layout
*/
public function generateXml()
{
$xml = $this->getUpdate()->asSimplexml();
$removeInstructions = $xml->xpath("//remove");
if (is_array($removeInstructions)) {
foreach ($removeInstructions as $infoNode) {
$attributes = $infoNode->attributes();
$blockName = (string)$attributes->name;
if ($blockName) {
$ignoreNodes = $xml->xpath("//block[@name='".$blockName."']");
if (!is_array($ignoreNodes)) {
continue;
}
$ignoreReferences = $xml->xpath("//reference[@name='".$blockName."']");
if (is_array($ignoreReferences)) {
$ignoreNodes = array_merge($ignoreNodes, $ignoreReferences);
}
foreach ($ignoreNodes as $block) {
if ($block->getAttribute('ignore') !== null) {
continue;
}
$acl = (string)$attributes->acl;
if ($acl && Mage::getSingleton('admin/session')->isAllowed($acl)) {
continue;
}
if (!isset($block->attributes()->ignore)) {
$block->addAttribute('ignore', true);
}
}
}
}
}
$this->setXml($xml);
return $this;
}
/**
* Create layout blocks hierarchy from layout xml configuration
*
* @param Mage_Core_Layout_Element|null $parent
*/
public function generateBlocks($parent=null)
{
if (empty($parent)) {
$parent = $this->getNode();
}
foreach ($parent as $node) {
$attributes = $node->attributes();
if ((bool)$attributes->ignore) {
continue;
}
switch ($node->getName()) {
case 'block':
$this->_generateBlock($node, $parent);
$this->generateBlocks($node);
break;
case 'reference':
$this->generateBlocks($node);
break;
case 'action':
$this->_generateAction($node, $parent);
break;
}
}
}
/**
* Add block object to layout based on xml node data
*
* @param Varien_Simplexml_Element $node
* @param Varien_Simplexml_Element $parent
* @return Mage_Core_Model_Layout
*/
protected function _generateBlock($node, $parent)
{
if (!empty($node['class'])) {
$className = (string)$node['class'];
} else {
$className = (string)$node['type'];
}
$blockName = (string)$node['name'];
$_profilerKey = 'BLOCK: '.$blockName;
Varien_Profiler::start($_profilerKey);
$block = $this->addBlock($className, $blockName);
if (!$block) {
return $this;
}
if (!empty($node['parent'])) {
$parentBlock = $this->getBlock((string)$node['parent']);
} else {
$parentName = $parent->getBlockName();
if (!empty($parentName)) {
$parentBlock = $this->getBlock($parentName);
}
}
if (!empty($parentBlock)) {
$alias = isset($node['as']) ? (string)$node['as'] : '';
if (isset($node['before'])) {
$sibling = (string)$node['before'];
if ('-'===$sibling) {
$sibling = '';
}
$parentBlock->insert($block, $sibling, false, $alias);
} elseif (isset($node['after'])) {
$sibling = (string)$node['after'];
if ('-'===$sibling) {
$sibling = '';
}
$parentBlock->insert($block, $sibling, true, $alias);
} else {
$parentBlock->append($block, $alias);
}
}
if (!empty($node['template'])) {
$block->setTemplate((string)$node['template']);
}
if (!empty($node['output'])) {
$method = (string)$node['output'];
$this->addOutputBlock($blockName, $method);
}
Varien_Profiler::stop($_profilerKey);
return $this;
}
/**
* Enter description here...
*
* @param Varien_Simplexml_Element $node
* @param Varien_Simplexml_Element $parent
* @return Mage_Core_Model_Layout
*/
protected function _generateAction($node, $parent)
{
if (isset($node['ifconfig']) && ($configPath = (string)$node['ifconfig'])) {
if (!Mage::getStoreConfigFlag($configPath)) {
return $this;
}
}
$method = (string)$node['method'];
if (!empty($node['block'])) {
$parentName = (string)$node['block'];
} else {
$parentName = $parent->getBlockName();
}
$_profilerKey = 'BLOCK ACTION: '.$parentName.' -> '.$method;
Varien_Profiler::start($_profilerKey);
if (!empty($parentName)) {
$block = $this->getBlock($parentName);
}
if (!empty($block)) {
$args = (array)$node->children();
unset($args['@attributes']);
foreach ($args as $key => $arg) {
if (($arg instanceof Mage_Core_Model_Layout_Element)) {
if (isset($arg['helper'])) {
$helperName = explode('/', (string)$arg['helper']);
$helperMethod = array_pop($helperName);
$helperName = implode('/', $helperName);
$arg = $arg->asArray();
unset($arg['@']);
$args[$key] = call_user_func_array(array(Mage::helper($helperName), $helperMethod), $arg);
} else {
/**
* if there is no helper we hope that this is assoc array
*/
$arr = array();
foreach($arg as $subkey => $value) {
$arr[(string)$subkey] = $value->asArray();
}
if (!empty($arr)) {
$args[$key] = $arr;
}
}
}
}
if (isset($node['json'])) {
$json = explode(' ', (string)$node['json']);
foreach ($json as $arg) {
$args[$arg] = Mage::helper('core')->jsonDecode($args[$arg]);
}
}
$this->_translateLayoutNode($node, $args);
call_user_func_array(array($block, $method), $args);
}
Varien_Profiler::stop($_profilerKey);
return $this;
}
/**
* Translate layout node
*
* @param Varien_Simplexml_Element $node
* @param array $args
**/
protected function _translateLayoutNode($node, &$args)
{
if (isset($node['translate'])) {
// Translate value by core module if module attribute was not set
$moduleName = (isset($node['module'])) ? (string)$node['module'] : 'core';
// Handle translations in arrays if needed
$translatableArguments = explode(' ', (string)$node['translate']);
foreach ($translatableArguments as $translatableArgumentName) {
/*
* .(dot) character is used as a path separator in nodes hierarchy
* e.g. info.title means that Magento needs to translate value of
node
* that is a child of node
*/
// @var $argumentHierarhy array - path to translatable item in $args array
$argumentHierarchy = explode('.', $translatableArgumentName);
$argumentStack = &$args;
$canTranslate = true;
while (is_array($argumentStack) && count($argumentStack) > 0) {
$argumentName = array_shift($argumentHierarchy);
if (isset($argumentStack[$argumentName])) {
/*
* Move to the next element in arguments hieracrhy
* in order to find target translatable argument
*/
$argumentStack = &$argumentStack[$argumentName];
} else {
// Target argument cannot be found
$canTranslate = false;
break;
}
}
if ($canTranslate && is_string($argumentStack)) {
// $argumentStack is now a reference to target translatable argument so it can be translated
$argumentStack = Mage::helper($moduleName)->__($argumentStack);
}
}
}
}
/**
* Save block in blocks registry
*
* @param string $name
* @param Mage_Core_Model_Layout $block
*/
public function setBlock($name, $block)
{
$this->_blocks[$name] = $block;
return $this;
}
/**
* Remove block from registry
*
* @param string $name
*/
public function unsetBlock($name)
{
$this->_blocks[$name] = null;
unset($this->_blocks[$name]);
return $this;
}
/**
* Block Factory
*
* @param string $type
* @param string $name
* @param array $attributes
* @return Mage_Core_Block_Abstract
*/
public function createBlock($type, $name='', array $attributes = array())
{
try {
$block = $this->_getBlockInstance($type, $attributes);
} catch (Exception $e) {
Mage::logException($e);
return false;
}
if (empty($name) || '.'===$name{0}) {
$block->setIsAnonymous(true);
if (!empty($name)) {
$block->setAnonSuffix(substr($name, 1));
}
$name = 'ANONYMOUS_'.sizeof($this->_blocks);
} elseif (isset($this->_blocks[$name]) && Mage::getIsDeveloperMode()) {
//Mage::throwException(Mage::helper('core')->__('Block with name "%s" already exists', $name));
}
$block->setType($type);
$block->setNameInLayout($name);
$block->addData($attributes);
$block->setLayout($this);
$this->_blocks[$name] = $block;
Mage::dispatchEvent('core_layout_block_create_after', array('block'=>$block));
return $this->_blocks[$name];
}
/**
* Add a block to registry, create new object if needed
*
* @param string|Mage_Core_Block_Abstract $blockClass
* @param string $blockName
* @return Mage_Core_Block_Abstract
*/
public function addBlock($block, $blockName)
{
return $this->createBlock($block, $blockName);
}
/**
* Create block object instance based on block type
*
* @param string $block
* @param array $attributes
* @return Mage_Core_Block_Abstract
*/
protected function _getBlockInstance($block, array $attributes=array())
{
if (is_string($block)) {
if (strpos($block, '/')!==false) {
if (!$block = Mage::getConfig()->getBlockClassName($block)) {
Mage::throwException(Mage::helper('core')->__('Invalid block type: %s', $block));
}
}
if (class_exists($block, false) || mageFindClassFile($block)) {
$block = new $block($attributes);
}
}
if (!$block instanceof Mage_Core_Block_Abstract) {
Mage::throwException(Mage::helper('core')->__('Invalid block type: %s', $block));
}
return $block;
}
/**
* Retrieve all blocks from registry as array
*
* @return array
*/
public function getAllBlocks()
{
return $this->_blocks;
}
/**
* Get block object by name
*
* @param string $name
* @return Mage_Core_Block_Abstract
*/
public function getBlock($name)
{
if (isset($this->_blocks[$name])) {
return $this->_blocks[$name];
} else {
return false;
}
}
/**
* Add a block to output
*
* @param string $blockName
* @param string $method
*/
public function addOutputBlock($blockName, $method='toHtml')
{
//$this->_output[] = array($blockName, $method);
$this->_output[$blockName] = array($blockName, $method);
return $this;
}
public function removeOutputBlock($blockName)
{
unset($this->_output[$blockName]);
return $this;
}
/**
* Get all blocks marked for output
*
* @return string
*/
public function getOutput()
{
$out = '';
if (!empty($this->_output)) {
foreach ($this->_output as $callback) {
$out .= $this->getBlock($callback[0])->$callback[1]();
}
}
return $out;
}
/**
* Retrieve messages block
*
* @return Mage_Core_Block_Messages
*/
public function getMessagesBlock()
{
$block = $this->getBlock('messages');
if ($block) {
return $block;
}
return $this->createBlock('core/messages', 'messages');
}
/**
* Enter description here...
*
* @param string $type
* @return Mage_Core_Helper_Abstract
*/
public function getBlockSingleton($type)
{
if (!isset($this->_helpers[$type])) {
$className = Mage::getConfig()->getBlockClassName($type);
if (!$className) {
Mage::throwException(Mage::helper('core')->__('Invalid block type: %s', $type));
}
$helper = new $className();
if ($helper) {
if ($helper instanceof Mage_Core_Block_Abstract) {
$helper->setLayout($this);
}
$this->_helpers[$type] = $helper;
}
}
return $this->_helpers[$type];
}
/**
* Retrieve helper object
*
* @param string $name
* @return Mage_Core_Helper_Abstract
*/
public function helper($name)
{
$helper = Mage::helper($name);
if (!$helper) {
return false;
}
return $helper->setLayout($this);
}
/**
* Lookup module name for translation from current specified layout node
*
* Priorities:
* 1) "module" attribute in the element
* 2) "module" attribute in any ancestor element
* 3) layout handle name - first 1 or 2 parts (namespace is determined automatically)
*
* @param Varien_Simplexml_Element $node
* @return string
*/
public static function findTranslationModuleName(Varien_Simplexml_Element $node)
{
$result = $node->getAttribute('module');
if ($result) {
return (string)$result;
}
foreach (array_reverse($node->xpath('ancestor::*[@module]')) as $element) {
$result = $element->getAttribute('module');
if ($result) {
return (string)$result;
}
}
foreach ($node->xpath('ancestor-or-self::*[last()-1]') as $handle) {
$name = Mage::getConfig()->determineOmittedNamespace($handle->getName());
if ($name) {
return $name;
}
}
return 'core';
}
}