Skip to content
This repository
Browse code

Adding data format support for components.

  • Loading branch information...
commit 32363fc959ad50542cb2c6f9726621060c004d12 1 parent 8b91ad1
Tomasz Jędrzejewski authored October 30, 2010
7  lib/Opt/Class.php
@@ -185,6 +185,8 @@ class Opt_Class extends Opl_Class
185 185
 	public $defaultFormat = 'Array';
186 186
 	public $containerFormat = 'Container';
187 187
 	public $treeFormat = 'DepthTree';
  188
+	public $componentFormat = 'Component';
  189
+	public $blockFormat = 'Block';
188 190
 
189 191
 	/**
190 192
 	 * The compiler object
@@ -289,6 +291,7 @@ class Opt_Class extends Opl_Class
289 291
 		'Objective' => 'Opt_Format_Objective',
290 292
 		'Global' => 'Opt_Format_Global',
291 293
 		'SingleArray' => 'Opt_Format_SingleArray',
  294
+		'SplDatastructure' => 'Opt_Format_SplDatastructure',
292 295
 		'StaticGenerator' => 'Opt_Format_StaticGenerator',
293 296
 		'RuntimeGenerator' => 'Opt_Format_RuntimeGenerator',
294 297
 		'System' => 'Opt_Format_System',
@@ -296,7 +299,9 @@ class Opt_Class extends Opl_Class
296 299
 		'SwitchContains' => 'Opt_Format_SwitchContains',
297 300
 		'Container' => 'Opt_Format_Container',
298 301
 		'DepthTree' => 'Opt_Format_DepthTree',
299  
-		'NestedTree' => 'Opt_Format_NestedTree'
  302
+		'NestedTree' => 'Opt_Format_NestedTree',
  303
+		'Component' => 'Opt_Format_Component',
  304
+		'Block' => 'Opt_Format_Block'
300 305
 	);
301 306
 	/**
302 307
 	 * The extra entities replaced by OPT
96  lib/Opt/Format/Component.php
... ...
@@ -0,0 +1,96 @@
  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
+
  13
+/**
  14
+ * The data format for components.
  15
+ *
  16
+ * @author Tomasz Jędrzejewski
  17
+ * @copyright Invenzzia Group <http://www.invenzzia.org/> and contributors.
  18
+ * @license http://www.invenzzia.org/license/new-bsd New BSD License
  19
+ * @package Formats
  20
+ */
  21
+class Opt_Format_Component extends Opt_Format_Abstract
  22
+{
  23
+	/**
  24
+	 * The list of supported hook types.
  25
+	 * @var array
  26
+	 */
  27
+	protected $_supports = array(
  28
+		'component'
  29
+	);
  30
+
  31
+	/**
  32
+	 * Build a PHP code for the specified hook name.
  33
+	 *
  34
+	 * @internal
  35
+	 * @param string $hookName The hook name
  36
+	 * @return string The output PHP code
  37
+	 */
  38
+	protected function _build($hookName)
  39
+	{
  40
+		switch($hookName)
  41
+		{
  42
+			case 'component:init':
  43
+				return ' '.$this->_getVar('variable').'->setView($this); ';
  44
+			case 'component:done':
  45
+				return '';
  46
+			case 'component:valid':
  47
+				return ' '.$this->_getVar('variable').' instanceof Opt_Component_Interface';
  48
+			case 'component:build':
  49
+				return ' '.$this->_getVar('variable').' = new '.$this->_getVar('className').'; ';
  50
+			case 'component:datasource':
  51
+				return ' '.$this->_getVar('variable').'->setDatasource('.$this->_getVar('datasource').'); ';
  52
+			case 'component:event-open':
  53
+				return ' if('.$this->_getVar('variable').'->processEvent('.$this->_getVar('eventName').')){ ';
  54
+			case 'component:event-close':
  55
+				return ' } ';
  56
+			case 'component:display':
  57
+				$attrs = $this->_getVar('attributes');
  58
+				$subCode = '';
  59
+				if(sizeof($attrs) > 0)
  60
+				{
  61
+					$subCode = 'array(';
  62
+					foreach($attrs as $name => $value)
  63
+					{
  64
+						$subCode .= '\''.$name.'\' => '.$value.',';
  65
+					}
  66
+					$subCode .= ')';
  67
+				}
  68
+				return ' '.$this->_getVar('variable').'->display('.$subCode.'); ';
  69
+			case 'component:inject-open':
  70
+				return ' '.$this->_getVar('variable').'->setInjection(';
  71
+			case 'component:inject-close':
  72
+				return '); ';
  73
+			case 'component:manage-attributes':
  74
+				$attrs = $this->_getVar('attributes');
  75
+				$subCode = 'array()';
  76
+				if(sizeof($attrs) > 0)
  77
+				{
  78
+					$subCode = 'array(';
  79
+					foreach($attrs as $name => $value)
  80
+					{
  81
+						$subCode .= '\''.$name.'\' => '.$value.',';
  82
+					}
  83
+					$subCode .= ')';
  84
+				}
  85
+
  86
+				return ' $out = '.$this->_getVar('variable').'->manageAttributes(\''.$this->_getVar('tag').'\', '.$subCode.'); ';
  87
+			case 'component:manage-attributes-apply':
  88
+				return ' if(is_array($out)){ foreach($out as $name=>$value){ echo \' \'.$name.\'="\'.$value.\'"\'; } } ';
  89
+			case 'component:set':
  90
+				return ' '.$this->_getVar('variable').'->__set('.$this->_getVar('name').', '.$this->_getVar('value').') ';
  91
+			case 'component:get':
  92
+				return ' '.$this->_getVar('variable').'->__get('.$this->_getVar('name').') ';
  93
+		}
  94
+	} // end _build();
  95
+
  96
+} // end Opt_Format_Component;
128  lib/Opt/Instruction/Component.php
@@ -84,21 +84,25 @@ public function processNode(Opt_Xml_Node $node)
84 84
 					'from' => array(self::REQUIRED, self::EXPRESSION, null),
