Completed
Pull Request — master (#537)
by
unknown
03:43
created

RenderViewHelper   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 71
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 4

Importance

Changes 0
Metric Value
dl 0
loc 71
rs 10
c 0
b 0
f 0
wmc 13
lcom 0
cbo 4

2 Methods

Rating   Name   Duplication   Size   Complexity  
A initializeArguments() 0 12 1
C renderStatic() 0 42 12
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\ParsedTemplateInterface;
10
use TYPO3Fluid\Fluid\Core\Rendering\RenderableInterface;
11
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
12
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
13
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
14
15
/**
16
 * A ViewHelper to render a section, a partial, a specified section in a partial
17
 * or a delegate ParsedTemplateInterface implementation.
18
 *
19
 * Examples
20
 * ========
21
 *
22
 * Rendering partials
23
 * ------------------
24
 *
25
 * ::
26
 *
27
 *     <f:render partial="SomePartial" arguments="{foo: someVariable}" />
28
 *
29
 * Output::
30
 *
31
 *     the content of the partial "SomePartial". The content of the variable {someVariable} will be available in the partial as {foo}
32
 *
33
 * Rendering sections
34
 * ------------------
35
 *
36
 * ::
37
 *
38
 *     <f:section name="someSection">This is a section. {foo}</f:section>
39
 *     <f:render section="someSection" arguments="{foo: someVariable}" />
40
 *
41
 * Output::
42
 *
43
 *     the content of the section "someSection". The content of the variable {someVariable} will be available in the partial as {foo}
44
 *
45
 * Rendering recursive sections
46
 * ----------------------------
47
 *
48
 * ::
49
 *
50
 *     <f:section name="mySection">
51
 *         <ul>
52
 *             <f:for each="{myMenu}" as="menuItem">
53
 *                 <li>
54
 *                     {menuItem.text}
55
 *                     <f:if condition="{menuItem.subItems}">
56
 *                         <f:render section="mySection" arguments="{myMenu: menuItem.subItems}" />
57
 *                     </f:if>
58
 *                 </li>
59
 *             </f:for>
60
 *         </ul>
61
 *        </f:section>
62
 *        <f:render section="mySection" arguments="{myMenu: menu}" />
63
 *
64
 * Output::
65
 *
66
 *     <ul>
67
 *         <li>menu1
68
 *             <ul>
69
 *               <li>menu1a</li>
70
 *               <li>menu1b</li>
71
 *             </ul>
72
 *         </li>
73
 *     [...]
74
 *     (depending on the value of {menu})
75
 *
76
 *
77
 * Passing all variables to a partial
78
 * ----------------------------------
79
 *
80
 * ::
81
 *
82
 *     <f:render partial="somePartial" arguments="{_all}" />
83
 *
84
 * Output::
85
 *
86
 *     the content of the partial "somePartial".
87
 *     Using the reserved keyword "_all", all available variables will be passed along to the partial
88
 *
89
 *
90
 * Rendering via a delegate ParsedTemplateInterface implementation w/ custom arguments
91
 * -----------------------------------------------------------------------------------
92
 *
93
 * ::
94
 *
95
 *     <f:render delegate="My\Special\ParsedTemplateImplementation" arguments="{_all}" />
96
 *
97
 * This will output whichever output was generated by calling ``My\Special\ParsedTemplateImplementation->render()``
98
 * with cloned RenderingContextInterface $renderingContext as only argument and content of arguments
99
 * assigned in VariableProvider of cloned context. Supports all other input arguments including
100
 * recursive rendering, contentAs argument, default value etc.
101
 *
102
 * Note that while ParsedTemplateInterface supports returning a Layout name, this Layout will not
103
 * be respected when rendering using this method. Only the ``render()`` method will be called!
104
 *
105
 * @api
106
 */
107
class RenderViewHelper extends AbstractViewHelper
108
{
109
    use CompileWithRenderStatic;
110
111
    /**
112
     * @var boolean
113
     */
114
    protected $escapeOutput = false;
115
116
    /**
117
     * @return void
118
     */
119
    public function initializeArguments()
120
    {
121
        parent::initializeArguments();
122
        $this->registerArgument('section', 'string', 'Section to render - combine with partial to render section in partial');
123
        $this->registerArgument('partial', 'string', 'Partial to render, with or without section');
124
        $this->registerArgument('delegate', 'string', 'Optional PHP class name of a permanent, included-in-app ParsedTemplateInterface implementation to override partial/section');
125
        $this->registerArgument('renderable', RenderableInterface::class, 'Instance of a RenderableInterface implementation to be rendered');
126
        $this->registerArgument('arguments', 'array', 'Array of variables to be transferred. Use {_all} for all variables', false, []);
127
        $this->registerArgument('optional', 'boolean', 'If TRUE, considers the *section* optional. Partial never is.', false, false);
128
        $this->registerArgument('default', 'mixed', 'Value (usually string) to be displayed if the section or partial does not exist');
129
        $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');
130
    }
131
132
    /**
133
     * @return mixed
134
     */
135
    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
136
    {
137
        $section = $arguments['section'];
138
        $partial = $arguments['partial'];
139
        $variables = (array) $arguments['arguments'];
140
        $optional = (boolean) $arguments['optional'];
141
        $delegate = $arguments['delegate'];
142
        /** @var RenderableInterface $renderable */
143
        $renderable = $arguments['renderable'];
144
        $tagContent = null;
145
        if ($arguments['contentAs']) {
146
            $tagContent = $tagContent ?: $renderChildrenClosure();
147
            $variables[$arguments['contentAs']] = $tagContent;
148
        }
149
150
        $view = $renderingContext->getViewHelperVariableContainer()->getView();
151
        $content = '';
152
        if ($renderable) {
153
            $content = $renderable->render($renderingContext);
154
        } elseif ($delegate !== null) {
155
            if (!is_a($delegate, ParsedTemplateInterface::class, true)) {
156
                throw new \InvalidArgumentException(sprintf('Cannot render %s - must implement ParsedTemplateInterface!', $delegate));
157
            }
158
            $renderingContext = clone $renderingContext;
159
            $renderingContext->getVariableProvider()->setSource($variables);
160
            $content = (new $delegate())->render($renderingContext);
161
        } elseif ($partial !== null) {
162
            $content = $view->renderPartial($partial, $section, $variables, $optional);
163
        } elseif ($section !== null) {
164
            $content = $view->renderSection($section, $variables, $optional);
165
        } elseif (!$optional) {
166
            throw new \InvalidArgumentException('ViewHelper f:render called without either argument section, partial, renderable or delegate and optional flag is false');
167
        }
168
        // Replace empty content with default value. If default is
169
        // not set, NULL is returned and cast to a new, empty string
170
        // outside of this ViewHelper.
171
        if ($content === '') {
172
            $tagContent = $tagContent ?: $renderChildrenClosure();
173
            $content = $arguments['default'] ?: $tagContent;
174
        }
175
        return $content;
176
    }
177
}
178