1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace TYPO3Fluid\Fluid\ViewHelpers; |
4
|
|
|
|
5
|
|
|
/* |
6
|
|
|
* This file belongs to the package "TYPO3 Fluid". |
7
|
|
|
* See LICENSE.txt that was shipped with this package. |
8
|
|
|
*/ |
9
|
|
|
|
10
|
|
|
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface; |
11
|
|
|
use TYPO3Fluid\Fluid\Core\Variables\VariableExtractor; |
12
|
|
|
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper; |
13
|
|
|
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* |
17
|
|
|
* |
18
|
|
|
* <code title="inline notation and custom title"> |
19
|
|
|
* {object -> f:debug(title: 'Custom title')} |
20
|
|
|
* </code> |
21
|
|
|
* <output> |
22
|
|
|
* all properties of {object} nicely highlighted (with custom title) |
23
|
|
|
* </output> |
24
|
|
|
* |
25
|
|
|
* <code title="only output the type"> |
26
|
|
|
* {object -> f:debug(typeOnly: true)} |
27
|
|
|
* </code> |
28
|
|
|
* <output> |
29
|
|
|
* the type or class name of {object} |
30
|
|
|
* </output> |
31
|
|
|
* |
32
|
|
|
* Note: This view helper is only meant to be used during development |
33
|
|
|
* |
34
|
|
|
* @api |
35
|
|
|
*/ |
36
|
|
|
class DebugViewHelper extends AbstractViewHelper |
37
|
|
|
{ |
38
|
|
|
|
39
|
|
|
use CompileWithRenderStatic; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @var boolean |
43
|
|
|
*/ |
44
|
|
|
protected $escapeChildren = false; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* @var boolean |
48
|
|
|
*/ |
49
|
|
|
protected $escapeOutput = false; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @return void |
53
|
|
|
* @throws \TYPO3Fluid\Fluid\Core\ViewHelper\Exception |
54
|
|
|
*/ |
55
|
|
|
public function initializeArguments() |
56
|
|
|
{ |
57
|
|
|
parent::initializeArguments(); |
58
|
|
|
$this->registerArgument( |
59
|
|
|
'typeOnly', |
60
|
|
|
'boolean', |
61
|
|
|
'If TRUE, debugs only the type of variables', |
62
|
|
|
false, |
63
|
|
|
false |
64
|
|
|
); |
65
|
|
|
$this->registerArgument( |
66
|
|
|
'levels', |
67
|
|
|
'integer', |
68
|
|
|
'Levels to render when rendering nested objects/arrays', |
69
|
|
|
false, |
70
|
|
|
5 |
71
|
|
|
); |
72
|
|
|
$this->registerArgument( |
73
|
|
|
'html', |
74
|
|
|
'boolean', |
75
|
|
|
'Render HTML. If FALSE, output is indented plaintext', |
76
|
|
|
false, |
77
|
|
|
false |
78
|
|
|
); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* @param array $arguments |
83
|
|
|
* @param \Closure $renderChildrenClosure |
84
|
|
|
* @param RenderingContextInterface $renderingContext |
85
|
|
|
* @return string |
86
|
|
|
*/ |
87
|
|
|
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext) |
88
|
|
|
{ |
89
|
|
|
$typeOnly = $arguments['typeOnly']; |
90
|
|
|
$expressionToExamine = $renderChildrenClosure(); |
91
|
|
|
if ($typeOnly === true) { |
92
|
|
|
return ( |
93
|
|
|
\is_object($expressionToExamine) ? \get_class($expressionToExamine) : \gettype($expressionToExamine) |
94
|
|
|
); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
return static::dumpVariable($expressionToExamine, $arguments['html'], 1, $arguments['levels']); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* @param mixed $variable |
103
|
|
|
* @param boolean $html |
104
|
|
|
* @param integer $level |
105
|
|
|
* @param integer $levels |
106
|
|
|
* @return string |
107
|
|
|
*/ |
108
|
|
|
protected static function dumpVariable($variable, $html, $level, $levels) |
109
|
|
|
{ |
110
|
|
|
$typeLabel = \is_object($variable) ? \get_class($variable) : \gettype($variable); |
111
|
|
|
|
112
|
|
|
if (!$html) { |
113
|
|
|
if (is_scalar($variable)) { |
114
|
|
|
$string = sprintf('%s %s', $typeLabel, var_export($variable, true)) . PHP_EOL; |
115
|
|
|
} elseif ($variable === null) { |
116
|
|
|
$string = 'null' . PHP_EOL; |
117
|
|
View Code Duplication |
} else { |
|
|
|
|
118
|
|
|
$string = sprintf('%s: ', $typeLabel); |
119
|
|
|
if ($level > $levels) { |
120
|
|
|
$string .= '*Recursion limited*'; |
121
|
|
|
} else { |
122
|
|
|
$string .= PHP_EOL; |
123
|
|
|
foreach (static::getValuesOfNonScalarVariable($variable) as $property => $value) { |
124
|
|
|
$string .= sprintf( |
125
|
|
|
'%s"%s": %s', |
126
|
|
|
str_repeat(' ', $level), |
127
|
|
|
$property, |
128
|
|
|
static::dumpVariable($value, $html, $level + 1, $levels) |
129
|
|
|
); |
130
|
|
|
} |
131
|
|
|
} |
132
|
|
|
} |
133
|
|
|
} else { |
134
|
|
|
if (is_scalar($variable) || $variable === null) { |
135
|
|
|
$string = sprintf( |
136
|
|
|
'<code>%s = %s</code>', |
137
|
|
|
$typeLabel, |
138
|
|
|
htmlspecialchars( |
139
|
|
|
var_export($variable, true), |
140
|
|
|
ENT_COMPAT, |
141
|
|
|
'UTF-8', |
142
|
|
|
false |
143
|
|
|
) |
144
|
|
|
); |
145
|
|
View Code Duplication |
} else { |
|
|
|
|
146
|
|
|
$string = sprintf('<code>%s</code>', $typeLabel); |
147
|
|
|
if ($level > $levels) { |
148
|
|
|
$string .= '<i>Recursion limited</i>'; |
149
|
|
|
} else { |
150
|
|
|
$string .= '<ul>'; |
151
|
|
|
foreach (static::getValuesOfNonScalarVariable($variable) as $property => $value) { |
152
|
|
|
$string .= sprintf( |
153
|
|
|
'<li>%s: %s</li>', |
154
|
|
|
$property, |
155
|
|
|
static::dumpVariable($value, $html, $level + 1, $levels) |
156
|
|
|
); |
157
|
|
|
} |
158
|
|
|
$string .= '</ul>'; |
159
|
|
|
} |
160
|
|
|
} |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
return $string; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* @param mixed $variable |
168
|
|
|
* @return array |
169
|
|
|
*/ |
170
|
|
|
protected static function getValuesOfNonScalarVariable($variable) |
171
|
|
|
{ |
172
|
|
|
if ($variable instanceof \ArrayObject || \is_array($variable)) { |
173
|
|
|
return (array)$variable; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
if ($variable instanceof \Iterator) { |
177
|
|
|
return iterator_to_array($variable); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
if (\is_resource($variable)) { |
181
|
|
|
return stream_get_meta_data($variable); |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
if ($variable instanceof \DateTimeInterface) { |
185
|
|
|
return [ |
186
|
|
|
'class' => \get_class($variable), |
187
|
|
|
'ISO8601' => $variable->format(\DateTime::ISO8601), |
188
|
|
|
'UNIXTIME' => (integer)$variable->format('U') |
189
|
|
|
]; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
$reflection = new \ReflectionObject($variable); |
193
|
|
|
$properties = $reflection->getProperties(); |
194
|
|
|
$output = []; |
195
|
|
|
foreach ($properties as $property) { |
196
|
|
|
$propertyName = $property->getName(); |
197
|
|
|
$output[$propertyName] = VariableExtractor::extract($variable, $propertyName); |
198
|
|
|
} |
199
|
|
|
return $output; |
200
|
|
|
} |
201
|
|
|
} |
202
|
|
|
|
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.