• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

FluidTYPO3 / vhs / 13566190336

27 Feb 2025 12:18PM UTC coverage: 72.127% (-0.6%) from 72.746%
13566190336

push

github

NamelessCoder
[TER] 7.1.0

5649 of 7832 relevant lines covered (72.13%)

20.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.82
/Classes/ViewHelpers/DebugViewHelper.php
1
<?php
2
namespace FluidTYPO3\Vhs\ViewHelpers;
3

4
/*
5
 * This file is part of the FluidTYPO3/Vhs project under GPLv2 or later.
6
 *
7
 * For the full copyright and license information, please read the
8
 * LICENSE.md file that was distributed with this source code.
9
 */
10

11
use TYPO3\CMS\Extbase\Reflection\Exception\PropertyNotAccessibleException;
12
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
13
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
14
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\NodeInterface;
15
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ObjectAccessorNode;
16
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode;
17
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
18

19
/**
20
 * ### ViewHelper Debug ViewHelper (sic)
21
 *
22
 * Debugs instances of other ViewHelpers and language
23
 * structures. Use in conjunction with other ViewHelpers
24
 * to inspect their current and possible arguments and
25
 * render their documentation:
26
 *
27
 * ```
28
 * <v:debug><f:format.html>{variable}</f:format.html></v:debug>
29
 * ```
30
 *
31
 * Or the same expression in inline syntax:
32
 *
33
 * ```
34
 * {variable -> f:format.html() -> v:debug()}
35
 * ```
36
 *
37
 * Can also be used to inspect `ObjectAccessor` instances
38
 * (e.g. variables you try to access) and rather than just
39
 * dumping the entire contents of the variable as is done
40
 * by `<f:debug />`, this ViewHelper makes a very simple
41
 * dump with a warning if the variable is not defined. If
42
 * an object is encountered (for example a domain object)
43
 * this ViewHelper will not dump the object but instead
44
 * will scan it for accessible properties (e.g. properties
45
 * which have a getter method!) and only present those
46
 * properties which can be accessed, along with the type
47
 * of variable that property currently contains:
48
 *
49
 * ```
50
 * {domainObject -> v:debug()}
51
 * ```
52
 *
53
 * Assuming that `{domainObject}` is an instance of an
54
 * object which has two methods: `getUid()` and `getTitle()`,
55
 * debugging that instance will render something like this
56
 * in plain text:
57
 *
58
 * ```
59
 * Path: {domainObject}
60
 * Value type: object
61
 * Accessible properties on {domainObject}:
62
 *    {form.uid} (integer)
63
 *    {form.title} (string)
64
 * ```
65
 *
66
 * The class itself can contain any number of protected
67
 * properties, but only those which have a getter method
68
 * can be accessed by Fluid and as therefore we only dump
69
 * those properties which you **can in fact access**.
70
 */