85 85
 					'datasource' => array(self::OPTIONAL, self::EXPRESSION, null),
86 86
 					'template' => array(self::OPTIONAL, self::ID, null),
  87
+					'id' => array(self::OPTIONAL, self::STRING, null),
87 88
 					'__UNKNOWN__' => array(self::OPTIONAL, self::EXPRESSION, null)
88 89
 				);
89 90
 				$vars = $this->_extractAttributes($node, $params);
90  
-				$this->_stack->push($params['from']);
  91
+				$format = $this->_compiler->getFormat('component#'.$params['id'], false, $this->_tpl->componentFormat);
  92
+				$format->assign('variable', $params['from']);
  93
+				$this->_stack->push(array($params['from'], $format));
91 94
 
92  
-				$mainCode = ' if(is_object('.$params['from'].') && '.$params['from'].' instanceof Opt_Component_Interface){ '.$params['from'].'->setView($this); ';
  95
+				$mainCode = ' if(is_object('.$params['from'].') && '.$format->get('component:valid').'){ '.$format->get('component:init');
93 96
 				if($params['datasource'] !== null)
94 97
 				{
95  
-					$mainCode .= $params['from'].'->setDatasource('.$params['datasource'].'); ';
  98
+					$format->assign('datasource', $params['datasource']);
  99
+					$mainCode .= $format->get('component:datasource');
96 100
 				}
97 101
 
98  
-				$mainCode .= $this->_commonProcessing($node, $params['from'], $params, $vars);
  102
+				$mainCode .= $this->_commonProcessing($node, $params['from'], $params, $vars, $format);
99 103
 
100 104
 				$node->addBefore(Opt_Xml_Buffer::TAG_BEFORE,  $mainCode);
101  
-				$node->addAfter(Opt_Xml_Buffer::TAG_AFTER, ' } ');
  105
+				$node->addAfter(Opt_Xml_Buffer::TAG_AFTER, $format->get('component:done').' } ');
102 106
 				break;
103 107
 			case 'on-event':
104 108
 				if($this->_stack->count() == 0)
@@ -110,9 +114,12 @@ public function processNode(Opt_Xml_Node $node)
110 114
 					'name' => array(self::REQUIRED, self::EXPRESSION)
111 115
 				);
112 116
 
  117
+				list($variable, $format) = $this->_stack->top();
  118
+
113 119
 				$this->_extractAttributes($node, $tagParams);
114  
-				$node->addAfter(Opt_Xml_Buffer::TAG_BEFORE, ' if('.$this->_stack->top().'->processEvent('.$tagParams['name'].')){ ');
115  
-				$node->addAfter(Opt_Xml_Buffer::TAG_AFTER, ' } ');
  120
+				$format->assign('eventName', $tagParams['name']);
  121
