Passed
Push — master ( 6a58b9...6d010e )
by Aimeos
02:10
created

SQL   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 183
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 25
eloc 49
c 1
b 0
f 0
dl 0
loc 183
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A createListTerm() 0 16 4
A createTerm() 0 19 3
A createNullTerm() 0 9 3
A createValueList() 0 13 3
A __construct() 0 8 2
A getOperators() 0 3 1
A getConnection() 0 3 1
A getParamType() 0 11 4
A translateValue() 0 8 4
1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2011
6
 * @copyright Aimeos (aimeos.org), 2015-2023
7
 * @package Base
8
 * @subpackage Common
9
 */
10
11
12
namespace Aimeos\Base\Criteria\Expression\Compare;
13
14
15
/**
16
 * SQL implementation for comparing objects.
17
 *
18
 * @package Base
19
 * @subpackage Common
20
 */
21
class SQL extends Base
22
{
23
	private static $operators = ['=~' => 'LIKE', '~=' => 'LIKE', '==' => '=', '!=' => '<>', '>' => '>', '>=' => '>=', '<' => '<', '<=' => '<=', '-' => '-'];
24
	private \Aimeos\Base\DB\Connection\Iface $conn;
25
26
27
	/**
28
	 * Initializes the object.
29
	 *
30
	 * @param \Aimeos\Base\DB\Connection\Iface $conn Database connection object
31
	 * @param string $operator Operator used for the expression
32
	 * @param string $name Name of variable or column that should be compared.
33
	 * @param mixed $value Value that the variable or column should be compared to
34
	 */
35
	public function __construct( \Aimeos\Base\DB\Connection\Iface $conn, string $operator, string $name, $value )
36
	{
37
		if( !isset( self::$operators[$operator] ) ) {
38
			throw new \Aimeos\Base\Exception( sprintf( 'Invalid operator "%1$s"', $operator ) );
39
		}
40
41
		parent::__construct( $operator, $name, $value );
42
		$this->conn = $conn;
43
	}
44
45
46
	/**
47
	 * Returns the available operators for the expression.
48
	 *
49
	 * @return array List of available operators
50
	 */
51
	public static function getOperators() : array
52
	{
53
		return array_keys( self::$operators );
54
	}
55
56
57
	/**
58
	 * Creates a term string from the given parameters.
59
	 *
60
	 * @param string|array $name Translated name(s) of the variable or column
61
	 * @param string $type Type constant
62
	 * @param mixed $value Value that the variable or column should be compared to
63
	 * @return string Created term string (name operator value)
64
	 */
65
	protected function createTerm( $name, string $type, $value ) : string
66
	{
67
		$op = $this->getOperator();
68
69
		if( $op === '-' )
70
		{
71
			$p = explode( ' - ', $value );
72
73
			return $name . ' >= ' . $this->escape( '>=', $type, $p[0] )
0 ignored issues
show
Bug introduced by
Are you sure $name of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

73
			return /** @scrutinizer ignore-type */ $name . ' >= ' . $this->escape( '>=', $type, $p[0] )
Loading history...
74
				. ' AND ' . $name . ' <= ' . $this->escape( '<=', $type, $p[1] );
75
		}
76
77
		$term = $name . ' ' . self::$operators[$op] . ' ' . $this->escape( $op, $type, $value );
78
79
		if( in_array( $op, array( '=~', '~=' ), true ) ) {
80
			$term .= ' ESCAPE \'#\'';
81
		}
82
83
		return $term;
84
	}
85
86
87
	/**
88
	 * Creates a term which contains a null value.
89
	 *
90
	 * @param string|array $name Translated name(s) of the variable or column
91
	 * @param string $type Code of the internal value type
92
	 * @return string String that can be inserted into a SQL statement
93
	 */
94
	protected function createNullTerm( $name, string $type ) : string
95
	{
96
		switch( $this->getOperator() )
97
		{
98
			case '==': return $name . ' IS NULL';
0 ignored issues
show
Bug introduced by
Are you sure $name of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

98
			case '==': return /** @scrutinizer ignore-type */ $name . ' IS NULL';
Loading history...
99
			case '!=': return $name . ' IS NOT NULL';
100
		}
101
102
		throw new \Aimeos\Base\Exception( sprintf( 'NULL value not allowed for operator "%1$s"', $this->getOperator() ) );
103
	}
104
105
106
	/**
107
	 * Creates a term from a list of values.
108
	 *
109
	 * @param string|array $name Translated name(s) of the variable or column
110
	 * @param string $type Type constant
111
	 * @return string String that can be inserted into a SQL statement
112
	 */
113
	protected function createListTerm( $name, string $type ) : string
114
	{
115
		switch( $this->getOperator() )
116
		{
117
			case '==':
118
				return $name . ' IN ' . $this->createValueList( $type, (array) $this->getValue() );
0 ignored issues
show
Bug introduced by
Are you sure $name of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

118
				return /** @scrutinizer ignore-type */ $name . ' IN ' . $this->createValueList( $type, (array) $this->getValue() );
Loading history...
119
			case '!=':
120
				return $name . ' NOT IN ' . $this->createValueList( $type, (array) $this->getValue() );
121
			default:
122
				$terms = [];
123
124
				foreach( (array) $this->getValue() as $val ) {
125
					$terms[] = $this->createTerm( $name, $type, $val );
126
				}
127
128
				return '(' . implode( ' OR ', $terms ) . ')';
129
		}
130
	}
131
132
133
	/**
134
	 * Creates a list of search values.
135
	 *
136
	 * @param string $type Type constant
137
	 * @param string[] $values Value list for the variable or column name
138
	 * @return string String of comma separated values in parenthesis
139
	 */
140
	protected function createValueList( string $type, array $values ) : string
141
	{
142
		if( empty( $values ) ) {
143
			return '(NULL)';
144
		}
145
146
		$operator = $this->getOperator();
147
148
		foreach( $values as $key => $value ) {
149
			$values[$key] = $this->escape( $operator, $type, $value );
150
		}
151
152
		return '(' . implode( ',', $values ) . ')';
153
	}
154
155
156
	/**
157
	 * Returns the connection object.
158
	 *
159
	 * return \Aimeos\Base\DB\Connection\Iface Connection object
160
	 */
161
	public function getConnection() : \Aimeos\Base\DB\Connection\Iface
162
	{
163
		return $this->conn;
164
	}
165
166
167
	/**
168
	 * Returns the internal type of the function parameter.
169
	 *
170
	 * @param mixed &$item Reference to parameter value (will be updated if necessary)
171
	 * @return string Internal parameter type
172
	 * @throws \Aimeos\Base\Exception If an error occurs
173
	 */
174
	protected function getParamType( &$item ) : string
175
	{
176
		if( is_null( $item ) ) {
177
			return \Aimeos\Base\DB\Statement\Base::PARAM_NULL;
178
		} elseif( is_float( $item ) ) {
179
			return \Aimeos\Base\DB\Statement\Base::PARAM_FLOAT;
180
		} elseif( is_int( $item ) ) {
181
			return \Aimeos\Base\DB\Statement\Base::PARAM_INT;
182
		}
183
184
		return \Aimeos\Base\DB\Statement\Base::PARAM_STR;
185
	}
186
187
188
	/**
189
	 * Translates a value to another one by a plugin if available.
190
	 *
191
	 * @param string $name Name of variable or column that should be translated
192
	 * @param mixed $value Original value
193
	 * @param mixed $type Value type
194
	 * @return mixed Translated value
195
	 */
196
	protected function translateValue( string $name, $value, $type )
197
	{
198
		if( $plugin = $this->getPlugin( $name ) ) {
199
			return $plugin->translate( $value, $type );
200
		}
201
202
		$types = [\Aimeos\Base\DB\Statement\Base::PARAM_INT, \Aimeos\Base\DB\Statement\Base::PARAM_FLOAT];
203
		return in_array( $type, $types ) && $value === '' ? null : $value;
204
	}
205
}
206