Completed
Pull Request — master (#446)
by Claus
02:04
created

RenderViewHelper::allowsChildNodeType()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7

Duplication

Lines 7
Ratio 100 %

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 1
dl 7
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
namespace TYPO3Fluid\Fluid\ViewHelpers;
3
4
/*
5
 * This file belongs to the package "TYPO3 Fluid".
6
 * See LICENSE.txt that was shipped with this package.
7
 */
8
9
use TYPO3Fluid\Fluid\Core\Parser\NodeFilterInterface;
10
use TYPO3Fluid\Fluid\Core\Parser\ParsedTemplateInterface;
11
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\NodeInterface;
12
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\TextNode;
13
use TYPO3Fluid\Fluid\Core\Rendering\RenderableInterface;
14
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
15
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
16
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
17
18
/**
19
 * A ViewHelper to render a section, a partial, a specified section in a partial
20
 * or a delegate ParsedTemplateInterface implementation.
21
 *
22
 * = Examples =
23
 *
24
 * <code title="Rendering partials">
25
 * <f:render partial="SomePartial" arguments="{foo: someVariable}" />
26
 * </code>
27
 * <output>
28
 * the content of the partial "SomePartial". The content of the variable {someVariable} will be available in the partial as {foo}
29
 * </output>
30
 *
31
 * <code title="Rendering sections">
32
 * <f:section name="someSection">This is a section. {foo}</f:section>
33
 * <f:render section="someSection" arguments="{foo: someVariable}" />
34
 * </code>
35
 * <output>
36
 * the content of the section "someSection". The content of the variable {someVariable} will be available in the partial as {foo}
37
 * </output>
38
 *
39
 * <code title="Rendering recursive sections">
40
 * <f:section name="mySection">
41
 *  <ul>
42
 *    <f:for each="{myMenu}" as="menuItem">
43
 *      <li>
44
 *        {menuItem.text}
45
 *        <f:if condition="{menuItem.subItems}">
46
 *          <f:render section="mySection" arguments="{myMenu: menuItem.subItems}" />
47
 *        </f:if>
48
 *      </li>
49
 *    </f:for>
50
 *  </ul>
51
 * </f:section>
52
 * <f:render section="mySection" arguments="{myMenu: menu}" />
53
 * </code>
54
 * <output>
55
 * <ul>
56
 *   <li>menu1
57
 *     <ul>
58
 *       <li>menu1a</li>
59
 *       <li>menu1b</li>
60
 *     </ul>
61
 *   </li>
62
 * [...]
63
 * (depending on the value of {menu})
64
 * </output>
65
 *
66
 *
67
 * <code title="Passing all variables to a partial">
68
 * <f:render partial="somePartial" arguments="{_all}" />
69
 * </code>
70
 * <output>
71
 * the content of the partial "somePartial".
72
 * Using the reserved keyword "_all", all available variables will be passed along to the partial
73
 * </output>
74
 *
75
 *
76
 * <code title="Rendering via a delegate ParsedTemplateInterface implementation w/ custom arguments">
77
 * <f:render delegate="My\Special\ParsedTemplateImplementation" arguments="{_all}" />
78
 * </code>
79
 * <output>
80
 * Whichever output was generated by calling My\Special\ParsedTemplateImplementation->render()
81
 * with cloned RenderingContextInterface $renderingContext as only argument and content of arguments
82
 * assigned in VariableProvider of cloned context. Supports all other input arguments including
83
 * recursive rendering, contentAs argument, default value etc.
84
 * Note that while ParsedTemplateInterface supports returning a Layout name, this Layout will not
85
 * be respected when rendering using this method. Only the `render()` method will be called!
86
 * </output>
87
 *
88
 * @api
89
 */
90
class RenderViewHelper extends AbstractViewHelper implements NodeFilterInterface
91
{
92
    use CompileWithRenderStatic;
93
    
94
    /**
95
     * @var boolean
96
     */
97
    protected $escapeOutput = false;
98
99
    /**
100
     * @return void
101
     */
102
    public function initializeArguments()
103
    {
104
        parent::initializeArguments();
105
        $this->registerArgument('section', 'string', 'Section to render - combine with partial to render section in partial');
106
        $this->registerArgument('partial', 'string', 'Partial to render, with or without section');
107
        $this->registerArgument('delegate', 'string', 'Optional PHP class name of a permanent, included-in-app ParsedTemplateInterface implementation to override partial/section');
108
        $this->registerArgument('renderable', RenderableInterface::class, 'Instance of a RenderableInterface implementation to be rendered');
109
        $this->registerArgument('arguments', 'array', 'Array of variables to be transferred. Use {_all} for all variables', false, []);
110
        $this->registerArgument('optional', 'boolean', 'If TRUE, considers the *section* optional. Partial never is.', false, false);
111
        $this->registerArgument('default', 'mixed', 'Value (usually string) to be displayed if the section or partial does not exist');
112
        $this->registerArgument('contentAs', 'string', 'If used, renders the child content and adds it as a template variable with this name for use in the partial/section');
113
    }
114
115
    /**
116
     * Condition ViewHelpers disallow child nodes that consist purely of whitespace,
117
     * thus avoiding whitespace in output inside f:if structures but not inside any
118
     * f:then or f:else nodes.
119
     *
120
     * @param NodeInterface $node
121
     * @return bool
122
     */
123 View Code Duplication
    public function allowsChildNodeType(NodeInterface $node): bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
124
    {
125
        if ($node instanceof TextNode && trim($node->getText()) === '') {
126
            return false;
127
        }
128
        return true;
129
    }
130
131
    /**
132
     * @return mixed
133
     */
134
    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
135
    {
136
        $section = $arguments['section'];
137
        $partial = $arguments['partial'];
138
        $variables = (array) $arguments['arguments'];
139
        $optional = (boolean) $arguments['optional'];
140
        $delegate = $arguments['delegate'];
141
        /** @var RenderableInterface $renderable */
142
        $renderable = $arguments['renderable'];
143
        $tagContent = $renderChildrenClosure();
144
        if ($arguments['contentAs']) {
145
            $variables[$arguments['contentAs']] = $tagContent;
146
        }
147
148
        $view = $renderingContext->getViewHelperVariableContainer()->getView();
149
        $content = '';
150
        if ($renderable) {
151
            $content = $renderable->render($renderingContext);
152
        } elseif ($delegate !== null) {
153
            if (!is_a($delegate, ParsedTemplateInterface::class, true)) {
154
                throw new \InvalidArgumentException(sprintf('Cannot render %s - must implement ParsedTemplateInterface!', $delegate));
155
            }
156
            $renderingContext = clone $renderingContext;
157
            $renderingContext->getVariableProvider()->setSource($variables);
158
            $content = (new $delegate())->render($renderingContext);
159
        } elseif ($partial !== null) {
160
            $content = $view->renderPartial($partial, $section, $variables, $optional);
161
        } elseif ($section !== null) {
162
            $content = $view->renderSection($section, $variables, $optional);
163
        } elseif (!$optional) {
164
            throw new \InvalidArgumentException('ViewHelper f:render called without either argument section, partial, renderable or delegate and optional flag is false');
165
        }
166
        // Replace empty content with default value. If default is
167
        // not set, NULL is returned and cast to a new, empty string
168
        // outside of this ViewHelper.
169
        if ($content === '') {
170
            $content = $arguments['default'] ?: $tagContent;
171
        }
172
        return $content;
173
    }
174
}
175