1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace HexMakina\Crudites\Grammar; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* An abstract class representing a SQL predicate. |
7
|
|
|
* Instantiate and __toString(). |
8
|
|
|
* |
9
|
|
|
* @package HexMakina\Crudites\Grammar\Query |
10
|
|
|
*/ |
11
|
|
|
class Predicate extends Grammar |
12
|
|
|
{ |
13
|
|
|
protected $left; |
14
|
|
|
protected ?string $operator = null; |
15
|
|
|
protected $right = null; |
16
|
|
|
|
17
|
|
|
protected ?string $bind_label = null; |
18
|
|
|
|
19
|
|
|
protected array $bindings = []; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Predicate constructor. |
23
|
|
|
* The constructor takes a left side expression, an operator, and a right side expression. |
24
|
|
|
* The left and right side expressions can be either strings or arrays. |
25
|
|
|
* If an array is provided, the first element is the table name and the second element is the column name. |
26
|
|
|
* The constructor also adds backticks to the column names. |
27
|
|
|
* |
28
|
|
|
* |
29
|
|
|
* @param mixed $left, left side expression |
30
|
|
|
* @param string $operator, operator to use |
31
|
|
|
* @param mixed $right, right side expression |
32
|
|
|
*/ |
33
|
|
|
public function __construct($left, string $operator = null, $right = null) |
34
|
|
|
{ |
35
|
|
|
$this->left = $left; |
36
|
|
|
$this->operator = $operator; |
37
|
|
|
$this->right = $right; |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Converts the predicate to a string. |
42
|
|
|
* |
43
|
|
|
* @return string The string representation of the predicate. |
44
|
|
|
*/ |
45
|
|
|
public function __toString() |
46
|
|
|
{ |
47
|
|
|
$left = is_array($this->left) ? self::identifier($this->left) : ($this->left ?? ''); |
48
|
|
|
$right = is_array($this->right) ? self::identifier($this->right) : ($this->right ?? ''); |
49
|
|
|
return trim(sprintf('%s %s %s', $left, $this->operator ?? '', $right)); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Gets the bindings for the predicate. |
54
|
|
|
* |
55
|
|
|
* @return array The bindings for the predicate. |
56
|
|
|
*/ |
57
|
|
|
public function bindings(): array |
58
|
|
|
{ |
59
|
|
|
return $this->bindings ?? []; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Gets the binding label for the predicate. |
64
|
|
|
* |
65
|
|
|
* @return string The binding label for the predicate. |
66
|
|
|
*/ |
67
|
|
|
public function bindLabel(string $prefix = null): string |
68
|
|
|
{ |
69
|
|
|
if($this->bind_label !== null) |
70
|
|
|
return $this->bind_label; |
71
|
|
|
|
72
|
|
|
if(is_string($this->right)) |
73
|
|
|
$this->bind_label = $this->right; |
74
|
|
|
else{ |
75
|
|
|
$this->bind_label = is_array($this->left) ? implode('_', $this->left) : $this->left; |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
if($prefix !== null) |
79
|
|
|
$this->bind_label = $prefix . '_' . $this->bind_label; |
80
|
|
|
|
81
|
|
|
return $this->bind_label; |
|
|
|
|
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
public function withValue($value, string $bind_prefix = null): self |
85
|
|
|
{ |
86
|
|
|
$this->bindings[$this->bindLabel($bind_prefix)] = $value; |
87
|
|
|
$this->right = ':' . $this->bindLabel($bind_prefix); |
88
|
|
|
return $this; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
public function withValues(array $values, string $bind_prefix) |
92
|
|
|
{ |
93
|
|
|
if (empty($values)) { |
94
|
|
|
throw new \InvalidArgumentException('PREDICATE_VALUES_ARE_EMPTY'); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
$bind_label = $this->bindLabel($bind_prefix); |
98
|
|
|
foreach ($values as $index => $val) { |
99
|
|
|
$this->bindings[sprintf('%s_%d',$bind_label, $index)] = $val; |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
$this->operator = 'IN'; |
103
|
|
|
$this->right = '(:' . implode(',:', array_keys($this->bindings)) . ')'; |
104
|
|
|
|
105
|
|
|
return $this; |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
public function isNotEmpty(): self |
109
|
|
|
{ |
110
|
|
|
$res = is_array($this->left) ? self::identifier($this->left) : $this->left; |
111
|
|
|
$this->left = sprintf("(%s IS NOT NULL AND %s <> '')", $res, $res); |
112
|
|
|
$this->operator = null; |
113
|
|
|
$this->right = null; |
114
|
|
|
|
115
|
|
|
return $this; |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
public function isEmpty(): self |
119
|
|
|
{ |
120
|
|
|
$res = is_array($this->left) ? self::identifier($this->left) : $this->left; |
121
|
|
|
$this->left = sprintf("(%s IS NULL OR %s = '')", $res, $res); |
122
|
|
|
$this->operator = null; |
123
|
|
|
$this->right = null; |
124
|
|
|
|
125
|
|
|
return $this; |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
|