PHPArrayToPostgresValueTransformer   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 84
Duplicated Lines 0 %

Test Coverage

Coverage 97.37%

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 39
c 1
b 1
f 0
dl 0
loc 84
ccs 37
cts 38
cp 0.9737
rs 10
wmc 15

2 Methods

Rating   Name   Duplication   Size   Complexity  
A transformToPostgresTextArray() 0 17 3
C formatValue() 0 51 12
1
<?php
2
3
declare(strict_types=1);
4
5
namespace MartinGeorgiev\Utils;
6
7
use MartinGeorgiev\Utils\Exception\InvalidArrayFormatException;
8
9
/**
10
 * Handles transformation from PHP values to PostgreSQL values.
11
 *
12
 * @since 3.0
13
 *
14
 * @author Martin Georgiev <[email protected]>
15
 */
16
class PHPArrayToPostgresValueTransformer
17
{
18
    private const POSTGRESQL_EMPTY_ARRAY = '{}';
19
20
    /**
21
     * Transforms a PHP array to a PostgreSQL text array.
22
     * This method supports only single-dimensioned PHP arrays.
23
     * This method relays on the default escaping strategy in PostgreSQL (double quotes).
24
     *
25
     * @throws InvalidArrayFormatException when the input is a multi-dimensional array or has invalid format
26
     */
27 30
    public static function transformToPostgresTextArray(array $phpArray): string
28
    {
29 30
        if ($phpArray === []) {
30 1
            return self::POSTGRESQL_EMPTY_ARRAY;
31
        }
32
33 29
        if (\array_filter($phpArray, 'is_array')) {
34 4
            throw InvalidArrayFormatException::multiDimensionalArrayNotSupported();
35
        }
36
37
        /** @var array<int|string, string> */
38 25
        $processed = \array_map(
39 25
            self::formatValue(...),
40 25
            $phpArray
41 25
        );
42
43 25
        return '{'.\implode(',', $processed).'}';
44
    }
45
46
    /**
47
     * Formats a single value for PostgreSQL array.
48
     */
49 25
    private static function formatValue(mixed $value): string
0 ignored issues
show
Unused Code introduced by
The method formatValue() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
50
    {
51 25
        if ($value === null) {
52 3
            return 'NULL';
53
        }
54
55 24
        if (\is_int($value) || \is_float($value)) {
56 4
            return (string) $value;
57
        }
58
59 22
        if (\is_bool($value)) {
60 3
            return $value ? 'true' : 'false';
61
        }
62
63 20
        if (\is_object($value)) {
64 4
            if (\method_exists($value, '__toString')) {
65 2
                $stringValue = $value->__toString();
66
            } else {
67
                // For objects without __toString, use a default representation
68 2
                $stringValue = $value::class;
69
            }
70 17
        } elseif (\is_resource($value)) {
71 1
            $stringValue = '(resource)';
72
        } else {
73 16
            $valueType = \get_debug_type($value);
74
75 16
            if ($valueType === 'string') {
76 15
                $stringValue = $value;
77 1
            } elseif (\in_array($valueType, ['int', 'float', 'bool'], true)) {
78
                /** @var bool|float|int $value */
79
                $stringValue = (string) $value;
80
            } else {
81 1
                $stringValue = $valueType;
82
            }
83
        }
84
85 20
        \assert(\is_string($stringValue));
86
87 20
        if ($stringValue === '') {
88 3
            return '""';
89
        }
90
91
        // Make sure strings are quoted, PostgreSQL will handle this gracefully
92
        // Double the backslashes and escape quotes
93 19
        $escaped = \str_replace(
94 19
            ['\\', '"'],
95 19
            ['\\\\', '\"'],
96 19
            $stringValue
97 19
        );
98
99 19
        return '"'.$escaped.'"';
100
    }
101
}
102