[TASK] Improve variable access in compiled templates 95/39195/4
authorChristian Müller <christian@kitsunet.de>
Sat, 2 May 2015 13:14:55 +0000 (15:14 +0200)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Sat, 2 May 2015 14:00:49 +0000 (16:00 +0200)
This is a slight improvement for variable access in Fluid
that reduces recursions of ``getPropertyPath`` by one level
by pre evaluating the property path and fetching the first level
directly from the variable container in compiled templates.

Releases: master
Resolves: #66745
Change-Id: I7e9abe9e8c24af7b3bf11779ad1c4257bbb531c0
Reviewed-on: http://review.typo3.org/39195
Reviewed-by: Andreas Fernandez <typo3@scripting-base.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
typo3/sysext/fluid/Classes/Core/Compiler/TemplateCompiler.php
typo3/sysext/fluid/Classes/Core/Parser/SyntaxTree/ObjectAccessorNode.php
typo3/sysext/fluid/Classes/Core/ViewHelper/TemplateVariableContainer.php

index 3df24c6..c4ebb66 100644 (file)
@@ -135,7 +135,10 @@ EOD;
  */
 public function %s(\TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface \$renderingContext) {
 \$self = \$this;
+\$currentVariableContainer = \$renderingContext->getTemplateVariableContainer();
+
 %s
+
 return %s;
 }
 
@@ -265,10 +268,20 @@ EOD;
         * @see convert()
         */
        protected function convertObjectAccessorNode(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ObjectAccessorNode $node) {
-               return array(
-                       'initialization' => '',
-                       'execution' => sprintf(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ObjectAccessorNode::class . '::getPropertyPath($renderingContext->getTemplateVariableContainer(), \'%s\', $renderingContext)', $node->getObjectPath())
-               );
+               $objectPathSegments = explode('.', $node->getObjectPath());
+               $firstPathElement = array_shift($objectPathSegments);
+               if ($objectPathSegments === array()) {
+                       return array(
+                               'initialization' => '',
+                               'execution' => sprintf('$currentVariableContainer->getOrNull(\'%s\')', $firstPathElement)
+                       );
+               } else {
+                       $executionCode = '\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\ObjectAccessorNode::getPropertyPath($currentVariableContainer->getOrNull(\'%s\'), \'%s\', $renderingContext)';
+                       return array(
+                               'initialization' => '',
+                               'execution' => sprintf($executionCode, $firstPathElement, implode('.', $objectPathSegments))
+                       );
+               }
        }
 
        /**
@@ -373,9 +386,14 @@ EOD;
         * @return string
         */
        public function wrapChildNodesInClosure(\TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\AbstractNode $node) {
+               $convertedSubNodes = $this->convertListOfSubNodes($node);
+               if ($convertedSubNodes['execution'] === 'NULL') {
+                       return 'function() {return NULL;}';
+               }
+
                $closure = '';
                $closure .= 'function() use ($renderingContext, $self) {' . LF;
-               $convertedSubNodes = $this->convertListOfSubNodes($node);
+               $closure .= '$currentVariableContainer = $renderingContext->getTemplateVariableContainer();' . LF;
                $closure .= $convertedSubNodes['initialization'];
                $closure .= sprintf('return %s;', $convertedSubNodes['execution']) . LF;
                $closure .= '}';
index 3bcf51a..ecc9ea4 100644 (file)
@@ -79,6 +79,9 @@ class ObjectAccessorNode extends \TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\Abstrac
        static public function getPropertyPath($subject, $propertyPath, \TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface $renderingContext) {
                $propertyPathSegments = explode('.', $propertyPath);
                foreach ($propertyPathSegments as $pathSegment) {
+                       if ($subject === NULL || is_scalar($subject)) {
+                               return NULL;
+                       }
                        $propertyExists = FALSE;
                        $propertyValue = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getPropertyInternal($subject, $pathSegment, FALSE, $propertyExists);
                        if ($propertyExists !== TRUE && (is_array($subject) || $subject instanceof \ArrayAccess) && isset($subject[$pathSegment])) {
@@ -93,5 +96,4 @@ class ObjectAccessorNode extends \TYPO3\CMS\Fluid\Core\Parser\SyntaxTree\Abstrac
                }
                return $subject;
        }
-
 }
index e532859..76a0464 100644 (file)
@@ -183,4 +183,18 @@ class TemplateVariableContainer implements \ArrayAccess {
                return $this->get($identifier);
        }
 
+       /**
+        * Gets a variable or NULL if it does not exist
+        *
+        * @param string $variableName name of the variable
+        * @return mixed the stored variable or NULL
+        * @internal
+        */
+       public function getOrNull($variableName) {
+               if ($variableName === '_all') {
+                       return $this->variables;
+               }
+
+               return isset($this->variables[$variableName]) ? $this->variables[$variableName] : NULL;
+       }
 }