9
9
/**
10
10
* To support some features these commits from laravel needed to be backported for older versions:
11
11
* - [10.x] Escaping functionality within the Grammar (https://github.com/laravel/framework/commit/e953137280cdf6e0fe3c3e4c49d7209ad86c92c0).
12
+ * - [10.x] Add toRawSql, dumpRawSql() and ddRawSql() to Query Builders (https://github.com/laravel/framework/commit/830efbeeb815a5f1558433b673a58b0ddcbdc750).
13
+ * - [11.x] Allow for custom Postgres operators to be added (https://github.com/laravel/framework/commit/029e993cb976e76a8d34d6b175eed8c8af1c3ed8)
12
14
*/
13
15
trait GrammarBackport
14
16
{
@@ -18,6 +20,22 @@ trait GrammarBackport
18
20
* @var \Illuminate\Database\Connection
19
21
*/
20
22
protected $ connection ;
23
+ /**
24
+ * The Postgres grammar specific custom operators.
25
+ *
26
+ * @var array
27
+ */
28
+ protected static $ customOperators = [];
29
+
30
+ /**
31
+ * Set any Postgres grammar specific custom operators.
32
+ */
33
+ public static function customOperators (array $ operators ): void
34
+ {
35
+ static ::$ customOperators = array_values (
36
+ array_merge (static ::$ customOperators , array_filter (array_filter ($ operators , 'is_string ' )))
37
+ );
38
+ }
21
39
22
40
/**
23
41
* Escapes a value for safe SQL embedding.
@@ -34,6 +52,14 @@ public function escape($value, $binary = false): string
34
52
return $ this ->connection ->escape ($ value , $ binary );
35
53
}
36
54
55
+ /**
56
+ * Get the Postgres grammar specific operators.
57
+ */
58
+ public function getOperators (): array
59
+ {
60
+ return array_values (array_unique (array_merge ($ this ->operators , static ::$ customOperators )));
61
+ }
62
+
37
63
/**
38
64
* Set the grammar's database connection.
39
65
*
@@ -45,4 +71,49 @@ public function setConnection($connection): static
45
71
46
72
return $ this ;
47
73
}
74
+
75
+ /**
76
+ * Substitute the given bindings into the given raw SQL query.
77
+ *
78
+ * @param string $sql
79
+ * @param array $bindings
80
+ */
81
+ public function substituteBindingsIntoRawSql ($ sql , $ bindings ): string
82
+ {
83
+ $ bindings = array_map (fn ($ value ) => $ this ->escape ($ value ), $ bindings );
84
+
85
+ $ query = '' ;
86
+
87
+ $ isStringLiteral = false ;
88
+
89
+ for ($ i = 0 ; $ i < \strlen ($ sql ); ++$ i ) {
90
+ $ char = $ sql [$ i ];
91
+ $ nextChar = $ sql [$ i + 1 ] ?? null ;
92
+
93
+ // Single quotes can be escaped as '' according to the SQL standard while
94
+ // MySQL uses \'. Postgres has operators like ?| that must get encoded
95
+ // in PHP like ??|. We should skip over the escaped characters here.
96
+ if (\in_array ($ char .$ nextChar , ["\' " , "'' " , '?? ' ])) {
97
+ $ query .= $ char .$ nextChar ;
98
+ ++$ i ;
99
+ } elseif ("' " === $ char ) { // Starting / leaving string literal...
100
+ $ query .= $ char ;
101
+ $ isStringLiteral = !$ isStringLiteral ;
102
+ } elseif ('? ' === $ char && !$ isStringLiteral ) { // Substitutable binding...
103
+ $ query .= array_shift ($ bindings ) ?? '? ' ;
104
+ } else { // Normal character...
105
+ $ query .= $ char ;
106
+ }
107
+ }
108
+
109
+ foreach ($ this ->getOperators () as $ operator ) {
110
+ if (!str_contains ($ operator , '? ' )) {
111
+ continue ;
112
+ }
113
+
114
+ $ query = str_replace (str_replace ('? ' , '?? ' , $ operator ), $ operator , $ query );
115
+ }
116
+
117
+ return $ query ;
118
+ }
48
119
}
0 commit comments