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

FluidTYPO3 / vhs / 30001290505

23 Jul 2026 10:57AM UTC coverage: 70.309% (-1.7%) from 72.022%
30001290505

push

github

NamelessCoder
[TER] 8.0.0

4819 of 6854 relevant lines covered (70.31%)

6.54 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 FluidTYPO3\Vhs\Core\ViewHelper\AbstractViewHelper;
12
use TYPO3\CMS\Extbase\Reflection\Exception\PropertyNotAccessibleException;
13
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
14
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
15
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ObjectAccessorNode;
16
use TYPO3Fluid\Fluid\Core\Parser\SyntaxTree\ViewHelperNode;
17

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

77
    /**
78
     * @var boolean
79
     */
80
    protected $escapeChildren = false;
81

82
    public function render(): string
83
    {
84
        $nodes = [];
6✔
85
        $objectAccessorNodes = [];
6✔
86
        foreach (((array) $this->viewHelperNode?->getChildNodes()) as $node) {
6✔
87
            if ($node instanceof ObjectAccessorNode) {
6✔
88
                $objectAccessorNodes[] = $node;
3✔
89
            }
90
            if (!$node instanceof ViewHelperNode) {
6✔
91
                continue;
3✔
92
            }
93
            $viewHelper = $node->getUninitializedViewHelper();
3✔
94
            $arguments = $viewHelper->prepareArguments();
3✔
95
            $givenArguments = $node->getArguments();
3✔
96
            $viewHelperReflection = new \ReflectionClass($viewHelper);
3✔
97
            $viewHelperDescription = $viewHelperReflection->getDocComment();
3✔
98
            $viewHelperDescription = htmlentities((string) $viewHelperDescription);
3✔
99
            $viewHelperDescription = '[CLASS DOC]' . PHP_EOL . $viewHelperDescription . PHP_EOL;
3✔
100
            $renderMethodDescription = $viewHelperReflection->getMethod('render')->getDocComment();
3✔
101
            $renderMethodDescription = htmlentities((string) $renderMethodDescription);
3✔
102
            $renderMethodDescription = implode(PHP_EOL, array_map('trim', explode(PHP_EOL, $renderMethodDescription)));
3✔
103
            $renderMethodDescription = '[RENDER METHOD DOC]' . PHP_EOL . $renderMethodDescription . PHP_EOL;
3✔
104
            $argumentDefinitions = [];
3✔
105
            foreach ($arguments as $argument) {
3✔
106
                $name = $argument->getName();
×
107
                $argumentDefinitions[$name] = ObjectAccess::getGettableProperties($argument);
×
108
            }
109
            $sections = [
3✔
110
                $viewHelperDescription,
3✔
111
                DebuggerUtility::var_dump($argumentDefinitions, '[ARGUMENTS]', 4, true, false, true),
3✔
112
                DebuggerUtility::var_dump($givenArguments, '[CURRENT ARGUMENTS]', 4, true, false, true),
3✔
113
                $renderMethodDescription
3✔
114
            ];
3✔
115
            $nodes[] = implode(PHP_EOL, $sections);
3✔
116
        }
117
        if (0 < count($objectAccessorNodes)) {
6✔
118
            $nodes[] = '[VARIABLE ACCESSORS]';
3✔
119
            /** @var array|object $templateVariables */
120
            $templateVariables = $this->renderingContext->getVariableProvider()->getAll();
3✔
121
            foreach ($objectAccessorNodes as $objectAccessorNode) {
3✔
122
                $path = $objectAccessorNode->getObjectPath();
3✔
123
                $segments = explode('.', $path);
3✔
124
                try {
125
                    $value = ObjectAccess::getProperty($templateVariables, array_shift($segments));
3✔
126
                    foreach ($segments as $segment) {
3✔
127
                        if (!is_array($value) && !is_object($value)) {
3✔
128
                            break;
×
129
                        }
130
                        $value = ObjectAccess::getProperty($value, $segment);
3✔
131
                    }
132
                    $type = gettype($value);
3✔
133
                } catch (PropertyNotAccessibleException $error) {
×
134
                    $value = null;
×
135
                    $type = 'UNDEFINED/INACCESSIBLE';
×
136
                }
137
                $sections = [
3✔
138
                    'Path: {' . $path . '}',
3✔
139
                    'Value type: ' . $type,
3✔
140
                ];
3✔
141
                if (is_object($value)) {
3✔
142
                    $sections[] = 'Accessible properties on {' . $path . '}:';
×
143
                    $gettable = ObjectAccess::getGettablePropertyNames($value);
×
144
                    unset($gettable[0]);
×
145
                    foreach ($gettable as $gettableProperty) {
×
146
                        $sections[] = '   {' . $path . '.' . $gettableProperty . '} (' .
×
147
                            gettype(ObjectAccess::getProperty($value, $gettableProperty)) . ')';
×
148
                    }
149
                } elseif (null !== $value) {
3✔
150
                    $sections[] = DebuggerUtility::var_dump(
3✔
151
                        $value,
3✔
152
                        'Dump of variable "' . $path . '"',
3✔
153
                        4,
3✔
154
                        true,
3✔
155
                        false,
3✔
156
                        true
3✔
157
                    );
3✔
158
                }
159
                $nodes[] = implode(PHP_EOL, $sections);
3✔
160
            }
161
        }
162
        return '<pre>' . implode(PHP_EOL . PHP_EOL, $nodes) . '</pre>';
6✔
163
    }
164
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc