/** * Compiles the XML attribute which may contain some dynamic data. * The method automatically recognizes the registered expression * engine and launches it. * * @param Opt_Xml_Attribute $attr The attribute to parse. */ public function compileAttribute(Opt_Xml_Attribute $attr) { $value = $attr->getValue(); if (preg_match('/^([a-zA-Z0-9\\_]+)\\:([^\\:].*)$/', $value, $found)) { switch ($found[1]) { case 'parse': $result = $this->parseExpression($found[2], $found[1], self::ESCAPE_ON, $this->_tpl->attributeModifier); $attr->addAfter(Opt_Xml_Buffer::ATTRIBUTE_VALUE, 'echo ' . $result['expression'] . '; '); break; case 'str': $result = $this->parseExpression($found[2], $found[1], self::ESCAPE_ON, $this->_tpl->attributeModifier); $attr->addAfter(Opt_Xml_Buffer::ATTRIBUTE_VALUE, 'echo ' . $result['escaped'] . '; '); break; case null: $attr->setValue($found[2]); break; } } }
/** * Processes the opt:attribute instruction tag. * @internal * @param Opt_Xml_Node $node XML node. */ public function processNode(Opt_Xml_Node $node) { $params = array('name' => array(0 => self::REQUIRED, self::EXPRESSION, null, 'parse'), 'value' => array(0 => self::OPTIONAL, self::EXPRESSION, null, 'parse'), 'ns' => array(0 => self::OPTIONAL, self::EXPRESSION, null, 'parse')); $this->_extractAttributes($node, $params); self::$_cnt++; $parent = $node->getParent(); $returnStyle = $node->get('attributeValueStyle'); $returnStyle = is_null($returnStyle) ? self::ATTR_DISPLAY : $returnStyle; if ($returnStyle == self::ATTR_DISPLAY) { if (!$node->getParent() instanceof Opt_Xml_Element) { throw new Opt_InstructionInvalidParent_Exception('opt:attribute', 'printable tag'); } $parentName = $node->getParent()->getXmlName(); if (($this->_compiler->isInstruction($parentName) || $this->_compiler->isComponent($parentName) || $this->_compiler->isBlock($parentName)) && $node->getParent()->get('call:attribute-friendly') === null) { throw new Opt_InstructionInvalidParent_Exception('opt:attribute', 'printable tag'); } // This is a bit tricky optimization. If the name is constant, there is no need to process it as a variable name. // If the name is constant, the result must contain only a string if ($params['ns'] !== null) { $trNamespace = trim($params['ns'], '\' '); if (!(substr_count($params['ns'], '\'') == 2 && substr_count($trNamespace, '\'') == 0 && $this->_compiler->isIdentifier($trNamespace))) { unset($trNamespace); } } // Using the same tricky optimization for names $trName = trim($params['name'], '\' '); if (!(substr_count($params['name'], '\'') == 2 && substr_count($trName, '\'') == 0 && $this->_compiler->isIdentifier($trName))) { unset($trName); } if (isset($trName) && $params['ns'] === null || isset($trName) && isset($trNamespace)) { $attribute = new Opt_Xml_Attribute($trName, $params['value']); if (isset($trNamespace)) { $attribute->setNamespace($trNamespace); } } else { $attribute = new Opt_Xml_Attribute('__xattr_' . self::$_cnt, $params['value']); if (isset($trNamespace)) { $attribute->addAfter(Opt_Xml_Buffer::ATTRIBUTE_NAME, 'echo \'' . $trNamespace . ':\'.' . $params['name'] . '; '); } elseif ($params['ns'] !== null) { $attribute->addAfter(Opt_Xml_Buffer::ATTRIBUTE_NAME, ' $_ns = ' . $params['ns'] . '; echo (!empty($_ns) ? $_ns.\':\' : \'\').' . $params['name'] . '; '); } else { $attribute->addAfter(Opt_Xml_Buffer::ATTRIBUTE_NAME, 'echo ' . $params['name'] . '; '); } } // Construct the value for the attribute. if ($node->hasChildren()) { // The more complex statement with opt:value nodes... list($pairs, $else) = $this->_getValuePairs($node, $params); // Now, create the IF...ELSEIF statement // We perform here a small optimization. If the "ELSE" statement is set // the value will always appear, so we can put this code directly in ATTRIBUTE_VALUE // and do not bother with temporary variables. if ($else !== null) { $destination = 'echo'; $code = ''; } else { $destination = '$_attr' . self::$_cnt . '_val = '; $code = '$_attr' . self::$_cnt . '_val = null; '; } $start = true; foreach ($pairs as $pair) { if ($start) { $code = ' if(' . $pair[0] . '){ ' . $destination . ' ' . $pair[1] . '; }'; $start = false; } else { $code .= 'elseif(' . $pair[0] . '){ ' . $destination . ' ' . $pair[1] . '; }'; } } if ($else !== null) { $code .= 'else{ ' . $destination . ' ' . $else . '; } '; $attribute->addAfter(Opt_Xml_Buffer::ATTRIBUTE_VALUE, $code); } else { $attribute->addAfter(Opt_Xml_Buffer::ATTRIBUTE_BEGIN, $code . ' if($_attr' . self::$_cnt . '_val !== null){ '); $attribute->addAfter(Opt_Xml_Buffer::ATTRIBUTE_VALUE, ' echo $_attr' . self::$_cnt . '_val; '); $attribute->addAfter(Opt_Xml_Buffer::ATTRIBUTE_END, ' } '); } } else { // The ordinary behaviour if ($params['value'] === null) { throw new Opt_AttributeNotDefined_Exception('value', $node->getXmlName()); } $attribute->addAfter(Opt_Xml_Buffer::ATTRIBUTE_VALUE, 'echo ' . $params['value'] . '; '); } } else { // In the raw mode, we simply put the raw expressions, because they will be processed // later by another instruction processor. $attribute = new Opt_Xml_Attribute('__xattr_' . self::$_cnt++, $params['value']); $attribute->addAfter(Opt_Xml_Buffer::ATTRIBUTE_NAME, $params['name']); // Construct the value for the attribute. if ($node->hasChildren()) { // The more complex statement with opt:value nodes... $attribute->set('call:values', $this->_getValuePairs($node, $params)); $attribute->addAfter(Opt_Xml_Buffer::ATTRIBUTE_VALUE, ''); } else { // The ordinary behaviour $attribute->addAfter(Opt_Xml_Buffer::ATTRIBUTE_VALUE, $params['value']); } if ($params['ns'] !== null) { $attribute->set('priv:namespace', $params['ns']); } } $node->set('priv:attr', $attribute); $node->set('postprocess', true); // Add the newly created attribute to the list of dynamic attributes in the parent tag. // If the list does not exist, then create it. if (!is_null($list = $parent->get('call:attribute'))) { array_push($list, $attribute); $parent->set('call:attribute', $list); } else { $parent->set('call:attribute', array(0 => $attribute)); } // Check, if such attribute does not exist... if ($parent->getAttribute($attribute->getXmlName()) !== null) { throw new Opt_XmlDuplicatedAttribute_Exception($attribute->getXmlName(), $parent->getXmlName()); } $parent->addAttribute($attribute); $parent->removeChild($node); }