Passed
Pull Request — master (#67)
by Aleksei
11:19
created

ArrayItemRenderer::renderValue()   B

Complexity

Conditions 9
Paths 7

Size

Total Lines 15
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
c 0
b 0
f 0
dl 0
loc 15
rs 8.0555
cc 9
nc 7
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Cycle\Schema\Converter\SchemaToPHP;
6
7
final class ArrayItemRenderer
8
{
9
    private const MIX_LINE_LENGTH = 120;
10
11
    public ?string $key;
12
    /** @var mixed */
13
    public $value;
14
    public bool $wrapValue = true;
15
    public bool $wrapKey;
16
17
    /**
18
     * @param null|string $key
19
     * @param mixed $value
20
     * @param bool $wrapKey
21
     */
22
    public function __construct(?string $key, $value = null, bool $wrapKey = false)
23
    {
24
        $this->key = $key;
25
        $this->value = $value;
26
        $this->wrapKey = $wrapKey;
27
    }
28
29
    public function __toString()
30
    {
31
        $result = '';
32
        if ($this->key !== null) {
33
            $result = $this->wrapKey ? "'{$this->key}' => " : "{$this->key} => ";
34
        }
35
        return $result . $this->renderValue($this->value);
36
    }
37
38
    /**
39
     * @param mixed $value
40
     * @return string
41
     */
42
    private function renderValue($value): string
43
    {
44
        switch (true) {
45
            case $value === null:
46
                return 'null';
47
            case is_bool($value):
48
                return $value ? 'true' : 'false';
49
            case is_array($value):
50
                return $this->renderArray($value);
51
            case !$this->wrapValue || is_int($value) || $value instanceof ArrayItemRenderer:
52
                return (string)$value;
53
            case is_string($value):
54
                return "'" . addslashes($value) . "'";
55
            default:
56
                return "unserialize('" . addslashes(serialize($value)) . "')";
57
        }
58
    }
59
60
    private function renderArray(array $value): string
61
    {
62
        $aiKeys = $this->isAutoIncrementedKeys($value);
63
        $inline = $aiKeys && $this->isScalarArrayValues($value);
64
        if ($inline) {
65
            $result = $this->renderArrayInline($value, !$aiKeys);
66
            if (strlen($result) <= self::MIX_LINE_LENGTH) {
67
                return $result;
68
            }
69
        }
70
        return $this->renderArrayBlock($value, !$aiKeys);
71
    }
72
73
    private function renderArrayInline(array $value, bool $withKeys = true): string
74
    {
75
        $elements = [];
76
        foreach ($value as $key => $item) {
77
            $str = '';
78
            if (!$item instanceof ArrayItemRenderer && $withKeys) {
79
                $str .= is_int($key) ? "{$key} => " : "'{$key}' => ";
80
            }
81
            $elements[] = $str . $this->renderValue($item);
82
        }
83
        return '[' . implode(', ', $elements) . ']';
84
    }
85
    private function renderArrayBlock(array $value, bool $withKeys = true): string
86
    {
87
        $result = '[';
88
        foreach ($value as $key => $item) {
89
            $result .= "\n";
90
            if (!$item instanceof ArrayItemRenderer && $withKeys) {
91
                $result .= is_int($key) ? "{$key} => " : "'{$key}' => ";
92
            }
93
            $result .= $this->renderValue($item) . ',';
94
        }
95
        return str_replace("\n", "\n    ", $result) . "\n]";
96
    }
97
98
    private function isAutoIncrementedKeys(array $array): bool
99
    {
100
        return count($array) === 0 || array_keys($array) === range(0, count($array) - 1);
101
    }
102
    private function isScalarArrayValues(array $array): bool
103
    {
104
        foreach ($array as $value) {
105
            if (!is_scalar($value)) {
106
                return false;
107
            }
108
        }
109
        return true;
110
    }
111
}
112