| Conditions | 74 | 
| Paths | 230 | 
| Total Lines | 309 | 
| Lines | 0 | 
| Ratio | 0 % | 
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | <?php  | 
            ||
| 377 | protected function sequenceInlineNodes(\Iterator $sequence, bool $allowArray = true): NodeInterface  | 
            ||
| 378 |     { | 
            ||
| 379 |         $text = '{'; | 
            ||
| 380 | $node = null;  | 
            ||
| 381 | $key = null;  | 
            ||
| 382 | $namespace = null;  | 
            ||
| 383 | $method = null;  | 
            ||
| 384 | $potentialAccessor = null;  | 
            ||
| 385 | $callDetected = false;  | 
            ||
| 386 | $hasPass = false;  | 
            ||
| 387 | $hasColon = null;  | 
            ||
| 388 | $hasWhitespace = false;  | 
            ||
| 389 | $isArray = false;  | 
            ||
| 390 | $array = [];  | 
            ||
| 391 | $arguments = [];  | 
            ||
| 392 | $ignoredEndingBraces = 0;  | 
            ||
| 393 | $countedEscapes = 0;  | 
            ||
| 394 | |||
| 395 | $this->splitter->switch($this->contexts->inline);  | 
            ||
| 396 | $sequence->next();  | 
            ||
| 397 |         foreach ($sequence as $symbol => $captured) { | 
            ||
| 398 | $text .= $captured;  | 
            ||
| 399 |             switch ($symbol) { | 
            ||
| 400 | case Splitter::BYTE_BACKSLASH:  | 
            ||
| 401 | // Increase the number of counted escapes (is passed to sequenceNode() in the "QUOTE" cases and reset  | 
            ||
| 402 | // after the quoted string is extracted).  | 
            ||
| 403 | ++$countedEscapes;  | 
            ||
| 404 | break;  | 
            ||
| 405 | |||
| 406 | case Splitter::BYTE_ARRAY_START:  | 
            ||
| 407 | |||
| 408 | $text .= chr($symbol);  | 
            ||
| 409 | $isArray = $allowArray;  | 
            ||
| 410 | |||
| 411 | #ArrayStart:  | 
            ||
| 412 | // Sequence the node. Pass the "use numeric keys?" boolean based on the current byte. Only array  | 
            ||
| 413 |                     // start creates numeric keys. Inline start with keyless values creates ECMA style {foo:foo, bar:bar} | 
            ||
| 414 |                     // from {foo, bar}. | 
            ||
| 415 | $array[$key ?? $captured ?? 0] = $node = $this->sequenceArrayNode($sequence, null, $symbol === Splitter::BYTE_ARRAY_START);  | 
            ||
| 416 | $this->splitter->switch($this->contexts->inline);  | 
            ||
| 417 | unset($key);  | 
            ||
| 418 | break;  | 
            ||
| 419 | |||
| 420 | case Splitter::BYTE_INLINE:  | 
            ||
| 421 |                     // Encountering this case can mean different things: sub-syntax like {foo.{index}} or array, depending | 
            ||
| 422 | // on presence of either a colon or comma before the inline. In protected mode it is simply added.  | 
            ||
| 423 |                     $text .= '{'; | 
            ||
| 424 |                     if (!$hasWhitespace && $text !== '{{') { | 
            ||
| 425 |                         // Most likely, a nested object accessor syntax e.g. {foo.{bar}} - enter protected context since | 
            ||
| 426 | // these accessors do not allow anything other than additional nested accessors.  | 
            ||
| 427 | $this->splitter->switch($this->contexts->accessor);  | 
            ||
| 428 | ++$ignoredEndingBraces;  | 
            ||
| 429 |                     } elseif ($this->splitter->context->context === Context::CONTEXT_PROTECTED) { | 
            ||
| 430 | // Ignore one ending additional curly brace. Subtracted in the BYTE_INLINE_END case below.  | 
            ||
| 431 |                         // The expression in this case looks like {{inline}.....} and we capture the curlies. | 
            ||
| 432 | $potentialAccessor .= $captured;  | 
            ||
| 433 | ++$ignoredEndingBraces;  | 
            ||
| 434 |                     } elseif ($allowArray || $isArray) { | 
            ||
| 435 | $isArray = true;  | 
            ||
| 436 | $captured = $key ?? $captured ?? $potentialAccessor;  | 
            ||
| 437 | // This is a sub-syntax following a colon - meaning it is an array.  | 
            ||
| 438 |                         if ($captured !== null) { | 
            ||
| 439 | #goto ArrayStart;  | 
            ||
| 440 | $array[$key ?? $captured ?? 0] = $node = $this->sequenceArrayNode($sequence, null, $symbol === Splitter::BYTE_ARRAY_START);  | 
            ||
| 441 | $this->splitter->switch($this->contexts->inline);  | 
            ||
| 442 | }  | 
            ||
| 443 |                     } else { | 
            ||
| 444 | $childNodeToAdd = $this->sequenceInlineNodes($sequence, $allowArray);  | 
            ||
| 445 | $node = isset($node) ? $node->addChildNode($childNodeToAdd) : (new RootNode())->addChildNode($childNodeToAdd);  | 
            ||
| 446 | }  | 
            ||
| 447 | break;  | 
            ||
| 448 | |||
| 449 | case Splitter::BYTE_MINUS:  | 
            ||
| 450 | $text .= '-';  | 
            ||
| 451 | break;  | 
            ||
| 452 | |||
| 453 | // Backtick may be encountered in two different contexts: normal inline context, in which case it has  | 
            ||
| 454 | // the same meaning as any quote and causes sequencing of a quoted string. Or protected context, in  | 
            ||
| 455 | // which case it also sequences a quoted node but appends the result instead of assigning to array.  | 
            ||
| 456 | // Note that backticks do not support escapes (they are a new feature that does not require escaping).  | 
            ||
| 457 | case Splitter::BYTE_BACKTICK:  | 
            ||
| 458 |                     if ($this->splitter->context->context === Context::CONTEXT_PROTECTED) { | 
            ||
| 459 | $node->addChildNode(new TextNode($text));  | 
            ||
| 460 | $node->addChildNode($this->sequenceQuotedNode($sequence)->flatten());  | 
            ||
| 461 | $text = '';  | 
            ||
| 462 | break;  | 
            ||
| 463 | }  | 
            ||
| 464 | // Fallthrough is intentional: if not in protected context, consider the backtick a normal quote.  | 
            ||
| 465 | |||
| 466 | // Case not normally countered in straight up "inline" context, but when encountered, means we have  | 
            ||
| 467 | // explicitly found a quoted array key - and we extract it.  | 
            ||
| 468 | case Splitter::BYTE_QUOTE_SINGLE:  | 
            ||
| 469 | case Splitter::BYTE_QUOTE_DOUBLE:  | 
            ||
| 470 |                     if (!$allowArray) { | 
            ||
| 471 | $text .= chr($symbol);  | 
            ||
| 472 | break;  | 
            ||
| 473 | }  | 
            ||
| 474 |                     if (isset($key)) { | 
            ||
| 475 | $array[$key] = $this->sequenceQuotedNode($sequence, $countedEscapes)->flatten(true);  | 
            ||
| 476 | $key = null;  | 
            ||
| 477 |                     } else { | 
            ||
| 478 | $key = $this->sequenceQuotedNode($sequence, $countedEscapes)->flatten(true);  | 
            ||
| 479 | }  | 
            ||
| 480 | $countedEscapes = 0;  | 
            ||
| 481 | $isArray = $allowArray;  | 
            ||
| 482 | break;  | 
            ||
| 483 | |||
| 484 | case Splitter::BYTE_SEPARATOR_COMMA:  | 
            ||
| 485 |                     if (!$allowArray) { | 
            ||
| 486 | $text .= ',';  | 
            ||
| 487 | break;  | 
            ||
| 488 | }  | 
            ||
| 489 |                     if (isset($captured)) { | 
            ||
| 490 | $array[$key ?? $captured] = is_numeric($captured) ? $captured + 0 : new ObjectAccessorNode($captured);  | 
            ||
| 491 | }  | 
            ||
| 492 | $key = null;  | 
            ||
| 493 | $isArray = $allowArray;  | 
            ||
| 494 | break;  | 
            ||
| 495 | |||
| 496 | case Splitter::BYTE_SEPARATOR_EQUALS:  | 
            ||
| 497 | $text .= '=';  | 
            ||
| 498 |                     if (!$allowArray) { | 
            ||
| 499 | $node = new RootNode();  | 
            ||
| 500 | $this->splitter->switch($this->contexts->protected);  | 
            ||
| 501 | break;  | 
            ||
| 502 | }  | 
            ||
| 503 | $key = $captured;  | 
            ||
| 504 | $isArray = $allowArray;  | 
            ||
| 505 | break;  | 
            ||
| 506 | |||
| 507 | case Splitter::BYTE_SEPARATOR_COLON:  | 
            ||
| 508 | $text .= ':';  | 
            ||
| 509 | $hasColon = true;  | 
            ||
| 510 | $namespace = $captured;  | 
            ||
| 511 | $key = $key ?? $captured;  | 
            ||
| 512 | $isArray = $isArray || ($allowArray && is_numeric($key));  | 
            ||
| 513 | break;  | 
            ||
| 514 | |||
| 515 | case Splitter::BYTE_WHITESPACE_SPACE:  | 
            ||
| 516 | case Splitter::BYTE_WHITESPACE_EOL:  | 
            ||
| 517 | case Splitter::BYTE_WHITESPACE_RETURN:  | 
            ||
| 518 | case Splitter::BYTE_WHITESPACE_TAB:  | 
            ||
| 519 | // If we already collected some whitespace we must enter protected context.  | 
            ||
| 520 | $text .= $this->source->source[$this->splitter->index - 1];  | 
            ||
| 521 |                     if ($hasWhitespace && !$hasPass && !$allowArray) { | 
            ||
| 522 | // Protection mode: this very limited context does not allow tags or inline syntax, and will  | 
            ||
| 523 | // protect things like CSS and JS - and will only enter a more reactive context if encountering  | 
            ||
| 524 | // the backtick character, meaning a quoted string will be sequenced. This backtick-quoted  | 
            ||
| 525 | // string can then contain inline syntax like variable accessors.  | 
            ||
| 526 | $node = $node ?? new RootNode();  | 
            ||
| 527 | $this->splitter->switch($this->contexts->protected);  | 
            ||
| 528 | break;  | 
            ||
| 529 | }  | 
            ||
| 530 | $key = $key ?? $captured;  | 
            ||
| 531 | $hasWhitespace = true;  | 
            ||
| 532 | $isArray = $allowArray && ($hasColon ?? $isArray ?? is_numeric($captured));  | 
            ||
| 533 | $potentialAccessor = ($potentialAccessor ?? $captured);  | 
            ||
| 534 | break;  | 
            ||
| 535 | |||
| 536 | case Splitter::BYTE_TAG_END:  | 
            ||
| 537 | case Splitter::BYTE_PIPE:  | 
            ||
| 538 | // If there is an accessor on the left side of the pipe and $node is not defined, we create $node  | 
            ||
| 539 | // as an object accessor. If $node already exists we do nothing (and expect the VH trigger, the  | 
            ||
| 540 | // parenthesis start case below, to add $node as childnode and create a new $node).  | 
            ||
| 541 | $hasPass = true;  | 
            ||
| 542 | $isArray = $allowArray;  | 
            ||
| 543 | $callDetected = false;  | 
            ||
| 544 | $potentialAccessor = $potentialAccessor ?? $captured;  | 
            ||
| 545 | $text .= $this->source->source[$this->splitter->index - 1];  | 
            ||
| 546 |                     if (isset($potentialAccessor)) { | 
            ||
| 547 | $childNodeToAdd = new ObjectAccessorNode($potentialAccessor);  | 
            ||
| 548 | $node = isset($node) ? $node->addChildNode($childNodeToAdd) : $childNodeToAdd; //$node ?? (is_numeric($potentialAccessor) ? $potentialAccessor + 0 : new ObjectAccessorNode($potentialAccessor));  | 
            ||
| 549 | }  | 
            ||
| 550 | //!isset($potentialAccessor) ?: ($node = ($node ?? $this->createObjectAccessorNodeOrRawValue($potentialAccessor)));  | 
            ||
| 551 | unset($namespace, $method, $potentialAccessor, $key);  | 
            ||
| 552 | break;  | 
            ||
| 553 | |||
| 554 | case Splitter::BYTE_PARENTHESIS_START:  | 
            ||
| 555 | $isArray = false;  | 
            ||
| 556 | // Special case: if a parenthesis start was preceded by whitespace but had no pass operator we are  | 
            ||
| 557 | // not dealing with a ViewHelper call and will continue the sequencing, grabbing the parenthesis as  | 
            ||
| 558 | // part of the expression.  | 
            ||
| 559 |                     $text .= '('; | 
            ||
| 560 |                     if (!$hasColon || ($hasWhitespace && !$hasPass)) { | 
            ||
| 561 | $this->splitter->switch($this->contexts->protected);  | 
            ||
| 562 | unset($namespace, $method);  | 
            ||
| 563 | break;  | 
            ||
| 564 | }  | 
            ||
| 565 | |||
| 566 | $callDetected = true;  | 
            ||
| 567 | $method = $captured;  | 
            ||
| 568 | $childNodeToAdd = $node;  | 
            ||
| 569 |                     try { | 
            ||
| 570 | $node = $this->resolver->createViewHelperInstance($namespace, $method);  | 
            ||
| 571 | $definitions = $node->prepareArguments();  | 
            ||
| 572 |                     } catch (\TYPO3Fluid\Fluid\Core\Exception $exception) { | 
            ||
| 573 | throw $this->createErrorAtPosition($exception->getMessage(), $exception->getCode());  | 
            ||
| 574 | }  | 
            ||
| 575 | $this->splitter->switch($this->contexts->array);  | 
            ||
| 576 | $arguments = $this->sequenceArrayNode($sequence, $definitions)->getInternalArray();  | 
            ||
| 577 | $this->splitter->switch($this->contexts->inline);  | 
            ||
| 578 |                     if ($childNodeToAdd) { | 
            ||
| 579 | $escapingEnabledBackup = $this->escapingEnabled;  | 
            ||
| 580 | $this->escapingEnabled = (bool)$node->isChildrenEscapingEnabled();  | 
            ||
| 581 |                         if ($childNodeToAdd instanceof ObjectAccessorNode) { | 
            ||
| 582 | $this->callInterceptor($childNodeToAdd, InterceptorInterface::INTERCEPT_OBJECTACCESSOR);  | 
            ||
| 583 | }  | 
            ||
| 584 | $this->escapingEnabled = $escapingEnabledBackup;  | 
            ||
| 585 | $node->addChildNode($childNodeToAdd);  | 
            ||
| 586 | }  | 
            ||
| 587 | $text .= ')';  | 
            ||
| 588 | unset($potentialAccessor);  | 
            ||
| 589 | break;  | 
            ||
| 590 | |||
| 591 | case Splitter::BYTE_INLINE_END:  | 
            ||
| 592 | $text .= '}';  | 
            ||
| 593 |                     if (--$ignoredEndingBraces >= 0) { | 
            ||
| 594 | break;  | 
            ||
| 595 | }  | 
            ||
| 596 | $isArray = $allowArray && ($isArray ?: ($hasColon && !$hasPass && !$callDetected));  | 
            ||
| 597 | $potentialAccessor = $potentialAccessor ?? $captured;  | 
            ||
| 598 | |||
| 599 | // Decision: if we did not detect a ViewHelper we match the *entire* expression, from the cached  | 
            ||
| 600 | // starting index, to see if it matches a known type of expression. If it does, we must return the  | 
            ||
| 601 | // appropriate type of ExpressionNode.  | 
            ||
| 602 |                     if ($isArray) { | 
            ||
| 603 |                         if ($captured !== null) { | 
            ||
| 604 | $array[$key ?? $captured] = is_numeric($captured) ? $captured + 0 : new ObjectAccessorNode($captured);  | 
            ||
| 605 | }  | 
            ||
| 606 | return new ArrayNode($array);  | 
            ||
| 607 |                     } elseif ($callDetected) { | 
            ||
| 608 | // The first-priority check is for a ViewHelper used right before the inline expression ends,  | 
            ||
| 609 | // in which case there is no further syntax to come.  | 
            ||
| 610 | $node = $node->postParse($arguments, $this->state, $this->renderingContext);  | 
            ||
| 611 | $interceptionPoint = InterceptorInterface::INTERCEPT_CLOSING_VIEWHELPER;  | 
            ||
| 612 |                     } elseif ($this->splitter->context->context === Context::CONTEXT_ACCESSOR) { | 
            ||
| 613 | // If we are currently in "accessor" context we can now add the accessor by stripping the collected text.  | 
            ||
| 614 | $node = new ObjectAccessorNode(substr($text, 1, -1));  | 
            ||
| 615 | $interceptionPoint = InterceptorInterface::INTERCEPT_OBJECTACCESSOR;  | 
            ||
| 616 |                     } elseif ($this->splitter->context->context === Context::CONTEXT_PROTECTED || ($hasWhitespace && !$callDetected && !$hasPass)) { | 
            ||
| 617 | // In order to qualify for potentially being an expression, the entire inline node must contain  | 
            ||
| 618 | // whitespace, must not contain parenthesis, must not contain a colon and must not contain an  | 
            ||
| 619 | // inline pass operand. This significantly limits the number of times this (expensive) routine  | 
            ||
| 620 | // has to be executed.  | 
            ||
| 621 | $interceptionPoint = InterceptorInterface::INTERCEPT_TEXT;  | 
            ||
| 622 | $childNodeToAdd = new TextNode($text);  | 
            ||
| 623 |                         foreach ($this->renderingContext->getExpressionNodeTypes() as $expressionNodeTypeClassName) { | 
            ||
| 624 | $matchedVariables = [];  | 
            ||
| 625 | // TODO: rewrite expression nodes to receive a sub-Splitter that lets the expression node  | 
            ||
| 626 | // consume a symbol+capture sequence and either match or ignore it; then use the already  | 
            ||
| 627 | // consumed (possibly halted mid-way through iterator!) sequence to achieve desired behavior.  | 
            ||
| 628 | preg_match_all($expressionNodeTypeClassName::$detectionExpression, $text, $matchedVariables, PREG_SET_ORDER);  | 
            ||
| 629 |                             foreach ($matchedVariables as $matchedVariableSet) { | 
            ||
| 630 |                                 try { | 
            ||
| 631 | $childNodeToAdd = new $expressionNodeTypeClassName($matchedVariableSet[0], $matchedVariableSet, $this->state);  | 
            ||
| 632 | $interceptionPoint = InterceptorInterface::INTERCEPT_EXPRESSION;  | 
            ||
| 633 |                                 } catch (ExpressionException $error) { | 
            ||
| 634 | $childNodeToAdd = new TextNode($this->renderingContext->getErrorHandler()->handleExpressionError($error));  | 
            ||
| 635 | }  | 
            ||
| 636 | break;  | 
            ||
| 637 | }  | 
            ||
| 638 | }  | 
            ||
| 639 | $node = isset($node) ? $node->addChildNode($childNodeToAdd) : $childNodeToAdd;  | 
            ||
| 640 |                     } elseif (!$hasPass && !$callDetected) { | 
            ||
| 641 | // Third priority check is if there was no pass syntax and no ViewHelper, in which case we  | 
            ||
| 642 | // create a standard ObjectAccessorNode; alternatively, if nothing was captured (expression  | 
            ||
| 643 |                         // was empty, e.g. {} was used) we create a TextNode with the captured text to output "{}". | 
            ||
| 644 |                         if (isset($potentialAccessor)) { | 
            ||
| 645 | // If the accessor is set we can trust it is not a numeric value, since this will have  | 
            ||
| 646 | // set $isArray to TRUE if nothing else already did so.  | 
            ||
| 647 | $node = is_numeric($potentialAccessor) ? $potentialAccessor + 0 : new ObjectAccessorNode($potentialAccessor);  | 
            ||
| 648 | $interceptionPoint = InterceptorInterface::INTERCEPT_OBJECTACCESSOR;  | 
            ||
| 649 |                         } else { | 
            ||
| 650 | $node = new TextNode($text);  | 
            ||
| 651 | $interceptionPoint = InterceptorInterface::INTERCEPT_TEXT;  | 
            ||
| 652 | }  | 
            ||
| 653 |                     } elseif ($hasPass && $this->resolver->isAliasRegistered((string)$potentialAccessor)) { | 
            ||
| 654 |                         // Fourth priority check is for a pass to a ViewHelper alias, e.g. "{value | raw}" in which case | 
            ||
| 655 | // we look for the alias used and create a ViewHelperNode with no arguments.  | 
            ||
| 656 | $childNodeToAdd = $node;  | 
            ||
| 657 | $node = $this->resolver->createViewHelperInstance(null, $potentialAccessor);  | 
            ||
| 658 | $node->addChildNode($childNodeToAdd);  | 
            ||
| 659 | $node = $node->postParse($arguments, $this->state, $this->renderingContext);  | 
            ||
| 660 | $interceptionPoint = InterceptorInterface::INTERCEPT_CLOSING_VIEWHELPER;  | 
            ||
| 661 |                     } else { | 
            ||
| 662 | # TODO: should this be an error case, or should it result in a TextNode?  | 
            ||
| 663 | throw $this->createErrorAtPosition(  | 
            ||
| 664 | 'Invalid inline syntax - not accessor, not expression, not array, not ViewHelper, but ' .  | 
            ||
| 665 | 'contains the tokens used by these in a sequence that is not valid Fluid syntax. You can ' .  | 
            ||
| 666 | 'most likely avoid this by adding whitespace inside the curly braces before the first ' .  | 
            ||
| 667 | 'Fluid-like symbol in the expression. Symbols recognized as Fluid are: "' .  | 
            ||
| 668 |                             addslashes(implode('","', array_map('chr', $this->contexts->inline->bytes))) . '"', | 
            ||
| 669 | 1558782228  | 
            ||
| 670 | );  | 
            ||
| 671 | }  | 
            ||
| 672 | |||
| 673 | $escapingEnabledBackup = $this->escapingEnabled;  | 
            ||
| 674 | $this->escapingEnabled = (bool)((isset($viewHelper) && $node->isOutputEscapingEnabled()) || $escapingEnabledBackup);  | 
            ||
| 675 | $this->callInterceptor($node, $interceptionPoint, $this->state);  | 
            ||
| 676 | $this->escapingEnabled = $escapingEnabledBackup;  | 
            ||
| 677 | return $node;  | 
            ||
| 678 | }  | 
            ||
| 679 | }  | 
            ||
| 680 | |||
| 681 | // See note in sequenceTagNode() end of method body. TL;DR: this is intentionally here instead of as "default"  | 
            ||
| 682 | // case in the switch above for a very specific reason: the case is only encountered if seeing EOF before the  | 
            ||
| 683 | // inline expression was closed.  | 
            ||
| 684 |         throw $this->createErrorAtPosition('Unterminated inline syntax', 1557838506); | 
            ||
| 685 | }  | 
            ||
| 686 | |||
| 935 | }  | 
            
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.