Completed
Push — master ( 687f7d...ab57ba )
by Aimeos
10:53
created

SQL::escape()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 25
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 17
nc 7
nop 3
dl 0
loc 25
rs 6.7272
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Metaways Infosystems GmbH, 2011
6
 * @copyright Aimeos (aimeos.org), 2015-2017
7
 * @package MW
8
 * @subpackage Common
9
 */
10
11
12
namespace Aimeos\MW\Criteria\Expression\Compare;
13
14
15
/**
16
 * SQL implementation for comparing objects.
17
 *
18
 * @package MW
19
 * @subpackage Common
20
 */
21
class SQL extends \Aimeos\MW\Criteria\Expression\Compare\Base
22
{
23
	private static $operators = array( '=~' => 'LIKE', '~=' => 'LIKE', '==' => '=', '!=' => '<>', '>' => '>', '>=' => '>=', '<' => '<', '<=' => '<=', '&' => '&', '|' => '|' );
24
	private $conn = null;
25
26
27
	/**
28
	 * Initializes the object.
29
	 *
30
	 * @param \Aimeos\MW\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\MW\DB\Connection\Iface $conn, $operator, $name, $value )
36
	{
37
		if( !isset( self::$operators[$operator] ) ) {
38
			throw new \Aimeos\MW\Common\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()
52
	{
53
		return array_keys( self::$operators );
54
	}
55
56
57
	/**
58
	 * Creates a term string from the given parameters.
59
	 *
60
	 * @param string $name Translated name of variable or column that should be compared
61
	 * @param integer $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, $type, $value )
66
	{
67
		$term = $name . ' ' . self::$operators[$this->getOperator()] . ' ' . $this->escape( $this->getOperator(), $type, $value );
68
69
		if( in_array( $this->getOperator(), array( '=~', '~=' ), true ) ) {
70
			$term .= ' ESCAPE \'#\'';
71
		}
72
73
		return $term;
74
	}
75
76
77
	/**
78
	 * Creates a term which contains a null value.
79
	 *
80
	 * @param string $name Translated name of the variable or column
81
	 * @return string String that can be inserted into a SQL statement
82
	 */
83
	protected function createNullTerm( $name )
84
	{
85
		switch( $this->getOperator() )
86
		{
87
			case '==':
88
				return $name . ' IS NULL';
89
			case '!=':
90
				return $name . ' IS NOT NULL';
91
			default:
92
				throw new \Aimeos\MW\Common\Exception( sprintf( 'NULL value not allowed for operator "%1$s"', $this->getOperator() ) );
93
		}
94
	}
95
96
97
	/**
98
	 * Creates a term from a list of values.
99
	 *
100
	 * @param string $name Translated name of the variable or column
101
	 * @param integer $type Type constant
102
	 * @return string String that can be inserted into a SQL statement
103
	 */
104
	protected function createListTerm( $name, $type )
105
	{
106
		switch( $this->getOperator() )
107
		{
108
			case '==':
109
				return $name . ' IN ' . $this->createValueList( $type, (array) $this->getValue() );
110
			case '!=':
111
				return $name . ' NOT IN ' . $this->createValueList( $type, (array) $this->getValue() );
112
			default:
113
				$terms = [];
114
115
				foreach( (array) $this->getValue() as $val ) {
116
					$terms[] = $this->createTerm( $name, $type, $val );
117
				}
118
119
				return '(' . implode( ' OR ', $terms ) . ')';
120
		}
121
	}
122
123
124
	/**
125
	 * Creates a list of search values.
126
	 *
127
	 * @param integer $type Type constant
128
	 * @param string[] $values Value list for the variable or column name
129
	 * @return string String of comma separated values in parenthesis
130
	 */
131
	protected function createValueList( $type, array $values )
132
	{
133
		if( empty( $values ) ) {
134
			return '(NULL)';
135
		}
136
137
		$operator = $this->getOperator();
138
139
		foreach( $values as $key => $value ) {
140
			$values[$key] = $this->escape( $operator, $type, $value );
141
		}
142
143
		return '(' . implode(',', $values) . ')';
144
	}
145
146
147
	/**
148
	 * Escapes the value so it can be inserted into a SQL statement
149
	 *
150
	 * @param string $operator Operator used for the expression
151
	 * @param integer $type Type constant
152
	 * @param mixed $value Value that the variable or column should be compared to
153
	 * @return double|string|integer Escaped value
154
	 */
155
	protected function escape( $operator, $type, $value )
156
	{
157
		$value = $this->translateValue( $this->getName(), $value );
158
159
		switch( $type )
160
		{
161
			case \Aimeos\MW\DB\Statement\Base::PARAM_BOOL:
162
				$value = (int) (bool) $value; break;
163
			case \Aimeos\MW\DB\Statement\Base::PARAM_INT:
164
				$value = (int) $value; break;
165
			case \Aimeos\MW\DB\Statement\Base::PARAM_FLOAT:
166
				$value = (double) $value; break;
167
			case \Aimeos\MW\DB\Statement\Base::PARAM_STR:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
168
				if( $operator === '~=' ) {
169
					$value = '\'%' . str_replace( ['#', '%', '_', '['], ['##', '#%', '#_', '#['], $this->conn->escape( $value ) ) . '%\''; break;
170
				}
171
				if( $operator === '=~' ) {
172
					$value = '\'' . str_replace( ['#', '%', '_', '['], ['##', '#%', '#_', '#['], $this->conn->escape( $value ) ) . '%\''; break;
173
				}
174
			default:
175
				$value = '\'' . $this->conn->escape( $value ) . '\'';
176
		}
177
178
		return $value;
179
	}
180
181
182
	/**
183
	 * Returns the internal type of the function parameter.
184
	 *
185
	 * @param string &$item Reference to parameter value (will be updated if necessary)
186
	 * @return integer Internal parameter type
187
	 * @throws \Aimeos\MW\Common\Exception If an error occurs
188
	 */
189
	protected function getParamType( &$item )
190
	{
191
		if( $item[0] == '"' )
192
		{
193
			if( ( $item = substr( $item, 1, strlen( $item ) - 2 ) ) === false ) {
194
				throw new \Aimeos\MW\Common\Exception( sprintf( 'Unable to extract string parameter from >%1$s<', $item ) );
195
			}
196
197
			return \Aimeos\MW\DB\Statement\Base::PARAM_STR;
198
		}
199
		else if( strpos( $item, '.' ) !== false )
200
		{
201
			return \Aimeos\MW\DB\Statement\Base::PARAM_FLOAT;
202
		}
203
		else if( ctype_digit( $item ) !== false )
204
		{
205
			return \Aimeos\MW\DB\Statement\Base::PARAM_INT;
206
		}
207
208
		return \Aimeos\MW\DB\Statement\Base::PARAM_STR;
209
	}
210
}
211