+				$node->addAfter(Opt_Xml_Buffer::TAG_BEFORE, $format->get('component:event-open'));
  122
+				$node->addAfter(Opt_Xml_Buffer::TAG_AFTER, $format->get('component:event-close'));
116 123
 				$this->_process($node);
117 124
 				break;
118 125
 
@@ -121,6 +128,7 @@ public function processNode(Opt_Xml_Node $node)
121 128
 				{
122 129
 					throw new Opt_Instruction_Exception('Component error: invalid use of "opt:display": no active component.');
123 130
 				}
  131
+				list($variable, $format) = $this->_stack->top();
124 132
 				$node->set('hidden', false);
125 133
 				$node->removeChildren();
126 134
 				// The opt:display attributes must be packed into array and sent
@@ -132,20 +140,20 @@ public function processNode(Opt_Xml_Node $node)
132 140
 						'__UNKNOWN__' => array(self::OPTIONAL, self::EXPRESSION, null)
133 141
 					);
134 142
 					$vars = $this->_extractAttributes($node, $params);
135  
-					$subCode = 'array(';
136  
-					foreach($vars as $name => $value)
137  
-					{
138  
-						$subCode .= '\''.$name.'\' => '.$value.',';
139  
-					}
140  
-					$subCode .= ')';
  143
+					$format->assign('attributes', $vars);
141 144
 				}
142  
-				$node->addAfter(Opt_Xml_Buffer::TAG_BEFORE, $this->_stack->top().'->display('.$subCode.'); ');
  145
+				else
  146
+				{
  147
+					$format->assign('attributes', array());
  148
+				}
  149
+				$node->addAfter(Opt_Xml_Buffer::TAG_BEFORE, $format->get('component:display'));
143 150
 				break;
144 151
 			case 'inject':
145 152
 				if($this->_stack->count() == 0)
146 153
 				{
147 154
 					throw new Opt_Instruction_Exception('Component error: invalid use of "opt:inject": no active component.');
148 155
 				}
  156
+				list($variable, $format) = $this->_stack->top();
149 157
 				$code = 'function() use($ctx){ ';
150 158
 
151 159
 				if($node->getAttribute('procedure') !== null)
@@ -157,7 +165,7 @@ public function processNode(Opt_Xml_Node $node)
157 165
 					$code .= ' $args = func_get_args(); array_unshift($args, $ctx); '.PHP_EOL;
158 166
 					$code .= $this->_compiler->processor('procedure')->callProcedure($params['procedure'], '$args', true).PHP_EOL;
159 167
 					$code .= '}'.PHP_EOL;
160  
-					$node->addAfter(Opt_Xml_Buffer::TAG_BEFORE, $this->_stack->top().'->setInjection('.$code.'); ');
  168
+					$node->addAfter(Opt_Xml_Buffer::TAG_BEFORE, $format->get('component:inject-open').$code.$format->get('component:inject-close'));
161 169
 				}
162 170
 				else
163 171
 				{
@@ -182,8 +190,8 @@ public function processNode(Opt_Xml_Node $node)
182 190
 						}
183 191
 						$value = '$args['.($i++).']';
184 192
 					}
185  
-					$node->addAfter(Opt_Xml_Buffer::TAG_BEFORE, $this->_stack->top().'->setInjection('.$code);
186  
-					$node->addBefore(Opt_Xml_Buffer::TAG_AFTER, ' }); ');
  193
+					$node->addAfter(Opt_Xml_Buffer::TAG_BEFORE, $format->get('component:inject-open').$code);
  194
+					$node->addBefore(Opt_Xml_Buffer::TAG_AFTER, ' } '.$format->get('component:inject-close'));
187 195
 					$this->_compiler->processor('snippet')->useSnippet($node, $params['snippet'], $snippetArgs, false, true);
188 196
 					$this->_process($node);
189 197
 				}
