|
TYPO3 API
SVNRelease
|
00001 <?php 00002 00003 /* * 00004 * This script belongs to the FLOW3 package "Fluid". * 00005 * * 00006 * It is free software; you can redistribute it and/or modify it under * 00007 * the terms of the GNU Lesser General Public License as published by the * 00008 * Free Software Foundation, either version 3 of the License, or (at your * 00009 * option) any later version. * 00010 * * 00011 * This script is distributed in the hope that it will be useful, but * 00012 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- * 00013 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * 00014 * General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU Lesser General Public * 00017 * License along with the script. * 00018 * If not, see http://www.gnu.org/licenses/lgpl.html * 00019 * * 00020 * The TYPO3 project - inspiring people to share! * 00021 * */ 00022 00023 /** 00024 * The abstract base class for all view helpers. 00025 * 00026 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later 00027 * @api 00028 */ 00029 abstract class Tx_Fluid_Core_ViewHelper_AbstractViewHelper { 00030 00031 /** 00032 * TRUE if arguments have already been initialized 00033 * @var boolean 00034 */ 00035 private $argumentsInitialized = FALSE; 00036 00037 /** 00038 * Stores all Tx_Fluid_ArgumentDefinition instances 00039 * @var array 00040 */ 00041 private $argumentDefinitions = array(); 00042 00043 /** 00044 * Current view helper node 00045 * @var Tx_Fluid_Core_Parser_SyntaxTree_ViewHelperNode 00046 */ 00047 private $viewHelperNode; 00048 00049 /** 00050 * Arguments accessor. 00051 * @var Tx_Fluid_Core_ViewHelper_Arguments 00052 * @api 00053 */ 00054 protected $arguments; 00055 00056 /** 00057 * Current variable container reference. 00058 * @var Tx_Fluid_Core_ViewHelper_TemplateVariableContainer 00059 * @api 00060 */ 00061 protected $templateVariableContainer; 00062 00063 /** 00064 * Controller Context to use 00065 * @var Tx_Extbase_MVC_Controller_ControllerContext 00066 * @api 00067 */ 00068 protected $controllerContext; 00069 00070 /** 00071 * @var Tx_Fluid_Core_Rendering_RenderingContextInterface 00072 */ 00073 private $renderingContext; 00074 00075 /** 00076 * ViewHelper Variable Container 00077 * @var Tx_Fluid_Core_ViewHelper_ViewHelperVariableContainer 00078 * @api 00079 */ 00080 protected $viewHelperVariableContainer; 00081 00082 /** 00083 * Reflection service 00084 * @var Tx_Extbase_Reflection_Service 00085 */ 00086 private $reflectionService; 00087 00088 /** 00089 * With this flag, you can disable the escaping interceptor inside this ViewHelper. 00090 * THIS MIGHT CHANGE WITHOUT NOTICE, NO PUBLIC API! 00091 * @var boolean 00092 * @internal 00093 */ 00094 protected $escapingInterceptorEnabled = TRUE; 00095 00096 /** 00097 * @param Tx_Fluid_Core_ViewHelper_Arguments $arguments 00098 * @return void 00099 * @author Bastian Waidelich <bastian@typo3.org> 00100 */ 00101 public function setArguments(Tx_Fluid_Core_ViewHelper_Arguments $arguments) { 00102 $this->arguments = $arguments; 00103 } 00104 00105 /** 00106 * @param Tx_Fluid_Core_ViewHelper_TemplateVariableContainer $templateVariableContainer Variable Container to be used for rendering 00107 * @return void 00108 * @author Bastian Waidelich <bastian@typo3.org> 00109 */ 00110 public function setTemplateVariableContainer(Tx_Fluid_Core_ViewHelper_TemplateVariableContainer $templateVariableContainer) { 00111 $this->templateVariableContainer = $templateVariableContainer; 00112 } 00113 00114 /** 00115 * @param Tx_Extbase_MVC_Controller_ControllerContext $controllerContext Controller context which is available inside the view 00116 * @return void 00117 * @author Sebastian Kurfürst <sebastian@typo3.org> 00118 */ 00119 public function setControllerContext(Tx_Extbase_MVC_Controller_ControllerContext $controllerContext) { 00120 $this->controllerContext = $controllerContext; 00121 } 00122 00123 /** 00124 * @param Tx_Fluid_Core_Rendering_RenderingContextInterface $renderingContext 00125 * @return void 00126 * @author Robert Lemke <robert@typo3.org> 00127 */ 00128 public function setRenderingContext(Tx_Fluid_Core_Rendering_RenderingContextInterface $renderingContext) { 00129 $this->renderingContext = $renderingContext; 00130 } 00131 00132 00133 /** 00134 * @param Tx_Fluid_Core_ViewHelper_ViewHelperVariableContainer $viewHelperVariableContainer 00135 * @return void 00136 * @author Sebastian Kurfürst <sebastian@typo3.org> 00137 */ 00138 public function setViewHelperVariableContainer(Tx_Fluid_Core_ViewHelper_ViewHelperVariableContainer $viewHelperVariableContainer) { 00139 $this->viewHelperVariableContainer = $viewHelperVariableContainer; 00140 } 00141 00142 /** 00143 * Inject a Reflection service 00144 * @param Tx_Extbase_Reflection_Service $reflectionService Reflection service 00145 * @author Sebastian Kurfürst <sebastian@typo3.org> 00146 */ 00147 public function injectReflectionService(Tx_Extbase_Reflection_Service $reflectionService) { 00148 $this->reflectionService = $reflectionService; 00149 } 00150 00151 /** 00152 * Returns whether the escaping interceptor should be disabled or enabled inside the tags contents. 00153 * 00154 * THIS METHOD MIGHT CHANGE WITHOUT NOTICE; NO PUBLIC API! 00155 * 00156 * @internal 00157 * @return boolean 00158 */ 00159 public function isEscapingInterceptorEnabled() { 00160 return $this->escapingInterceptorEnabled; 00161 } 00162 00163 /** 00164 * Register a new argument. Call this method from your ViewHelper subclass 00165 * inside the initializeArguments() method. 00166 * 00167 * @param string $name Name of the argument 00168 * @param string $type Type of the argument 00169 * @param string $description Description of the argument 00170 * @param boolean $required If TRUE, argument is required. Defaults to FALSE. 00171 * @param mixed $defaultValue Default value of argument 00172 * @return Tx_Fluid_Core_ViewHelper_AbstractViewHelper $this, to allow chaining. 00173 * @author Sebastian Kurfürst <sebastian@typo3.org> 00174 * @todo Object Factory usage! 00175 * @api 00176 */ 00177 protected function registerArgument($name, $type, $description, $required = FALSE, $defaultValue = NULL) { 00178 if (array_key_exists($name, $this->argumentDefinitions)) { 00179 throw new Tx_Fluid_Core_ViewHelper_Exception('Argument "' . $name . '" has already been defined, thus it should not be defined again.', 1253036401); 00180 } 00181 $this->argumentDefinitions[$name] = new Tx_Fluid_Core_ViewHelper_ArgumentDefinition($name, $type, $description, $required, $defaultValue); 00182 return $this; 00183 } 00184 00185 /** 00186 * Overrides a registered argument. Call this method from your ViewHelper subclass 00187 * inside the initializeArguments() method if you want to override a previously registered argument. 00188 * @see registerArgument() 00189 * 00190 * @param string $name Name of the argument 00191 * @param string $type Type of the argument 00192 * @param string $description Description of the argument 00193 * @param boolean $required If TRUE, argument is required. Defaults to FALSE. 00194 * @param mixed $defaultValue Default value of argument 00195 * @return Tx_Fluid_Core_ViewHelper_AbstractViewHelper $this, to allow chaining. 00196 * @author Bastian Waidelich <bastian@typo3.org> 00197 * @todo Object Factory usage! 00198 * @api 00199 */ 00200 protected function overrideArgument($name, $type, $description, $required = FALSE, $defaultValue = NULL) { 00201 if (!array_key_exists($name, $this->argumentDefinitions)) { 00202 throw new Tx_Fluid_Core_ViewHelper_Exception('Argument "' . $name . '" has not been defined, thus it can\'t be overridden.', 1279212461); 00203 } 00204 $this->argumentDefinitions[$name] = new Tx_Fluid_Core_ViewHelper_ArgumentDefinition($name, $type, $description, $required, $defaultValue); 00205 return $this; 00206 } 00207 00208 /** 00209 * Sets all needed attributes needed for the rendering. Called by the 00210 * framework. Populates $this->viewHelperNode. 00211 * This is PURELY INTERNAL! Never override this method!! 00212 * 00213 * @param Tx_Fluid_Core_Parser_SyntaxTree_ViewHelperNode $node View Helper node to be set. 00214 * @return void 00215 * @author Sebastian Kurfürst <sebastian@typo3.org> 00216 */ 00217 public function setViewHelperNode(Tx_Fluid_Core_Parser_SyntaxTree_ViewHelperNode $node) { 00218 $this->viewHelperNode = $node; 00219 } 00220 00221 /** 00222 * Initialize the arguments of the ViewHelper, and call the render() method of the ViewHelper. 00223 * 00224 * @param array $renderMethodParameters the parameters of the render() method. 00225 * @return string the rendered ViewHelper. 00226 * @author Sebastian Kurfürst <sebastian@typo3.org> 00227 */ 00228 public function initializeArgumentsAndRender(array $renderMethodParameters) { 00229 $this->validateArguments(); 00230 $this->initialize(); 00231 return $this->callRenderMethod($renderMethodParameters); 00232 } 00233 00234 /** 00235 * Call the render() method and handle errors. 00236 * 00237 * @param array $renderMethodParameters the parameters of the render() method. 00238 * @return string the rendered ViewHelper 00239 * @author Sebastian Kurfürst <sebastian@typo3.org> 00240 */ 00241 protected function callRenderMethod(array $renderMethodParameters) { 00242 try { 00243 return call_user_func_array(array($this, 'render'), $renderMethodParameters); 00244 } catch (Tx_Fluid_Core_ViewHelper_Exception $exception) { 00245 // @todo [BW] rethrow exception, log, ignore.. depending on the current context 00246 return $exception->getMessage(); 00247 } 00248 } 00249 00250 /** 00251 * Initializes the view helper before invoking the render method. 00252 * 00253 * Override this method to solve tasks before the view helper content is rendered. 00254 * 00255 * @return void 00256 * @author Bastian Waidelich <bastian@typo3.org> 00257 * @api 00258 */ 00259 public function initialize() { 00260 } 00261 00262 /** 00263 * Helper method which triggers the rendering of everything between the 00264 * opening and the closing tag. 00265 * 00266 * @return mixed The finally rendered child nodes. 00267 * @author Sebastian Kurfürst <sebastian@typo3.org> 00268 * @author Bastian Waidelich <bastian@typo3.org> 00269 * @api 00270 */ 00271 protected function renderChildren() { 00272 return $this->viewHelperNode->evaluateChildNodes($this->renderingContext); 00273 } 00274 00275 /** 00276 * Initialize all arguments and return them 00277 * 00278 * @return array Array of Tx_Fluid_Core_ViewHelper_ArgumentDefinition instances. 00279 * @author Sebastian Kurfürst <sebastian@typo3.org> 00280 */ 00281 public function prepareArguments() { 00282 if (!$this->argumentsInitialized) { 00283 $this->registerRenderMethodArguments(); 00284 $this->initializeArguments(); 00285 $this->argumentsInitialized = TRUE; 00286 } 00287 return $this->argumentDefinitions; 00288 } 00289 00290 /** 00291 * Register method arguments for "render" by analysing the doc comment above. 00292 * 00293 * @return void 00294 * @author Sebastian Kurfürst <sebastian@typo3.org> 00295 * @author Bastian Waidelich <bastian@typo3.org> 00296 */ 00297 private function registerRenderMethodArguments() { 00298 $methodParameters = $this->reflectionService->getMethodParameters(get_class($this), 'render'); 00299 if (count($methodParameters) === 0) { 00300 return; 00301 } 00302 00303 if (Tx_Fluid_Fluid::$debugMode) { 00304 $methodTags = $this->reflectionService->getMethodTagsValues(get_class($this), 'render'); 00305 00306 $paramAnnotations = array(); 00307 if (isset($methodTags['param'])) { 00308 $paramAnnotations = $methodTags['param']; 00309 } 00310 } 00311 00312 $i = 0; 00313 foreach ($methodParameters as $parameterName => $parameterInfo) { 00314 $dataType = NULL; 00315 if (isset($parameterInfo['type'])) { 00316 $dataType = $parameterInfo['type']; 00317 } elseif ($parameterInfo['array']) { 00318 $dataType = 'array'; 00319 } 00320 if ($dataType === NULL) { 00321 throw new Tx_Fluid_Core_Parser_Exception('could not determine type of argument "' . $parameterName .'" of the render-method in ViewHelper "' . get_class($this) . '". Either the methods docComment is invalid or some PHP optimizer strips off comments.', 1242292003); 00322 } 00323 00324 $description = ''; 00325 if (Tx_Fluid_Fluid::$debugMode && isset($paramAnnotations[$i])) { 00326 $explodedAnnotation = explode(' ', $paramAnnotations[$i]); 00327 array_shift($explodedAnnotation); 00328 array_shift($explodedAnnotation); 00329 $description = implode(' ', $explodedAnnotation); 00330 } 00331 $defaultValue = NULL; 00332 if (isset($parameterInfo['defaultValue'])) { 00333 $defaultValue = $parameterInfo['defaultValue']; 00334 } 00335 $this->argumentDefinitions[$parameterName] = new Tx_Fluid_Core_ViewHelper_ArgumentDefinition($parameterName, $dataType, $description, ($parameterInfo['optional'] === FALSE), $defaultValue, TRUE); 00336 $i++; 00337 } 00338 } 00339 00340 /** 00341 * Validate arguments, and throw exception if arguments do not validate. 00342 * 00343 * @return void 00344 * @author Sebastian Kurfürst <sebastian@typo3.org> 00345 * @author Bastian Waidelich <bastian@typo3.org> 00346 */ 00347 public function validateArguments() { 00348 $argumentDefinitions = $this->prepareArguments(); 00349 if (!count($argumentDefinitions)) return; 00350 00351 foreach ($argumentDefinitions as $argumentName => $registeredArgument) { 00352 if ($this->arguments->offsetExists($argumentName)) { 00353 $type = $registeredArgument->getType(); 00354 if ($this->arguments[$argumentName] === $registeredArgument->getDefaultValue()) continue; 00355 00356 if ($type === 'array') { 00357 if (!is_array($this->arguments[$argumentName]) && !$this->arguments[$argumentName] instanceof ArrayAccess && !$this->arguments[$argumentName] instanceof Traversable) { 00358 throw new InvalidArgumentException('The argument "' . $argumentName . '" was registered with type "array", but is of type "' . gettype($this->arguments[$argumentName]) . '" in view helper "' . get_class($this) . '"', 1237900529); 00359 } 00360 } elseif ($type === 'boolean') { 00361 if (!is_bool($this->arguments[$argumentName])) { 00362 throw new InvalidArgumentException('The argument "' . $argumentName . '" was registered with type "boolean", but is of type "' . gettype($this->arguments[$argumentName]) . '" in view helper "' . get_class($this) . '".', 1240227732); 00363 } 00364 } elseif (class_exists($type, FALSE)) { 00365 if (! ($this->arguments[$argumentName] instanceof $type)) { 00366 if (is_object($this->arguments[$argumentName])) { 00367 throw new InvalidArgumentException('The argument "' . $argumentName . '" was registered with type "' . $type . '", but is of type "' . get_class($this->arguments[$argumentName]) . '" in view helper "' . get_class($this) . '".', 1256475114); 00368 } else { 00369 throw new InvalidArgumentException('The argument "' . $argumentName . '" was registered with type "' . $type . '", but is of type "' . gettype($this->arguments[$argumentName]) . '" in view helper "' . get_class($this) . '".', 1256475113); 00370 } 00371 } 00372 } 00373 } 00374 } 00375 } 00376 00377 /** 00378 * Initialize all arguments. You need to override this method and call 00379 * $this->registerArgument(...) inside this method, to register all your arguments. 00380 * 00381 * @return void 00382 * @author Sebastian Kurfürst <sebastian@typo3.org> 00383 * @api 00384 */ 00385 public function initializeArguments() { 00386 } 00387 00388 /** 00389 * Render method you need to implement for your custom view helper. 00390 * Available objects at this point are $this->arguments, and $this->templateVariableContainer. 00391 * 00392 * Besides, you often need $this->renderChildren(). 00393 * 00394 * @return string rendered string, view helper specific 00395 * @author Sebastian Kurfürst <sebastian@typo3.org> 00396 * @api 00397 */ 00398 //abstract public function render(); 00399 00400 /** 00401 * Get the rendering context interface. 00402 * THIS METHOD IS NO PUBLIC API AND ONLY CALLABLE INSIDE THE FRAMEWORK! 00403 * 00404 * @return Tx_Fluid_Core_Rendering_RenderingContextInterface 00405 * @author Sebastian Kurfürst <sebastian@typo3.org> 00406 */ 00407 public function getRenderingContext() { 00408 if ($this instanceof Tx_Fluid_Core_ViewHelper_Facets_ChildNodeAccessInterface) { 00409 return $this->renderingContext; 00410 } else { 00411 throw new Tx_Fluid_Core_ViewHelper_Exception_RenderingContextNotAccessibleException('It is forbidden to call getRenderingContext() if you do not implement Tx_Fluid_Core_ViewHelper_Facets_ChildNodeAccessInterface. But beware, this interface is NO PUBLIC API! If you want to implement conditions, you should subclass Tx_Fluid_Core_ViewHelper_AbstractConditionViewHelper.', 127895038); 00412 } 00413 } 00414 } 00415 00416 ?>
1.8.0