Utils::stringifyAssocArray()   A
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 15
nc 6
nop 2
dl 0
loc 26
ccs 15
cts 15
cp 1
crap 6
rs 9.2222
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Murtukov\PHPCodeGenerator;
6
7
use Error;
8
use Exception;
9
use Murtukov\PHPCodeGenerator\Exception\UnrecognizedValueTypeException;
10
use function get_class;
11
use function is_int;
12
use function json_encode;
13
use function rtrim;
14
use function str_replace;
15
use function substr;
16
use function var_export;
17
18
class Utils
19
{
20
    const TYPE_STRING = 'string';
21
    const TYPE_INT = 'integer';
22
    const TYPE_BOOL = 'boolean';
23
    const TYPE_DOUBLE = 'double';
24
    const TYPE_OBJECT = 'object';
25
    const TYPE_ARRAY = 'array';
26
27
    /**
28
     * @var bool whether arrays should be split into multiple lines
29
     */
30
    private static ?bool $multiline = false;
31
32
    /**
33
     * @var bool defines whether arrays should be rendered with keys
34
     */
35
    private static ?bool $withKeys = false;
36
37
    /**
38
     * @var bool if true, null values are not rendered
39
     */
40
    public static bool $skipNullValues = false;
41
42
    /**
43
     * @var array custom converters registered by users
44
     */
45
    private static array $customConverters = [];
46
47
    /**
48
     * @param mixed $value
49
     *
50
     * @throws UnrecognizedValueTypeException
51
     */
52 25
    public static function stringify($value, ?bool $multiline = null, ?bool $withKeys = null, array $converters = []): string
53
    {
54
        // Common options to avoid passing them recursively
55 25
        self::$multiline = $multiline;
56 25
        self::$withKeys = $withKeys;
57 25
        self::$customConverters = $converters;
58
59 25
        return self::stringifyValue($value, true);
60
    }
61
62
    /**
63
     * @param mixed $value
64
     *
65
     * @throws UnrecognizedValueTypeException
66
     * @throws Exception
67
     */
68 25
    private static function stringifyValue($value, bool $topLevel = false): string
69
    {
70 25
        $type = gettype($value);
71
72
        // Custom converters
73 25
        if (!empty(self::$customConverters)) {
74 1
            foreach (Config::getConverterClasses($type) as $fqcn) {
75 1
                $converter = Config::getConverter($fqcn);
76 1
                if ($converter && $converter->check($value)) {
77 1
                    return (string) $converter->convert($value);
78
                }
79
            }
80
        }
81
82
        // Default converters
83 25
        switch ($type) {
84 25
            case 'boolean':
85 24
            case 'integer':
86 24
            case 'double':
87 8
                return json_encode($value);
88 24
            case 'string':
89 14
                if ('' === $value) {
90 2
                    return "''";
91
                }
92
93 12
                return var_export($value, true);
94 21
            case 'array':
95 15
                if (empty($value)) {
96 7
                    return '[]';
97
                }
98
99 9
                if (null !== self::$withKeys && true === $topLevel) {
100 5
                    return self::$withKeys
101 5
                        ? self::stringifyAssocArray($value, self::$multiline)
102 5
                        : self::stringifyNumericArray($value, self::$multiline);
103
                }
104
105 7
                return isset($value[0])
106 5
                    ? self::stringifyNumericArray($value)
107 7
                    : self::stringifyAssocArray($value);
108
109 13
            case 'object':
110 6
                if (!$value instanceof GeneratorInterface) {
111
                    try {
112 1
                        $result = json_encode($value->__toString());
113
114 1
                        return false !== $result ? $result : '[object]';
115 1
                    } catch (Error $e) {
116 1
                        $class = get_class($value);
117 1
                        throw new Exception("Cannot stringify object of class: '$class'.");
118
                    }
119
                }
120
121 5
                return (string) $value;
122 9
            case 'NULL':
123 9
                if (self::$skipNullValues) {
124 1
                    return '';
125
                }
126
127 8
                return 'null';
128
            default:
129
                throw new UnrecognizedValueTypeException('Cannot stringify value of unrecognized type.');
130
        }
131
    }
132
133
    /**
134
     * @throws UnrecognizedValueTypeException
135
     */
136 7
    private static function stringifyAssocArray(array $items, ?bool $multiline = true): string
137
    {
138 7
        $code = '';
139
140 7
        if ($multiline) {
141 7
            $code .= "\n";
142
143 7
            foreach ($items as $key => $value) {
144 7
                $key = is_int($key) ? $key : "'$key'";
145 7
                $value = self::stringifyValue($value);
146 7
                $code .= "$key => $value,\n";
147
            }
148
149 7
            $code = Utils::indent($code, false);
150
        } else {
151 2
            foreach ($items as $key => $value) {
152 2
                $key = is_int($key) ? $key : "'$key'";
153 2
                $value = self::stringifyValue($value);
154 2
                $code .= "$key => $value, ";
155
            }
156
        }
157
158
        // Remove last comma
159 7
        $code = rtrim($code, ', ');
160
161 7
        return "[$code]";
162
    }
163
164
    /**
165
     * @throws UnrecognizedValueTypeException
166
     */
167 5
    private static function stringifyNumericArray(array $items, ?bool $multiline = false): string
168
    {
169 5
        $code = '';
170
171 5
        if ($multiline) {
172 2
            $code .= "\n";
173
174 2
            foreach ($items as $value) {
175 2
                $value = self::stringifyValue($value);
176 2
                $code .= "$value,\n";
177
            }
178
179 2
            $code = Utils::indent($code, false);
180
        } else {
181 5
            foreach ($items as $value) {
182 5
                $value = self::stringifyValue($value);
183 5
                $code .= "$value, ";
184
            }
185
        }
186
187
        // Remove last comma and space
188 5
        $code = rtrim($code, ', ');
189
190 5
        return "[$code]";
191
    }
192
193 26
    public static function indent(string $code, bool $leadingIndent = true): string
194
    {
195 26
        $indent = Config::$indent;
196 26
        $code = str_replace("\n", "\n$indent", $code);
197
198 26
        if (true === $leadingIndent) {
199 19
            $code = $indent.$code;
200
        }
201
202 26
        return $code;
203
    }
204
205 25
    public static function resolveQualifier(string $path)
206
    {
207 25
        if ($portion = strrchr($path, '\\')) {
208 4
            return substr($portion, 1);
209
        }
210
211 22
        return false;
212
    }
213
}
214