[BUGFIX] Show properties of stdClass object in <f:debug>
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Utility / DebuggerUtility.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Utility;
3
4 /* *
5 * This script belongs to the Extbase framework *
6 * *
7 * It is free software; you can redistribute it and/or modify it under *
8 * the terms of the GNU Lesser General Public License as published by the *
9 * Free Software Foundation, either version 3 of the License, or (at your *
10 * option) any later version. *
11 * *
12 * This script is distributed in the hope that it will be useful, but *
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- *
14 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
15 * General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with the script. *
19 * If not, see http://www.gnu.org/licenses/lgpl.html *
20 * *
21 * The TYPO3 project - inspiring people to share! *
22 * */
23 /**
24 * This class is a backport of the corresponding class of TYPO3 Flow.
25 * All credits go to the TYPO3 Flow team.
26 */
27 /**
28 * A debugging utility class
29 *
30 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
31 * @api
32 */
33 class DebuggerUtility {
34
35 const PLAINTEXT_INDENT = ' ';
36 const HTML_INDENT = '&nbsp;&nbsp;&nbsp;';
37
38 /**
39 * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage
40 */
41 static protected $renderedObjects;
42
43 /**
44 * Hardcoded list of Extbase class names (regex) which should not be displayed during debugging
45 *
46 * @var array
47 */
48 static protected $blacklistedClassNames = array(
49 'PHPUnit_Framework_MockObject_InvocationMocker',
50 'TYPO3\\CMS\\Extbase\\Persistence\\Generic\\IdentityMap',
51 'TYPO3\\CMS\\Extbase\\Reflection\\ReflectionService',
52 'TYPO3\\CMS\\Extbase\\Object\\ObjectManager',
53 'TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Mapper\\DataMapper',
54 'TYPO3\\CMS\\Extbase\\Persistence\\Generic\\PersistenceManager',
55 'TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Qom\\QueryObjectModelFactory',
56 'TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer'
57 );
58
59 /**
60 * Hardcoded list of property names (regex) which should not be displayed during debugging
61 *
62 * @var array
63 */
64 static protected $blacklistedPropertyNames = array('warning');
65
66 /**
67 * Is set to TRUE once the CSS file is included in the current page to prevent double inclusions of the CSS file.
68 *
69 * @var boolean
70 */
71 static protected $stylesheetEchoed = FALSE;
72
73 /**
74 * Defines the max recursion depth of the dump, set to 8 due to common memory limits
75 *
76 * @var int
77 */
78 static protected $maxDepth = 8;
79
80 /**
81 * Clear the state of the debugger
82 *
83 * @return void
84 */
85 static protected function clearState() {
86 self::$renderedObjects = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
87 }
88
89 /**
90 * Renders a dump of the given value
91 *
92 * @param mixed $value
93 * @param integer $level
94 * @param boolean $plainText
95 * @param boolean $ansiColors
96 * @return string
97 */
98 static protected function renderDump($value, $level, $plainText, $ansiColors) {
99 $dump = '';
100 if (is_string($value)) {
101 $croppedValue = strlen($value) > 2000 ? substr($value, 0, 2000) . '...' : $value;
102 if ($plainText) {
103 $dump = self::ansiEscapeWrap(('"' . implode((PHP_EOL . str_repeat(self::PLAINTEXT_INDENT, ($level + 1))), str_split($croppedValue, 76)) . '"'), '33', $ansiColors) . ' (' . strlen($value) . ' chars)';
104 } else {
105 $dump = sprintf('\'<span class="debug-string">%s</span>\' (%s chars)', implode('<br />' . str_repeat(self::HTML_INDENT, ($level + 1)), str_split(htmlspecialchars($croppedValue), 76)), strlen($value));
106 }
107 } elseif (is_numeric($value)) {
108 $dump = sprintf('%s (%s)', self::ansiEscapeWrap($value, '35', $ansiColors), gettype($value));
109 } elseif (is_bool($value)) {
110 $dump = $value ? self::ansiEscapeWrap('TRUE', '32', $ansiColors) : self::ansiEscapeWrap('FALSE', '32', $ansiColors);
111 } elseif (is_null($value) || is_resource($value)) {
112 $dump = gettype($value);
113 } elseif (is_array($value)) {
114 $dump = self::renderArray($value, $level + 1, $plainText, $ansiColors);
115 } elseif (is_object($value)) {
116 $dump = self::renderObject($value, $level + 1, $plainText, $ansiColors);
117 }
118 return $dump;
119 }
120
121 /**
122 * Renders a dump of the given array
123 *
124 * @param array|\Traversable $array
125 * @param integer $level
126 * @param boolean $plainText
127 * @param boolean $ansiColors
128 * @return string
129 */
130 static protected function renderArray($array, $level, $plainText = FALSE, $ansiColors = FALSE) {
131 $content = '';
132 $count = count($array);
133
134 if ($plainText) {
135 $header = self::ansiEscapeWrap('array', '36', $ansiColors);
136 } else {
137 $header = '<span class="debug-type">array</span>';
138 }
139 $header .= $count > 0 ? '(' . $count . ' item' . ($count > 1 ? 's' : '') . ')' : '(empty)';
140 if ($level >= self::$maxDepth) {
141 if ($plainText) {
142 $header .= ' ' . self::ansiEscapeWrap('max depth', '47;30', $ansiColors);
143 } else {
144 $header .= '<span class="debug-filtered">max depth</span>';
145 }
146 } else {
147 $content = self::renderCollection($array, $level, $plainText, $ansiColors);
148 if (!$plainText) {
149 $header = ($level > 1 && $count > 0 ? '<input type="checkbox" /><span class="debug-header" >' : '<span>') . $header . '</span >';
150 }
151 }
152 if ($level > 1 && $count > 0 && !$plainText) {
153 $dump = '<span class="debug-tree">' . $header . '<span class="debug-content">' . $content . '</span></span>';
154 } else {
155 $dump = $header . $content;
156 }
157 return $dump;
158 }
159
160 /**
161 * Renders a dump of the given object
162 *
163 * @param object $object
164 * @param integer $level
165 * @param boolean $plainText
166 * @param boolean $ansiColors
167 * @return string
168 */
169 static protected function renderObject($object, $level, $plainText = FALSE, $ansiColors = FALSE) {
170 if ($object instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
171 $object = $object->_loadRealInstance();
172 }
173 $header = self::renderHeader($object, $level, $plainText, $ansiColors);
174 if ($level < self::$maxDepth && !self::isBlacklisted($object) && !(self::isAlreadyRendered($object) && $plainText !== TRUE)) {
175 $content = self::renderContent($object, $level, $plainText, $ansiColors);
176 } else {
177 $content = '';
178 }
179 if ($plainText) {
180 return $header . $content;
181 } else {
182 return '<span class="debug-tree">' . $header . '<span class="debug-content">' . $content . '</span></span>';
183 }
184 }
185
186 /**
187 * Checks if a given object or property should be excluded/filtered
188 *
189 * @param object $value An ReflectionProperty or other Object
190 * @return boolean TRUE if the given object should be filtered
191 */
192 static protected function isBlacklisted($value) {
193 $result = FALSE;
194 if ($value instanceof \ReflectionProperty) {
195 $result = (strpos(implode('|', self::$blacklistedPropertyNames), $value->getName()) > 0);
196 } elseif (is_object($value)) {
197 $result = (strpos(implode('|', self::$blacklistedClassNames), get_class($value)) > 0);
198 }
199 return $result;
200 }
201
202 /**
203 * Checks if a given object was already rendered.
204 *
205 * @param object $object
206 * @return boolean TRUE if the given object was already rendered
207 */
208 static protected function isAlreadyRendered($object) {
209 return self::$renderedObjects->contains($object);
210 }
211
212 /**
213 * Renders the header of a given object/collection. It is usually the class name along with some flags.
214 *
215 * @param object $object
216 * @param integer $level
217 * @param boolean $plainText
218 * @param boolean $ansiColors
219 * @return string The rendered header with tags
220 */
221 static protected function renderHeader($object, $level, $plainText, $ansiColors) {
222 $dump = '';
223 $persistenceType = '';
224 $className = get_class($object);
225 $classReflection = new \ReflectionClass($className);
226 if ($plainText) {
227 $dump .= self::ansiEscapeWrap($className, '36', $ansiColors);
228 } else {
229 $dump .= '<span class="debug-type">' . $className . '</span>';
230 }
231 if ($object instanceof \TYPO3\CMS\Core\SingletonInterface) {
232 $scope = 'singleton';
233 } else {
234 $scope = 'prototype';
235 }
236 if ($plainText) {
237 $dump .= ' ' . self::ansiEscapeWrap($scope, '44;37', $ansiColors);
238 } else {
239 $dump .= $scope ? '<span class="debug-scope">' . $scope . '</span>' : '';
240 }
241 if ($object instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject) {
242 if ($object->_isDirty()) {
243 $persistenceType = 'modified';
244 } elseif ($object->_isNew()) {
245 $persistenceType = 'transient';
246 } else {
247 $persistenceType = 'persistent';
248 }
249 }
250 if ($object instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage && $object->_isDirty()) {
251 $persistenceType = 'modified';
252 }
253 if ($object instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractEntity) {
254 $domainObjectType = 'entity';
255 } elseif ($object instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractValueObject) {
256 $domainObjectType = 'valueobject';
257 } else {
258 $domainObjectType = 'object';
259 }
260 if ($plainText) {
261 $dump .= ' ' . self::ansiEscapeWrap(($persistenceType . ' ' . $domainObjectType), '42;30', $ansiColors);
262 } else {
263 $dump .= '<span class="debug-ptype">' . ($persistenceType ? $persistenceType . ' ' : '') . $domainObjectType . '</span>';
264 }
265 if (strpos(implode('|', self::$blacklistedClassNames), get_class($object)) > 0) {
266 if ($plainText) {
267 $dump .= ' ' . self::ansiEscapeWrap('filtered', '47;30', $ansiColors);
268 } else {
269 $dump .= '<span class="debug-filtered">filtered</span>';
270 }
271 } elseif (self::$renderedObjects->contains($object) && !$plainText) {
272 $dump = '<a href="javascript:;" onclick="document.location.hash=\'#' . spl_object_hash($object) . '\';" class="debug-seeabove">' . $dump . '<span class="debug-filtered">see above</span></a>';
273 } elseif ($level >= self::$maxDepth && !$object instanceof \DateTime) {
274 if ($plainText) {
275 $dump .= ' ' . self::ansiEscapeWrap('max depth', '47;30', $ansiColors);
276 } else {
277 $dump .= '<span class="debug-filtered">max depth</span>';
278 }
279 } elseif ($level > 1 && !$object instanceof \DateTime && !$plainText) {
280 if (($object instanceof \Countable && count($object) === 0) || (count($classReflection->getProperties()) === 0)) {
281 $dump = '<span>' . $dump . '</span>';
282 } else {
283 $dump = '<input type="checkbox" id="' . spl_object_hash($object) . '" /><span class="debug-header">' . $dump . '</span>';
284 }
285 }
286 if ($object instanceof \Countable) {
287 $dump .= count($object) > 0 ? ' (' . count($object) . ' items)' : ' (empty)';
288 }
289 if ($object instanceof \DateTime) {
290 $dump .= ' (' . $object->format(\DateTime::RFC3339) . ', ' . $object->getTimestamp() . ')';
291 }
292 if ($object instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface && !$object->_isNew()) {
293 $dump .= ' (uid=' . $object->getUid() . ', pid=' . $object->getPid() . ')';
294 }
295 return $dump;
296 }
297
298 /**
299 * @param object $object
300 * @param integer $level
301 * @param boolean $plainText
302 * @param boolean $ansiColors
303 * @return string The rendered body content of the Object(Storage)
304 */
305 static protected function renderContent($object, $level, $plainText, $ansiColors) {
306 $dump = '';
307 if ($object instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage || $object instanceof \Iterator || $object instanceof \ArrayObject) {
308 $dump .= self::renderCollection($object, $level, $plainText, $ansiColors);
309 } else {
310 self::$renderedObjects->attach($object);
311 if (!$plainText) {
312 $dump .= '<a name="' . spl_object_hash($object) . '" id="' . spl_object_hash($object) . '"></a>';
313 }
314 if (get_class($object) === 'stdClass') {
315 $objReflection = new \ReflectionObject($object);
316 $properties = $objReflection->getProperties();
317 } else {
318 $classReflection = new \ReflectionClass(get_class($object));
319 $properties = $classReflection->getProperties();
320 }
321 foreach ($properties as $property) {
322 if (self::isBlacklisted($property)) {
323 continue;
324 }
325 $dump .= PHP_EOL . str_repeat(self::PLAINTEXT_INDENT, $level) . ($plainText ? '' : '<span class="debug-property">') . self::ansiEscapeWrap($property->getName(), '37', $ansiColors) . ($plainText ? '' : '</span>') . ' => ';
326 $property->setAccessible(TRUE);
327 $dump .= self::renderDump($property->getValue($object), $level, $plainText, $ansiColors);
328 if ($object instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject && !$object->_isNew() && $object->_isDirty($property->getName())) {
329 if ($plainText) {
330 $dump .= ' ' . self::ansiEscapeWrap('modified', '43;30', $ansiColors);
331 } else {
332 $dump .= '<span class="debug-dirty">modified</span>';
333 }
334 }
335 }
336 }
337 return $dump;
338 }
339
340 /**
341 * @param mixed $collection
342 * @param integer $level
343 * @param boolean $plainText
344 * @param boolean $ansiColors
345 * @return string
346 */
347 static protected function renderCollection($collection, $level, $plainText, $ansiColors) {
348 $dump = '';
349 foreach ($collection as $key => $value) {
350 $dump .= PHP_EOL . str_repeat(self::PLAINTEXT_INDENT, $level) . ($plainText ? '' : '<span class="debug-property">') . self::ansiEscapeWrap($key, '37', $ansiColors) . ($plainText ? '' : '</span>') . ' => ';
351 $dump .= self::renderDump($value, $level, $plainText, $ansiColors);
352 }
353 if ($collection instanceof \Iterator) {
354 $collection->rewind();
355 }
356 return $dump;
357 }
358
359 /**
360 * Wrap a string with the ANSI escape sequence for colorful output
361 *
362 * @param string $string The string to wrap
363 * @param string $ansiColors The ansi color sequence (e.g. "1;37")
364 * @param boolean $enable If FALSE, the raw string will be returned
365 * @return string The wrapped or raw string
366 */
367 static protected function ansiEscapeWrap($string, $ansiColors, $enable = TRUE) {
368 if ($enable) {
369 return '\e[' . $ansiColors . 'm' . $string . '\e[0m';
370 } else {
371 return $string;
372 }
373 }
374
375 /**
376 * A var_dump function optimized for Extbase's object structures
377 *
378 * @param mixed $variable The value to dump
379 * @param string $title optional custom title for the debug output
380 * @param integer $maxDepth Sets the max recursion depth of the dump. De- or increase the number according to your needs and memory limit.
381 * @param boolean $plainText If TRUE, the dump is in plain text, if FALSE the debug output is in HTML format.
382 * @param boolean $ansiColors If TRUE (default), ANSI color codes is added to the output, if FALSE the debug output not colored.
383 * @param boolean $return if TRUE, the dump is returned for custom post-processing (e.g. embed in custom HTML). If FALSE (default), the dump is directly displayed.
384 * @param array $blacklistedClassNames An array of class names (RegEx) to be filtered. Default is an array of some common class names.
385 * @param array $blacklistedPropertyNames An array of property names and/or array keys (RegEx) to be filtered. Default is an array of some common property names.
386 * @return string if $return is TRUE, the dump is returned. By default, the dump is directly displayed, and nothing is returned.
387 * @api
388 */
389 static public function var_dump($variable, $title = NULL, $maxDepth = 8, $plainText = FALSE, $ansiColors = TRUE, $return = FALSE, $blacklistedClassNames = NULL, $blacklistedPropertyNames = NULL) {
390 self::$maxDepth = $maxDepth;
391 if ($title === NULL) {
392 $title = 'Extbase Variable Dump';
393 }
394 $ansiColors = $plainText && $ansiColors;
395 if ($ansiColors === TRUE) {
396 $title = '\e[1m' . $title . '\e[0m';
397 }
398 if (is_array($blacklistedClassNames)) {
399 self::$blacklistedClassNames = $blacklistedClassNames;
400 }
401 if (is_array($blacklistedPropertyNames)) {
402 self::$blacklistedPropertyNames = $blacklistedPropertyNames;
403 }
404 self::clearState();
405 if (!$plainText && self::$stylesheetEchoed === FALSE) {
406 echo '
407 <style type=\'text/css\'>
408 .debug-tree{position:relative;}
409 .debug-tree input{position:absolute;top:0;left:0;cursor:pointer;opacity:0;z-index:2;}
410 .debug-tree input ~ .debug-content{display:none;}
411 .debug-tree .debug-header:before{content:"+";padding:0 2px 0 2px;margin:0 3px 0 3px;font-size:1em;font-weight:bold;color:#004fb0;border:1px #004fb0 solid;}
412 .debug-tree input:checked ~ .debug-content{display:inline;}
413 .debug-tree input:checked ~ .debug-header:before{content:"-";}
414 .Extbase-Utility-Debugger-VarDump{display:block;text-align:left;background:#b9b9b9;border:10px solid #b9b9b9;-moz-border-radius:10px;-webkit-border-radius:10px;border-radius:10px;-moz-box-shadow:0 0 20px #333;-webkit-box-shadow:0 0 20px #333;box-shadow:0 0 20px #333;z-index:999;color:#000;margin:20px 0 0;}
415 .Extbase-Utility-Debugger-VarDump-Floating{position:relative;width:96%;margin:40px auto;}
416 .Extbase-Utility-Debugger-VarDump-Top{background:#eee;font:normal bold 12px \'Lucida Grande\',sans-serif;padding:5px;}
417 .Extbase-Utility-Debugger-VarDump-Center{background:#b9b9b9 url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAkCAIAAADD4xdmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAACFJREFUeNpi/P//PwMDAwMDAxMDDAx2FsuFR+eGmpsBAwAgmgXHfd6vHgAAAABJRU5ErkJggg==) 0 18px repeat;font:normal normal 11px/18px Monospaced,\'Lucida Console\',monospace;padding:18px 10px;}
418 .Extbase-Utility-Debugger-VarDump-Center pre{background-color:transparent;margin:0;padding:0;}
419 .Extbase-Utility-Debugger-VarDump-Center,.Extbase-Utility-Debugger-VarDump-Center pre,.Extbase-Utility-Debugger-VarDump-Center p,.Extbase-Utility-Debugger-VarDump-Center a,.Extbase-Utility-Debugger-VarDump-Center strong,.Extbase-Utility-Debugger-VarDump-Center .debug-string{font:normal normal 11px/18px Monospaced,\'Lucida Console\',monospace;}
420 .Extbase-Utility-Debugger-VarDump-Center .debug-string{color:#000;white-space:normal;}
421 .Extbase-Utility-Debugger-VarDump-Center .debug-type{color:#004fb0;padding-right:4px;}
422 .Extbase-Utility-Debugger-VarDump-Center .debug-unregistered{background-color:#dce1e8;}
423 .Extbase-Utility-Debugger-VarDump-Center .debug-scope,.Extbase-Utility-Debugger-VarDump-Center .debug-ptype,.Extbase-Utility-Debugger-VarDump-Center .debug-proxy,.Extbase-Utility-Debugger-VarDump-Center .debug-filtered{color:#FFF;font-size:10px;line-height:16px;padding:1px 4px;margin-right:2px;}
424 .Extbase-Utility-Debugger-VarDump-Center .debug-scope{background-color:#3e7fe1;}
425 .Extbase-Utility-Debugger-VarDump-Center .debug-ptype{background-color:#6FBC16;}
426 .Extbase-Utility-Debugger-VarDump-Center .debug-dirty{background-color:#FFFF00;}
427 .Extbase-Utility-Debugger-VarDump-Center .debug-filtered{background-color:#8c8c8c;}
428 .Extbase-Utility-Debugger-VarDump-Center .debug-seeabove{text-decoration:none;font-style:italic;font-weight:400;}
429 .Extbase-Utility-Debugger-VarDump-Center .debug-property{color:#555;line-height:16px;padding:1px 2px;}
430 </style>';
431 self::$stylesheetEchoed = TRUE;
432 }
433 if ($plainText) {
434 $output = $title . PHP_EOL . self::renderDump($variable, 0, TRUE, $ansiColors) . PHP_EOL . PHP_EOL;
435 } else {
436 $output = '
437 <div class="Extbase-Utility-Debugger-VarDump ' . ($return ? 'Extbase-Utility-Debugger-VarDump-Inline' : 'Extbase-Utility-Debugger-VarDump-Floating') . '">
438 <div class="Extbase-Utility-Debugger-VarDump-Top">' . htmlspecialchars($title) . '</div>
439 <div class="Extbase-Utility-Debugger-VarDump-Center">
440 <pre dir="ltr">' . self::renderDump($variable, 0, FALSE, FALSE) . '</pre>
441 </div>
442 </div>
443 ';
444 }
445 if ($return === TRUE) {
446 return $output;
447 } else {
448 echo $output;
449 }
450 return '';
451 }
452 }