@@ -223,55 +231,30 @@ public function processComponent(Opt_Xml_Element $node)
223 231
 	{
224 232
 		// Defined component processing
225 233
 		$params = array(
  234
+			'id' => array(self::OPTIONAL, self::STRING, null),
226 235
 			'datasource' => array(self::OPTIONAL, self::EXPRESSION, null),
227 236
 			'template' => array(self::OPTIONAL, self::ID, null),
228 237
 			'__UNKNOWN__' => array(self::OPTIONAL, self::EXPRESSION, null)
229 238
 		);
230 239
 
231 240
 		$vars = $this->_extractAttributes($node, $params);
232  
-		// Get the real class name
  241
+		// Initialize component structures
233 242
 		$cn = '$_component_'.($this->_unique++);
234  
-
235  
-		$this->_stack->push($cn);
236  
-
237  
-		$class = $this->_compiler->component($node->getXmlName());
238  
-
239  
-		// Check, if there are any conversions that may take control over initializing
240  
-		// the component object. We are allowed to capture only particular component
241  
-		// creation or all of them.
242  
-		if((($to = $this->_compiler->convert('##component_'.$class)) != '##component_'.$class))
243  
-		{
244  
-			$attributes = 'array(';
245  
-			foreach($vars as $name => $value)
246  
-			{
247  
-				$attributes .= '\''.$name.'\' => '.$value.', ';
248  
-			}
249  
-			$attributes .= ')';
250  
-			$ccode = str_replace(array('%CLASS%', '%TAG%', '%ATTRIBUTES%'), array($class, $node->getXmlName(), $attributes), $to);
251  
-		}
252  
-		elseif((($to = $this->_compiler->convert('##component')) != '##component'))
253  
-		{
254  
-			$attributes = 'array(';
255  
-			foreach($vars as $name => $value)
256  
-			{
257  
-				$attributes .= '\''.$name.'\' => '.$value.', ';
258  
-			}
259  
-			$attributes .= ')';
260  
-			$ccode = str_replace(array('%CLASS%', '%TAG%', '%ATTRIBUTES%'), array($class, $node->getXmlName(), $attributes), $to);
261  
-		}
262  
-		else
263  
-		{
264  
-			$ccode = 'new '.$class;
265  
-		}
  243
+		$format = $this->_compiler->getFormat('component#'.$params['id'], false, $this->_tpl->componentFormat);
  244
+		$format->assign('variable', $cn);
  245
+		$this->_stack->push(array($cn, $format));
266 246
 
267 247
 		// Generate the initialization code
268  
-		$mainCode = $cn.' = '.$ccode.'; '.$cn.'->setView($this); ';
  248
+		$format->assign('className', $this->_compiler->component($node->getXmlName()));
  249
+		$mainCode = $format->get('component:build').$format->get('component:init');
  250
+
269 251
 		if($params['datasource'] !== null)
270 252
 		{
271  
-			$mainCode .= $cn.'->setDatasource('.$params['datasource'].'); ';
  253
+			$format->assign('datasource', $params['datasource']);
  254
+			$mainCode .= $format->get('component:datasource');
272 255
 		}
273 256
 
274  
-		$mainCode .= $this->_commonProcessing($node, $cn, $params, $vars);
  257
+		$mainCode .= $this->_commonProcessing($node, $cn, $params, $vars, $format).$format->get('component:done');
275 258
 		$node->addAfter(Opt_Xml_Buffer::TAG_BEFORE,  $mainCode);
276 259
 	} // end processComponent();
277 260
 
@@ -305,9 +288,10 @@ public function postprocessComponent(Opt_Xml_Node $node)
305 288
 	 * @param string $componentVariable The PHP component variable name.
306 289
 	 * @param array $params The array of standard component attributes.
307 290
 	 * @param array $args The array of custom component attributes.
  291
+	 * @param Opt_Format_Abstract $format The component data format.
308 292
 	 * @return string
309 293
 	 */
310  
-	private function _commonProcessing(Opt_Xml_Element $node, $componentVariable, array $params, array $args)
  294
+	private function _commonProcessing(Opt_Xml_Element $node, $componentVariable, array $params, array $args, Opt_Format_Abstract $format)
311 295
 	{
312 296
 		// Common part of the component processing
313 297
 		$set2 = array();
@@ -345,33 +329,29 @@ private function _commonProcessing(Opt_Xml_Element $node, $componentVariable, ar
345 329
 			);
346 330
 
347 331
 			$this->_extractAttributes($set, $tagParams);
348  
-			$code .= $componentVariable.'->__set('.$tagParams['name']['bare'].', '.$tagParams['value'].'); ';
  332
+			$format->assign('name', $tagParams['name']['bare']);
  333
+			$format->assign('value', $tagParams['value']);
  334
+			$code .= $format->get('component:set');
349 335
 		}
350 336
 		foreach($args as $name => $value)