71
class DebugViewHelper extends AbstractViewHelper
72
{
73
    /**
74
     * @var ViewHelperNode[]
75
     */
76
    protected array $childViewHelperNodes = [];
77

78
    /**
79
     * @var ObjectAccessorNode[]
80
     */
81
    protected array $childObjectAccessorNodes = [];
82

83
    /**
84
     * @var boolean
85
     */
86
    protected $escapeOutput = false;
87

88
    /**
89
     * @var boolean
90
     */
91
    protected $escapeChildren = false;
92

93
    /**
94
     * @return string
95
     */
96
    public function render()
97
    {
98
        $nodes = [];
14✔
99
        foreach ($this->childViewHelperNodes as $viewHelperNode) {
14✔
100
            $viewHelper = $viewHelperNode->getUninitializedViewHelper();
7✔
101
            $arguments = $viewHelper->prepareArguments();
7✔
102
            $givenArguments = $viewHelperNode->getArguments();
7✔
103
            $viewHelperReflection = new \ReflectionClass($viewHelper);
7✔
104
            $viewHelperDescription = $viewHelperReflection->getDocComment();
7✔
105
            $viewHelperDescription = htmlentities((string) $viewHelperDescription);
7✔
106
            $viewHelperDescription = '[CLASS DOC]' . LF . $viewHelperDescription . LF;
7✔
107
            $renderMethodDescription = $viewHelperReflection->getMethod('render')->getDocComment();
7✔
108
            $renderMethodDescription = htmlentities((string) $renderMethodDescription);
7✔
109
            $renderMethodDescription = implode(LF, array_map('trim', explode(LF, $renderMethodDescription)));
7✔
110
            $renderMethodDescription = '[RENDER METHOD DOC]' . LF . $renderMethodDescription . LF;
7✔
111
            $argumentDefinitions = [];
7✔
112
            foreach ($arguments as $argument) {
7✔
113
                $name = $argument->getName();
×
114
                $argumentDefinitions[$name] = ObjectAccess::getGettableProperties($argument);
×
115
            }
116
            $sections = [
7✔
117
                $viewHelperDescription,
7✔
118
                DebuggerUtility::var_dump($argumentDefinitions, '[ARGUMENTS]', 4, true, false, true),
7✔
119
                DebuggerUtility::var_dump($givenArguments, '[CURRENT ARGUMENTS]', 4, true, false, true),
7✔
120
                $renderMethodDescription
7✔
121
            ];
7✔
122
            $nodes[] = implode(LF, $sections);
7✔
123
        }
124
        if (0 < count($this->childObjectAccessorNodes)) {
14✔
125
            $nodes[] = '[VARIABLE ACCESSORS]';
7✔
126
            /** @var array|object $templateVariables */
127
            $templateVariables = $this->renderingContext->getVariableProvider()->getAll();
7✔
128
            foreach ($this->childObjectAccessorNodes as $objectAccessorNode) {
7✔
129
                $path = $objectAccessorNode->getObjectPath();
7✔
130
                $segments = explode('.', $path);
7✔
131
                try {
132
                    $value = ObjectAccess::getProperty($templateVariables, array_shift($segments));
7✔
133
                    foreach ($segments as $segment) {
7✔
134
                        if (!is_array($value) && !is_object($value)) {
7✔
135
                            break;
×
136
                        }
137
                        $value = ObjectAccess::getProperty($value, $segment);
7✔
138
                    }
139
                    $type = gettype($value);
7✔
140
                } catch (PropertyNotAccessibleException $error) {
×
141
                    $value = null;
×
142
                    $type = 'UNDEFINED/INACCESSIBLE';
×
143
                }
144
                $sections = [
7✔
145
                    'Path: {' . $path . '}',
7✔
146
                    'Value type: ' . $type,
7✔
147
                ];
7✔
148
                if (is_object($value)) {
7✔
149
                    $sections[] = 'Accessible properties on {' . $path . '}:';
×
150
                    $gettable = ObjectAccess::getGettablePropertyNames($value);
×
151
                    unset($gettable[0]);
×
152
                    foreach ($gettable as $gettableProperty) {
×
153
                        $sections[] = '   {' . $path . '.' . $gettableProperty . '} (' .
×
154
                            gettype(ObjectAccess::getProperty($value, $gettableProperty)) . ')';
×
155
                    }
156
                } elseif (null !== $value) {
7✔
157
                    $sections[] = DebuggerUtility::var_dump(
7✔
158
                        $value,
7✔
159
                        'Dump of variable "' . $path . '"',
7✔
160
                        4,
7✔
161
                        true,
7✔
162
                        false,
7✔
163
                        true
7✔
164
                    );
7✔
165
                }
166
                $nodes[] = implode(LF, $sections);
7✔
167
            }
168
        }
169
        return '<pre>' . implode(LF . LF, $nodes) . '</pre>';
14✔
170
    }
171

172
    /**
173
     * Sets the direct child nodes of the current syntax tree node.
174
     *
175
     * @param NodeInterface[] $childNodes
176
     */
177
    public function setChildNodes(array $childNodes): void
178
    {
179
        foreach ($childNodes as $childNode) {
14✔
180
            if ($childNode instanceof ViewHelperNode) {
14✔
181
                $this->childViewHelperNodes[] = $childNode;
7✔
182
            } elseif ($childNode instanceof ObjectAccessorNode) {
7✔
183
                $this->childObjectAccessorNodes[] = $childNode;
7✔
184
            }
185
        }
186
    }
187
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc