Passed
Pull Request — 2.x (#135)
by Aleksei
18:00
created

JsonExpression::__toString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
/**
4
 * This file is part of Cycle ORM package.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\Database\Injection;
13
14
use Cycle\Database\Driver\CompilerInterface;
15
use Cycle\Database\Driver\Quoter;
16
17
abstract class JsonExpression implements FragmentInterface
18
{
19
    protected string $expression;
20
    protected Quoter $quoter;
21
22
    /**
23
     * @var ParameterInterface[]
24
     */
25
    protected array $parameters = [];
26
27
    /**
28
     * @psalm-param non-empty-string $statement
29
     */
30
    public function __construct(string $statement, mixed ...$parameters)
31
    {
32
        $this->quoter = new Quoter('', $this->getQuotes());
33
34
        $this->expression = $this->compile($statement);
35
36
        foreach ($parameters as $parameter) {
37
            if ($parameter instanceof ParameterInterface) {
38
                $this->parameters[] = $parameter;
39
            } else {
40
                $this->parameters[] = new Parameter($parameter);
41
            }
42
        }
43
    }
44
45
    public function __toString(): string
46
    {
47
        return 'exp:' . $this->expression;
48
    }
49
50
    public static function __set_state(array $an_array): self
51
    {
52
        return new static(
53
            $an_array['expression'] ?? $an_array['statement'],
54
            ...($an_array['parameters'] ?? [])
55
        );
56
    }
57
58
    public function getType(): int
59
    {
60
        return CompilerInterface::JSON_EXPRESSION;
61
    }
62
63
    public function getTokens(): array
64
    {
65
        return [
66
            'expression' => $this->expression,
67
            'parameters' => $this->parameters,
68
        ];
69
    }
70
71
    abstract protected function compile(string $statement): string;
72
73
    /**
74
     * @param non-empty-string $value
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
75
     * @param non-empty-string $delimiter
76
     *
77
     * @return non-empty-string
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
78
     */
79
    public function wrapPath(string $value, string $delimiter = '->'): string
80
    {
81
        $value = \preg_replace("/([\\\\]+)?\\'/", "''", $value);
82
83
        $segments = \explode($delimiter, $value);
84
        $jsonPath = \implode('.', \array_map(fn ($segment): string => $this->wrapJsonPathSegment($segment), $segments));
85
86
        return "'$" . (\str_starts_with($jsonPath, '[') ? '' : '.') . $jsonPath . "'";
87
    }
88
89
    /**
90
     * @param non-empty-string $segment
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
91
     *
92
     * @return non-empty-string
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
93
     */
94
    protected function wrapJsonPathSegment(string $segment): string
95
    {
96
        if (\preg_match('/(\[[^\]]+\])+$/', $segment, $parts)) {
97
            $key = \substr($segment, 0, \strpos($segment, $parts[0]));
98
99
            if (!empty($key)) {
100
                return '"' . $key . '"' . $parts[0];
101
            }
102
103
            return $parts[0];
104
        }
105
106
        return '"' . $segment . '"';
107
    }
108
109
    /**
110
     * @param non-empty-string $attribute
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
111
     *
112
     * @return array<non-empty-string>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<non-empty-string> at position 2 could not be parsed: Unknown type name 'non-empty-string' at position 2 in array<non-empty-string>.
Loading history...
113
     */
114
    protected function parseJsonPathArrayKeys(string $attribute): array
115
    {
116
        if (\preg_match('/(\[[^\]]+\])+$/', $attribute, $parts)) {
117
            $key = \substr($attribute, 0, \strpos($attribute, $parts[0]));
118
119
            \preg_match_all('/\[([^\]]+)\]/', $parts[0], $matches);
120
            $keys = $matches[1];
121
122
            $cleanKeys = \array_values(\array_filter($keys, static fn ($key) => $key !== ''));
123
124
            return \array_merge([$key], $cleanKeys);
125
        }
126
127
        return [$attribute];
128
    }
129
130
    protected function getQuotes(): string
131
    {
132
        return '""';
133
    }
134
}
135