PageRenderTime 82ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/includes/Opl/Opt/Instruction/Component.php

https://bitbucket.org/kandsten/hitta.sverok.se
PHP | 296 lines | 233 code | 31 blank | 32 comment | 22 complexity | 851ce7707ac48204df333e84baee4c4e MD5 | raw file
Possible License(s): GPL-3.0, MIT
  1. <?php
  2. /*
  3. * OPEN POWER LIBS <http://www.invenzzia.org>
  4. *
  5. * This file is subject to the new BSD license that is bundled
  6. * with this package in the file LICENSE. It is also available through
  7. * WWW at this URL: <http://www.invenzzia.org/license/new-bsd>
  8. *
  9. * Copyright (c) Invenzzia Group <http://www.invenzzia.org>
  10. * and other contributors. See website for details.
  11. *
  12. * $Id: Component.php 254 2009-10-25 14:02:44Z zyxist $
  13. */
  14. class Opt_Instruction_Component extends Opt_Compiler_Processor
  15. {
  16. protected $_name = 'component';
  17. // The counter used to generate unique variable names for defined components
  18. protected $_unique = 0;
  19. // The stack is required by the processSystemVar() method to determine, which component
  20. // the call refers to.
  21. protected $_stack;
  22. public function configure()
  23. {
  24. $this->_addInstructions(array('opt:component', 'opt:onEvent', 'opt:display', ));
  25. $this->_stack = new SplStack;
  26. } // end configure();
  27. public function processNode(Opt_Xml_Node $node)
  28. {
  29. switch($node->getName())
  30. {
  31. case 'component':
  32. $node->set('component', true);
  33. // Undefined component processing
  34. $params = array(
  35. 'from' => array(self::REQUIRED, self::EXPRESSION, null),
  36. 'datasource' => array(self::OPTIONAL, self::EXPRESSION, null),
  37. 'template' => array(self::OPTIONAL, self::ID, null),
  38. '__UNKNOWN__' => array(self::OPTIONAL, self::EXPRESSION, null)
  39. );
  40. $vars = $this->_extractAttributes($node, $params);
  41. $this->_stack->push($params['from']);
  42. $mainCode = ' if(is_object('.$params['from'].') && '.$params['from'].' instanceof Opt_Component_Interface){ '.$params['from'].'->setView($this); ';
  43. if(!is_null($params['datasource']))
  44. {
  45. $mainCode .= $params['from'].'->setDatasource('.$params['datasource'].'); ';
  46. }
  47. $mainCode .= $this->_commonProcessing($node, $params['from'], $params, $vars);
  48. $node->addBefore(Opt_Xml_Buffer::TAG_BEFORE, $mainCode);
  49. $node->addAfter(Opt_Xml_Buffer::TAG_AFTER, ' } ');
  50. break;
  51. case 'onEvent':
  52. if($this->_stack->count() == 0)
  53. {
  54. throw new Opt_ComponentNotActive_Exception($node->getXmlName());
  55. }
  56. $tagParams = array(
  57. 'name' => array(self::REQUIRED, self::EXPRESSION)
  58. );
  59. $this->_extractAttributes($node, $tagParams);
  60. $node->addAfter(Opt_Xml_Buffer::TAG_BEFORE, ' if('.$this->_stack->top().'->processEvent('.$tagParams['name'].')){ ');
  61. $node->addAfter(Opt_Xml_Buffer::TAG_AFTER, ' } ');
  62. $this->_process($node);
  63. break;
  64. case 'display':
  65. if($this->_stack->count() == 0)
  66. {
  67. throw new Opt_ComponentNotActive_Exception($node->getXmlName());
  68. }
  69. $node->set('hidden', false);
  70. $node->removeChildren();
  71. // The opt:display attributes must be packed into array and sent
  72. // to Opt_Component_Interface::display()
  73. $subCode = '';
  74. if($node->hasAttributes())
  75. {
  76. $params = array(
  77. '__UNKNOWN__' => array(self::OPTIONAL, self::EXPRESSION, null)
  78. );
  79. $vars = $this->_extractAttributes($node, $params);
  80. $subCode = 'array(';
  81. foreach($vars as $name => $value)
  82. {
  83. $subCode .= '\''.$name.'\' => '.$value.',';
  84. }
  85. $subCode .= ')';
  86. }
  87. $node->addAfter(Opt_Xml_Buffer::TAG_BEFORE, $this->_stack->top().'->display('.$subCode.'); ');
  88. break;
  89. }
  90. } // end processNode();
  91. public function postprocessNode(Opt_Xml_Node $node)
  92. {
  93. if(!is_null($attribute = $node->get('_componentTemplate')))
  94. {
  95. $this->_compiler->processor('snippet')->postprocessAttribute($node, $attribute);
  96. }
  97. $this->_stack->pop();
  98. } // end postprocessNode();
  99. public function processComponent(Opt_Xml_Element $node)
  100. {
  101. // Defined component processing
  102. $params = array(
  103. 'datasource' => array(self::OPTIONAL, self::EXPRESSION, null),
  104. 'template' => array(self::OPTIONAL, self::ID, null),
  105. '__UNKNOWN__' => array(self::OPTIONAL, self::EXPRESSION, null)
  106. );
  107. $vars = $this->_extractAttributes($node, $params);
  108. // Get the real class name
  109. $cn = '$_component_'.($this->_unique++);
  110. $this->_stack->push($cn);
  111. $class = $this->_compiler->component($node->getXmlName());
  112. // Check, if there are any conversions that may take control over initializing
  113. // the component object. We are allowed to capture only particular component
  114. // creation or all of them.
  115. if((($to = $this->_compiler->convert('##component_'.$class)) != '##component_'.$class))
  116. {
  117. $attributes = 'array(';
  118. foreach($vars as $name => $value)
  119. {
  120. $attributes .= '\''.$name.'\' => '.$value.', ';
  121. }
  122. $attributes .= ')';
  123. $ccode = str_replace(array('%CLASS%', '%TAG%', '%ATTRIBUTES%'), array($class, $node->getXmlName(), $attributes), $to);
  124. }
  125. elseif((($to = $this->_compiler->convert('##component')) != '##component'))
  126. {
  127. $attributes = 'array(';
  128. foreach($vars as $name => $value)
  129. {
  130. $attributes .= '\''.$name.'\' => '.$value.', ';
  131. }
  132. $attributes .= ')';
  133. $ccode = str_replace(array('%CLASS%', '%TAG%', '%ATTRIBUTES%'), array($class, $node->getXmlName(), $attributes), $to);
  134. }
  135. else
  136. {
  137. $ccode = 'new '.$class;
  138. }
  139. // Generate the initialization code
  140. $mainCode = $cn.' = '.$ccode.'; '.$cn.'->setView($this); ';
  141. if(!is_null($params['datasource']))
  142. {
  143. $mainCode .= $cn.'->setDatasource('.$params['datasource'].'); ';
  144. }
  145. $mainCode .= $this->_commonProcessing($node, $cn, $params, $vars);
  146. $node->addAfter(Opt_Xml_Buffer::TAG_BEFORE, $mainCode);
  147. } // end processComponent();
  148. public function postprocessComponent(Opt_Xml_Node $node)
  149. {
  150. if(!is_null($attribute = $node->get('_componentTemplate')))
  151. {
  152. $this->_compiler->processor('snippet')->postprocessAttribute($node, $attribute);
  153. $node->set('_componentTemplate', NULL);
  154. }
  155. $this->_stack->pop();
  156. } // end postprocessComponent();
  157. private function _commonProcessing($node, $cn, $params, $args)
  158. {
  159. // Common part of the component processing
  160. $set2 = array();
  161. if(!is_null($params['template']))
  162. {
  163. // Scan for opt:set tags - they may contain some custom arguments.
  164. $set2 = $node->getElementsByTagNameNS('opt', 'set');
  165. // Now a little trick - how to cheat the opt:insert instruction
  166. $attribute = new Opt_Xml_Attribute('opt:use', $params['template']);
  167. $this->_compiler->processor('snippet')->processAttribute($node, $attribute);
  168. }
  169. // Find all the important component elements
  170. // Remember that some opt:set tags may have been found above and are located in $set2 array.
  171. $everything = $this->_find($node);
  172. $everything[0] = array_merge($everything[0], $set2);
  173. $code = '';
  174. // opt:set
  175. foreach($everything[0] as $set)
  176. {
  177. $tagParams = array(
  178. 'name' => array(self::REQUIRED, self::EXPRESSION),
  179. 'value' => array(self::REQUIRED, self::EXPRESSION)
  180. );
  181. $this->_extractAttributes($set, $tagParams);
  182. $code .= $cn.'->set('.$tagParams['name'].', '.$tagParams['value'].'); ';
  183. }
  184. foreach($args as $name => $value)
  185. {
  186. $code .= $cn.'->set(\''.$name.'\', '.$value.'); ';
  187. }
  188. // com:* and opt:component-attributes
  189. foreach($everything[1] as $wtf)
  190. {
  191. $id = null;
  192. if($wtf->getNamespace() == 'com')
  193. {
  194. $wtf->setNamespace(NULL);
  195. $subCode = ' $out = '.$cn.'->manageAttributes(\''.$wtf->getName().'\', array(';
  196. }
  197. else
  198. {
  199. $id = $wtf->getAttribute('opt:component-attributes')->getValue();
  200. $subCode = ' $out = '.$cn.'->manageAttributes(\''.$wtf->getName().'#'.$id.'\', array(';
  201. }
  202. foreach($wtf->getAttributes() as $attribute)
  203. {
  204. $params = array(
  205. '__UNKNOWN__' => array(self::OPTIONAL, self::STRING, null)
  206. );
  207. $vars = $this->_extractAttributes($wtf, $params);
  208. foreach($vars as $name => $value)
  209. {
  210. $subCode .= '\''.$name.'\' => '.$value.',';
  211. }
  212. }
  213. $wtf->removeAttributes();
  214. $wtf->addAfter(Opt_Xml_Buffer::TAG_BEFORE, $subCode.')); ');
  215. $wtf->addAfter(Opt_Xml_Buffer::TAG_ENDING_ATTRIBUTES, ' if(is_array($out)){ foreach($out as $name=>$value){ echo \' \'.$name.\'="\'.$value.\'"\'; } } ');
  216. }
  217. $node->set('postprocess', true);
  218. if(isset($attribute))
  219. {
  220. $node->set('_componentTemplate', $attribute);
  221. }
  222. $this->_process($node);
  223. return $code;
  224. } // end _commonProcessing();
  225. public function processSystemVar($opt)
  226. {
  227. if($this->_stack->count() == 0)
  228. {
  229. throw new Opt_SysVariableInvalidUse_Exception('$'.implode('.',$opt), 'components');
  230. }
  231. return $this->_stack->top().'->get(\''.$opt[2].'\')';
  232. } // end processSystemVar();
  233. private function _find($node)
  234. {
  235. // We have so many recursions... let's do it in the imperative way.
  236. $queue = new SplQueue;
  237. $queue->enqueue($node);
  238. $result = array(
  239. 0 => array(), // opt:set
  240. 1 => array(), // com:*
  241. );
  242. $map = array('opt:set' => 0);
  243. do
  244. {
  245. $current = $queue->dequeue();
  246. if($current instanceof Opt_Xml_Element)
  247. {
  248. if(isset($map[$current->getXmlName()]))
  249. {
  250. $result[$map[$current->getXmlName()]][] = $current;
  251. }
  252. elseif($current->getNamespace() == 'com' || $current->getAttribute('opt:component-attributes') !== null)
  253. {
  254. $result[1][] = $current;
  255. }
  256. }
  257. foreach($current as $subnode)
  258. {
  259. $queue->enqueue($subnode);
  260. }
  261. }
  262. while($queue->count() > 0);
  263. return $result;
  264. } // end _find();
  265. } // end Opt_Instruction_Component;