/** * Returns the concatenated elements of opt:value * * @internal * @param Opt_Xml_Element $node The node to scan. * @param array $params The node parameters. * @return array */ private function _getValuePairs(Opt_Xml_Element $node, array $params) { // The more sophisticated behaviour. $tags = $node->getElementsByTagNameNS('opt', 'value', false); $pairs = new SplQueue(); $else = null; if (isset($params['value'])) { $else = $params['value']; } // Pack the tags into the PHP code. foreach ($tags as $tag) { if ($tag->countChildren() > 1) { throw new Opt_InvalidValue_Exception('opt:value'); } if (!($content = $tag->getLastChild()) instanceof Opt_Xml_Text) { throw new Opt_InvalidValue_Exception('opt:value'); } // Concatenate the tag content into an expression $code = array(); foreach ($content as $items) { if ($items instanceof Opt_Xml_Cdata) { $code[] = '\'' . (string) $items . '\''; } elseif ($items instanceof Opt_Xml_Expression) { $result = $this->_compiler->compileExpression($items->getExpression(), false, Opt_Compiler_Class::ESCAPE_OFF); $code[] = $result[0]; } } $code = $this->_compiler->escape(implode('.', $code)); // Decide, what to do (final alternative or not...) if (($condition = $tag->getAttribute('test')) === null) { if ($else !== null) { throw new Opt_AttributeNotDefined_Exception('test', 'opt:value'); } $else = $code; } else { $result = $this->_compiler->compileExpression($condition, true, Opt_Compiler_Class::ESCAPE_OFF); $pairs->enqueue(array($result[0], $code)); } } return array($pairs, $else); }
/** * The common processing part of the dynamically and statically * deployed components. Returns the compiled PHP code ready to * be appended to the XML tag. The caller must generate a component * variable name that will be used in the generated code to refer * to the component object. Furthermore, he must pass the results * of _extractAttributes() method: both the $params array and the * returned values. * * @internal * @param Opt_Xml_Element $node The node with the component data. * @param string $componentVariable The PHP component variable name. * @param array $params The array of standard component attributes. * @param array $args The array of custom component attributes. * @return string */ private function _commonProcessing(Opt_Xml_Element $node, $componentVariable, array $params, array $args) { // Common part of the component processing $set2 = array(); if (!is_null($params['template'])) { // Scan for opt:set tags - they may contain some custom arguments. $set2 = $node->getElementsByTagNameNS('opt', 'set'); // Now a little trick - how to cheat the opt:insert instruction $attribute = new Opt_Xml_Attribute('opt:use', $params['template']); $this->_compiler->processor('snippet')->processAttribute($node, $attribute); } // Find all the important component elements // Remember that some opt:set tags may have been found above and are located in $set2 array. $everything = $this->_find($node); $everything[0] = array_merge($everything[0], $set2); $code = ''; // opt:set foreach ($everything[0] as $set) { $tagParams = array('name' => array(self::REQUIRED, self::EXPRESSION), 'value' => array(self::REQUIRED, self::EXPRESSION)); $this->_extractAttributes($set, $tagParams); $code .= $componentVariable . '->set(' . $tagParams['name'] . ', ' . $tagParams['value'] . '); '; } foreach ($args as $name => $value) { $code .= $componentVariable . '->set(\'' . $name . '\', ' . $value . '); '; } // com:* and opt:component-attributes foreach ($everything[1] as $wtf) { $id = null; if ($wtf->getNamespace() == 'com') { $wtf->setNamespace(NULL); $subCode = ' $out = ' . $componentVariable . '->manageAttributes(\'' . $wtf->getName() . '\', array('; } else { $id = $wtf->getAttribute('opt:component-attributes')->getValue(); $subCode = ' $out = ' . $componentVariable . '->manageAttributes(\'' . $wtf->getName() . '#' . $id . '\', array('; } foreach ($wtf->getAttributes() as $attribute) { $params = array('__UNKNOWN__' => array(self::OPTIONAL, self::EXPRESSION, null)); $vars = $this->_extractAttributes($wtf, $params); foreach ($vars as $name => $value) { $subCode .= '\'' . $name . '\' => ' . $value . ','; } } $wtf->removeAttributes(); $wtf->addAfter(Opt_Xml_Buffer::TAG_BEFORE, $subCode . ')); '); $wtf->addAfter(Opt_Xml_Buffer::TAG_ENDING_ATTRIBUTES, ' if(is_array($out)){ foreach($out as $name=>$value){ echo \' \'.$name.\'="\'.$value.\'"\'; } } '); } $node->set('postprocess', true); if (isset($attribute)) { $node->set('_componentTemplate', $attribute); } $this->_process($node); return $code; }
/** * An utility method that cleans the contents of the section node, by * moving the alternative section (opt:sectionelse etc. tags) code to the end * of the children list. * * In the parameters, we must specify the name and the namespace of the * tags that will be treated as the alternative content tags. * * @param Opt_Xml_Element $node The section node * @param String $ns The namespace * @param String $name The alternative section content tag name */ protected function _sortSectionContents(Opt_Xml_Element $node, $ns, $name) { $else = $node->getElementsByTagNameNS($ns, $name, false); if (sizeof($else) == 1) { if (!$node->hasAttributes()) { throw new Opt_InstructionTooManyItems_Exception($ns . ':' . $name, $node->getXmlName(), 'Zero'); } $node->bringToEnd($else[0]); } elseif (sizeof($else) > 1) { throw new Opt_InstructionTooManyItems_Exception($ns . ':' . $name, $node->getXmlName(), 'Zero or one'); } }