2 namespace TYPO3\CMS\Extbase\Utility;
49 'PHPUnit_Framework_MockObject_InvocationMocker',
50 \TYPO3\CMS\Extbase\Reflection\ReflectionService::class,
51 \TYPO3\CMS\Extbase\Object\ObjectManager::class,
52 \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper::class,
53 \TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager::class,
54 \TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory::class,
55 \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class
86 self::$renderedObjects = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
98 protected static function renderDump($value, $level, $plainText, $ansiColors)
101 if (is_string($value)) {
102 $croppedValue = strlen($value) > 2000 ? substr($value, 0, 2000) .
'...' : $value;
104 $dump = self::ansiEscapeWrap((
'"' . implode((PHP_EOL . str_repeat(self::PLAINTEXT_INDENT, ($level + 1))), str_split($croppedValue, 76)) .
'"'),
'33', $ansiColors) .
' (' . strlen($value) .
' chars)';
106 $dump = sprintf(
'\'<span
class=
"extbase-debug-string">%s</span>\
' (%s chars)', implode(
'<br />' . str_repeat(self::HTML_INDENT, ($level + 1)), str_split(htmlspecialchars($croppedValue), 76)), strlen($value));
108 }
elseif (is_numeric($value)) {
109 $dump = sprintf(
'%s (%s)', self::ansiEscapeWrap($value,
'35', $ansiColors), gettype($value));
110 }
elseif (is_bool($value)) {
111 $dump = $value ? self::ansiEscapeWrap(
'TRUE',
'32', $ansiColors) : self::ansiEscapeWrap(
'FALSE',
'32', $ansiColors);
112 }
elseif (is_null($value) || is_resource($value)) {
113 $dump = gettype($value);
114 }
elseif (is_array($value)) {
115 $dump = self::renderArray($value, $level + 1, $plainText, $ansiColors);
116 }
elseif (is_object($value)) {
117 $dump = self::renderObject($value, $level + 1, $plainText, $ansiColors);
131 protected static function renderArray($array, $level, $plainText =
false, $ansiColors =
false)
134 $count = count($array);
137 $header = self::ansiEscapeWrap(
'array',
'36', $ansiColors);
139 $header =
'<span class="extbase-debug-type">array</span>';
141 $header .= $count > 0 ?
'(' . $count .
' item' . ($count > 1 ?
's' :
'') .
')' :
'(empty)';
142 if ($level >= self::$maxDepth) {
144 $header .=
' ' . self::ansiEscapeWrap(
'max depth',
'47;30', $ansiColors);
146 $header .=
'<span class="extbase-debug-filtered">max depth</span>';
149 $content = self::renderCollection($array, $level, $plainText, $ansiColors);
151 $header = ($level > 1 && $count > 0 ?
'<input type="checkbox" /><span class="extbase-debug-header" >' :
'<span>') . $header .
'</span >';
154 if ($level > 1 && $count > 0 && !$plainText) {
155 $dump =
'<span class="extbase-debugger-tree">' . $header .
'<span class="extbase-debug-content">' . $content .
'</span></span>';
157 $dump = $header . $content;
171 protected static function renderObject($object, $level, $plainText =
false, $ansiColors =
false)
173 if ($object instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
174 $object = $object->_loadRealInstance();
176 $header = self::renderHeader($object, $level, $plainText, $ansiColors);
177 if ($level < self::$maxDepth && !self::isBlacklisted($object) && !(self::isAlreadyRendered($object) && $plainText !==
true)) {
178 $content = self::renderContent($object, $level, $plainText, $ansiColors);
183 return $header . $content;
185 return '<span class="extbase-debugger-tree">' . $header .
'<span class="extbase-debug-content">' . $content .
'</span></span>';
198 if ($value instanceof \ReflectionProperty) {
199 $result = (strpos(implode(
'|', self::$blacklistedPropertyNames), $value->getName()) > 0);
200 }
elseif (is_object($value)) {
201 $result = (strpos(implode(
'|', self::$blacklistedClassNames), get_class($value)) > 0);
214 return self::$renderedObjects->contains($object);
226 protected static function renderHeader($object, $level, $plainText, $ansiColors)
229 $persistenceType =
'';
230 $className = get_class($object);
231 $classReflection = new \ReflectionClass($className);
233 $dump .= self::ansiEscapeWrap($className,
'36', $ansiColors);
235 $dump .=
'<span class="extbase-debug-type">' . $className .
'</span>';
237 if ($object instanceof \TYPO3\CMS\Core\SingletonInterface) {
238 $scope =
'singleton';
240 $scope =
'prototype';
243 $dump .=
' ' . self::ansiEscapeWrap($scope,
'44;37', $ansiColors);
245 $dump .= $scope ?
'<span class="extbase-debug-scope">' . $scope .
'</span>' :
'';
247 if ($object instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject) {
248 if ($object->_isDirty()) {
249 $persistenceType =
'modified';
250 }
elseif ($object->_isNew()) {
251 $persistenceType =
'transient';
253 $persistenceType =
'persistent';
256 if ($object instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage && $object->_isDirty()) {
257 $persistenceType =
'modified';
259 if ($object instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractEntity) {
260 $domainObjectType =
'entity';
261 }
elseif ($object instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractValueObject) {
262 $domainObjectType =
'valueobject';
264 $domainObjectType =
'object';
267 $dump .=
' ' . self::ansiEscapeWrap(($persistenceType .
' ' . $domainObjectType),
'42;30', $ansiColors);
269 $dump .=
'<span class="extbase-debug-ptype">' . ($persistenceType ? $persistenceType .
' ' :
'') . $domainObjectType .
'</span>';
271 if (strpos(implode(
'|', self::$blacklistedClassNames), get_class($object)) > 0) {
273 $dump .=
' ' . self::ansiEscapeWrap(
'filtered',
'47;30', $ansiColors);
275 $dump .=
'<span class="extbase-debug-filtered">filtered</span>';
277 }
elseif (self::$renderedObjects->contains($object) && !$plainText) {
278 $dump =
'<a href="javascript:;" onclick="document.location.hash=\'#' . spl_object_hash($object) .
'\';
" class="extbase-
debug-seeabove
">' . $dump . '<span class="extbase-
debug-filtered
">see above</span></a>';
279 } elseif ($level >= self::$maxDepth && !$object instanceof \DateTime) {
281 $dump .= ' ' . self::ansiEscapeWrap('max depth', '47;30', $ansiColors);
283 $dump .= '<span class="extbase-
debug-filtered
">max depth</span>';
285 } elseif ($level > 1 && !$object instanceof \DateTime && !$plainText) {
286 if (($object instanceof \Countable && empty($object)) || empty($classReflection->getProperties())) {
287 $dump = '<span>' . $dump . '</span>';
289 $dump = '<input type="checkbox
" id="' . spl_object_hash($object) . '" /><span class="extbase-
debug-header
">' . $dump . '</span>';
292 if ($object instanceof \Countable) {
293 $objectCount = count($object);
294 $dump .= $objectCount > 0 ? ' (' . $objectCount . ' items)' : ' (empty)';
296 if ($object instanceof \DateTime) {
297 $dump .= ' (' . $object->format(\DateTime::RFC3339) . ', ' . $object->getTimestamp() . ')';
299 if ($object instanceof \TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface && !$object->_isNew()) {
300 $dump .= ' (uid=' . $object->getUid() . ', pid=' . $object->getPid() . ')';
312 protected static function renderContent($object, $level, $plainText, $ansiColors)
315 if ($object instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage || $object instanceof \Iterator || $object instanceof \ArrayObject) {
316 $dump .= self::renderCollection($object, $level, $plainText, $ansiColors);
318 self::$renderedObjects->attach($object);
320 $dump .= '<a name="' . spl_object_hash($object) . '" id="' . spl_object_hash($object) . '"></a>';
322 if (get_class($object) === 'stdClass') {
323 $objReflection = new \ReflectionObject($object);
324 $properties = $objReflection->getProperties();
326 $classReflection = new \ReflectionClass(get_class($object));
327 $properties = $classReflection->getProperties();
329 foreach ($properties as $property) {
330 if (self::isBlacklisted($property)) {
333 $dump .= PHP_EOL . str_repeat(self::PLAINTEXT_INDENT, $level) . ($plainText ? '' : '<span class="extbase-
debug-
property">') . self::ansiEscapeWrap($property->getName(), '37', $ansiColors) . ($plainText ? '' : '</span>') . ' => ';
334 $property->setAccessible(true);
335 $dump .= self::renderDump($property->getValue($object), $level, $plainText, $ansiColors);
336 if ($object instanceof \TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject && !$object->_isNew() && $object->_isDirty($property->getName())) {
338 $dump .= ' ' . self::ansiEscapeWrap('modified', '43;30', $ansiColors);
340 $dump .= '<span class="extbase-
debug-dirty
">modified</span>';
355 protected static function renderCollection($collection, $level, $plainText, $ansiColors)
358 foreach ($collection as $key => $value) {
359 $dump .= PHP_EOL . str_repeat(self::PLAINTEXT_INDENT, $level) . ($plainText ? '' : '<span class="extbase-
debug-
property">') . self::ansiEscapeWrap($key, '37', $ansiColors) . ($plainText ? '' : '</span>') . ' => ';
360 $dump .= self::renderDump($value, $level, $plainText, $ansiColors);
362 if ($collection instanceof \Iterator) {
363 $collection->rewind();
376 protected static function ansiEscapeWrap($string, $ansiColors, $enable = true)
379 return '[' . $ansiColors . 'm' . $string . '[0m';
399 public static function var_dump($variable, $title = null, $maxDepth = 8, $plainText = false, $ansiColors = true, $return = false, $blacklistedClassNames = null, $blacklistedPropertyNames = null)
401 self::$maxDepth = $maxDepth;
402 if ($title === null) {
403 $title = 'Extbase Variable Dump';
405 $ansiColors = $plainText && $ansiColors;
406 if ($ansiColors === true) {
407 $title = '[1m' . $title . '[0m';
409 if (is_array($blacklistedClassNames)) {
410 self::$blacklistedClassNames = $blacklistedClassNames;
412 if (is_array($blacklistedPropertyNames)) {
413 self::$blacklistedPropertyNames = $blacklistedPropertyNames;
416 if (!$plainText && self::$stylesheetEchoed === false) {
418 <style type=\'text/css\'>
419 .extbase-debugger-tree{position:relative}
420 .extbase-debugger-tree input{position:absolute;top:0;left:0;height:14px;width:14px;margin:0;cursor:pointer;opacity:0;z-index:2}
421 .extbase-debugger-tree input~.extbase-debug-content{display:none}
422 .extbase-debugger-tree .extbase-debug-header:before{position:relative;top:3px;content:"";padding:0;line-height:10px;height:12px;width:12px;text-align:center;margin:0 3px 0 0;background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkViZW5lXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTIgMTIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEyIDEyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHN0eWxlIHR5cGU9InRleHQvY3NzIj4uc3Qwe2ZpbGw6Izg4ODg4ODt9PC9zdHlsZT48cGF0aCBpZD0iQm9yZGVyIiBjbGFzcz0ic3QwIiBkPSJNMTEsMTFIMFYwaDExVjExeiBNMTAsMUgxdjloOVYxeiIvPjxnIGlkPSJJbm5lciI+PHJlY3QgeD0iMiIgeT0iNSIgY2xhc3M9InN0MCIgd2lkdGg9IjciIGhlaWdodD0iMSIvPjxyZWN0IHg9IjUiIHk9IjIiIGNsYXNzPSJzdDAiIHdpZHRoPSIxIiBoZWlnaHQ9IjciLz48L2c+PC9zdmc+);display:inline-block}
423 .extbase-debugger-tree input:checked~.extbase-debug-content{display:inline}
424 .extbase-debugger-tree input:checked~.extbase-debug-header:before{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkViZW5lXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTIgMTIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDEyIDEyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHN0eWxlIHR5cGU9InRleHQvY3NzIj4uc3Qwe2ZpbGw6Izg4ODg4ODt9PC9zdHlsZT48cGF0aCBpZD0iQm9yZGVyIiBjbGFzcz0ic3QwIiBkPSJNMTEsMTFIMFYwaDExVjExeiBNMTAsMUgxdjloOVYxeiIvPjxnIGlkPSJJbm5lciI+PHJlY3QgeD0iMiIgeT0iNSIgY2xhc3M9InN0MCIgd2lkdGg9IjciIGhlaWdodD0iMSIvPjwvZz48L3N2Zz4=)}
425 .extbase-debugger{display:block;text-align:left;background:#2a2a2a;border:1px solid #2a2a2a;box-shadow:0 3px 0 rgba(0,0,0,.5);color:#000;margin:20px;overflow:hidden;border-radius:4px}
426 .extbase-debugger-floating{position:relative;z-index:999}
427 .extbase-debugger-top{background:#444;font-size:12px;font-family:monospace;color:#f1f1f1;padding:6px 15px}
428 .extbase-debugger-center{padding:0 15px;margin:15px 0;background-image:repeating-linear-gradient(to bottom,transparent 0,transparent 20px,#252525 20px,#252525 40px)}
429 .extbase-debugger-center,.extbase-debugger-center .extbase-debug-string,.extbase-debugger-center a,.extbase-debugger-center p,.extbase-debugger-center pre,.extbase-debugger-center strong{font-size:12px;font-weight:400;font-family:monospace;line-height:20px;color:#f1f1f1}
430 .extbase-debugger-center pre{background-color:transparent;margin:0;padding:0;border:0;word-wrap:break-word;color:#999}
431 .extbase-debugger-center .extbase-debug-string{color:#ce9178;white-space:normal}
432 .extbase-debugger-center .extbase-debug-type{color:#569CD6;padding-right:4px}
433 .extbase-debugger-center .extbase-debug-unregistered{background-color:#dce1e8}
434 .extbase-debugger-center .extbase-debug-filtered,.extbase-debugger-center .extbase-debug-proxy,.extbase-debugger-center .extbase-debug-ptype,.extbase-debugger-center .extbase-debug-scope{color:#fff;font-size:10px;line-height:12px;padding:2px 4px;margin-right:2px;position:relative;top:-1px}
435 .extbase-debugger-center .extbase-debug-scope{background-color:#497AA2}
436 .extbase-debugger-center .extbase-debug-ptype{background-color:#698747}
437 .extbase-debugger-center .extbase-debug-dirty{background-color:#FFFFB6}
438 .extbase-debugger-center .extbase-debug-filtered{background-color:#4F4F4F}
439 .extbase-debugger-center .extbase-debug-seeabove{text-decoration:none;font-style:italic}
440 .extbase-debugger-center .extbase-debug-property{color:#f1f1f1}
442 self::$stylesheetEchoed = true;
445 $output = $title . PHP_EOL . self::renderDump($variable, 0, true, $ansiColors) . PHP_EOL . PHP_EOL;
448 <div class="extbase-debugger
' . ($return ? 'extbase-debugger-
inline' : 'extbase-debugger-floating
') . '">
449 <div class="extbase-debugger-top
">' . htmlspecialchars($title) . '</div>
450 <div class="extbase-debugger-center
">
451 <pre dir="ltr
">' . self::renderDump($variable, 0, false, false) . '</pre>
456 if ($return === true) {