351 337
 		{
352  
-			$code .= $componentVariable.'->__set(\''.$name.'\', '.$value.'); ';
  338
+			$format->assign('name', $name);
  339
+			$format->assign('value', $value);
  340
+			$code .= $format->get('component:set');
353 341
 		}
354 342
 		// opt:component-attributes
355 343
 		foreach($everything[1] as $wtf)
356 344
 		{
357  
-			$id = $wtf->getAttribute('opt:component-attributes')->getValue();
358  
-			$subCode = ' $out = '.$componentVariable.'->manageAttributes(\''.$wtf->getName().'#'.$id.'\', array(';
359  
-		//	$wtf->removeAttribute('opt:component-attributes');
  345
+			$params = array(
  346
+				'__UNKNOWN__' => array(self::OPTIONAL, self::EXPRESSION, null, 'str')
  347
+			);
  348
+			$vars = $this->_extractAttributes($wtf, $params);
  349
+			$format->assign('tag', $wtf->getName().'#'.$wtf->getAttribute('opt:component-attributes')->getValue());
  350
+			$format->assign('attributes', $vars);
360 351
 
361  
-		//	foreach($wtf->getAttributes() as $attribute)
362  
-	//		{
363  
-				$params = array(
364  
-					'__UNKNOWN__' => array(self::OPTIONAL, self::EXPRESSION, null, 'str')
365  
-				);
366  
-				$vars = $this->_extractAttributes($wtf, $params);
367  
-				foreach($vars as $name => $value)
368  
-				{
369  
-					$subCode .= '\''.$name.'\' => '.$value.',';
370  
-				}
371  
-	//		}
372 352
 			$wtf->removeAttributes();
373  
-			$wtf->addAfter(Opt_Xml_Buffer::TAG_BEFORE, $subCode.')); ');
374  
-			$wtf->addAfter(Opt_Xml_Buffer::TAG_ENDING_ATTRIBUTES, ' if(is_array($out)){ foreach($out as $name=>$value){ echo \' \'.$name.\'="\'.$value.\'"\'; } } ');
  353
+			$wtf->addAfter(Opt_Xml_Buffer::TAG_BEFORE, $format->get('component:manage-attributes'));
  354
+			$wtf->addAfter(Opt_Xml_Buffer::TAG_ENDING_ATTRIBUTES, $format->get('component:manage-attributes-apply'));
375 355
 		}
376 356
 
377 357
 		$node->set('postprocess', true);
@@ -398,7 +378,9 @@ public function processSystemVar($opt)
398 378
 		{
399 379
 			throw new Opt_Instruction_Exception('Component error: invalid use of $'.implode('.',$opt).': no active component.');
400 380
 		}
401  
-		return $this->_stack->top().'->'.$opt[2];
  381
+		list($variable, $format) = $this->_stack->top();
  382
+		$format->assign('name', $opt[2]);
  383
+		return $format->get('component:get');
402 384
 	} // end processSystemVar();
403 385
 
404 386
 	/**
1  tests/Package/Instruction/ComponentTest.php
@@ -53,6 +53,7 @@ public static function dataProvider()
53 53
 			array('Component/component_nesting.txt'),
54 54
 			array('Component/component_template.txt'),
55 55
 			array('Component/component_template_missing.txt'),
  56
+			array('Component/component_id.txt'),
56 57
 		);
57 58
 	} // end dataProvider();
58 59
 
26  tests/Package/Instruction/Tests/Component/component_id.txt
... ...
@@ -0,0 +1,26 @@
  1
+Checking working with data formats.
  2
+
  3
+>>>>templates/test.tpl
  4
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
  5
+<opt:root xmlns:opt="http://xml.invenzzia.org/opt">
  6
+
  7
+<opt:component from="$component" id="foo">
  8
+<opt:set name="foo" value="str:bar" />
  9
+{$system.component.foo}
  10
+</opt:component>
  11
+
  12
+</opt:root>
  13
+
  14
+>>>>data.php
  15
+
  16
+$view->setFormat('component#foo', 'Component');
  17
+$view->component = new Extra_Mock_Component;
  18
+
  19
+>>>>expected.txt
  20
+OUTPUT
  21
+
  22
+>>>>result.txt
  23
+VIEW PASSED
  24
+PARAM foo PASSED
  25
+PARAM foo RETURNED
  26
+bar

0 notes on commit 32363fc

Please sign in to comment.
Something went wrong with that request. Please try again.