Completed
Pull Request — master (#377)
by Markus
03:25
created

DebugViewHelper::initializeArguments()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 25
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 20
nc 1
nop 0
dl 0
loc 25
rs 8.8571
c 0
b 0
f 0
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 {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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 {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
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