Passed
Pull Request — 2.x (#56)
by
unknown
19:39
created

Interpolator::replaceOnce()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 3
dl 0
loc 11
ccs 4
cts 5
cp 0.8
crap 2.032
rs 10
c 0
b 0
f 0
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\Query;
13
14
use Cycle\Database\Injection\ParameterInterface;
15
use DateTimeInterface;
16
17
/**
18
 * Simple helper class used to interpolate query with given values. To be used for profiling and
19
 * debug purposes only.
20
 */
21
final class Interpolator
22
{
23
    /**
24
     * Injects parameters into statement. For debug purposes only.
25
     *
26
     * @psalm-param non-empty-string $query
27
     *
28
     * @psalm-return non-empty-string
29
     */
30 3730
    public static function interpolate(string $query, iterable $parameters = []): string
31
    {
32 3730
        if ($parameters === []) {
33 3724
            return $query;
34
        }
35
36
        $lastPosition = 0;
37 2026
        $replaceOnce = static function (
38 2026
            string $search,
39 20
            string $replace,
40 20
            string $subject
41 20
        ) use (&$lastPosition): string {
42
            $position = strpos($subject, $search, $lastPosition);
43
            if ($position !== false) {
44 20
                $subject = substr_replace($subject, $replace, $position, strlen($search));
45
                $lastPosition = $position + strlen($replace);
46
            }
47 2022
48 2022
            return $subject;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $subject could return the type array which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
49 2022
        };
50
51
        //Let's prepare values so they looks better
52
        foreach ($parameters as $index => $parameter) {
53
            $mask = is_numeric($index) ? ':' . ltrim($index, ':') : '?';
54 2026
55
            $query = $replaceOnce($mask, self::resolveValue($parameter), $query);
56
        }
57
58
        return $query;
59
    }
60
61
    /**
62 2026
     * Get parameter value.
63
     *
64 2026
     * @psalm-return non-empty-string
65 432
     */
66
    protected static function resolveValue(mixed $parameter): string
67
    {
68 2026
        if ($parameter instanceof ParameterInterface) {
69 2026
            return self::resolveValue($parameter->getValue());
70
        }
71
72 2026
        switch (gettype($parameter)) {
73 590
            case 'boolean':
74
                return $parameter ? 'TRUE' : 'FALSE';
75 2026
76 24
            case 'integer':
77
                return (string)($parameter + 0);
78 2026
79
            case 'NULL':
80
                return 'NULL';
81 2026
82 2026
            case 'double':
83
                return sprintf('%F', $parameter);
84 20
85 12
            case 'string':
86
                return "'" . addcslashes($parameter, "'") . "'";
87
88
            case 'object':
89 12
                if (method_exists($parameter, '__toString')) {
90 12
                    return "'" . addcslashes((string)$parameter, "'") . "'";
91
                }
92
93
                if ($parameter instanceof DateTimeInterface) {
94 8
                    return "'" . $parameter->format(DateTimeInterface::ATOM) . "'";
95
                }
96
        }
97
98
        return '[UNRESOLVED]';
99
    }
100
}
101