Passed
Pull Request — developer (#15831)
by Arkadiusz
20:14
created

BaseField::operatorS()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 * Base query field conditions file.
4
 *
5
 * @package UIType
6
 *
7
 * @copyright YetiForce S.A.
8
 * @license   YetiForce Public License 5.0 (licenses/LicenseEN.txt or yetiforce.com)
9
 * @author    Mariusz Krzaczkowski <[email protected]>
10
 * @author    Radosław Skrzypczak <[email protected]>
11
 */
12
13
namespace App\Conditions\QueryFields;
14
15
use App\Log;
16
17
/**
18
 * Base query field conditions class.
19
 */
20
class BaseField
21
{
22
	/**
23
	 * @var \App\QueryGenerator
24
	 */
25
	protected $queryGenerator;
26
27
	/**
28
	 * @var \Vtiger_Field_Model
29
	 */
30
	protected $fieldModel;
31
32
	/**
33
	 * @var string
34
	 */
35
	protected $fullColumnName;
36
37
	/**
38
	 * @var string
39
	 */
40
	protected $tableName;
41
42
	/**
43
	 * @var array|string
44
	 */
45
	protected $value;
46
47
	/**
48
	 * @var string
49
	 */
50
	protected $operator;
51
52
	/**
53
	 * @var array Related detail
54
	 */
55
	protected $related = [];
56
57
	/**
58
	 * Constructor.
59
	 *
60
	 * @param \App\QueryGenerator $queryGenerator
61
	 * @param \Vtiger_Field_Model $fieldModel
62 4
	 * @param array|string        $value
63
	 * @param string              $operator
64 4
	 */
65 4
	public function __construct(\App\QueryGenerator $queryGenerator, $fieldModel = false)
66 4
	{
67
		$this->queryGenerator = $queryGenerator;
68
		$this->fieldModel = $fieldModel;
0 ignored issues
show
Documentation Bug introduced by
It seems like $fieldModel can also be of type false. However, the property $fieldModel is declared as type Vtiger_Field_Model. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
69
	}
70
71
	/**
72
	 * Get module name.
73
	 *
74
	 * @return string
75
	 */
76
	public function getModuleName(): string
77
	{
78
		return $this->queryGenerator->getModule();
79
	}
80
81
	/**
82
	 * Set operator.
83 4
	 *
84
	 * @param string $operator
85 4
	 */
86 4
	public function setOperator(string $operator): void
87
	{
88
		$this->operator = strtolower($operator);
89
	}
90
91
	/**
92
	 * Set related details.
93
	 *
94
	 * @param array $relatedInfo
95
	 */
96
	public function setRelated(array $relatedInfo): void
97
	{
98
		$this->related = $relatedInfo;
99
	}
100
101
	/**
102
	 * Get related details.
103 1
	 *
104
	 * @return array
105 1
	 */
106
	public function getRelated(): array
107
	{
108
		return $this->related;
109
	}
110
111
	/**
112
	 *  Get additional field model for list view.
113
	 *
114
	 * @return bool|\Vtiger_Field_Model
115
	 */
116
	public function getListViewFields()
117
	{
118
		return false;
119
	}
120
121
	/**
122
	 * Get order by.
123
	 *
124
	 * @param mixed $order
125
	 *
126
	 * @return array
127
	 */
128 4
	public function getOrderBy($order = false): array
129
	{
130 4
		$order = $order && \App\Db::DESC === strtoupper($order) ? SORT_DESC : SORT_ASC;
131 2
		return [$this->getColumnName() => $order];
132
	}
133 4
134
	/**
135
	 * Get column name.
136
	 *
137
	 * @return string
138
	 */
139
	public function getColumnName(): string
140
	{
141 4
		if ($this->fullColumnName) {
142
			return $this->fullColumnName;
143 4
		}
144
		return $this->fullColumnName = $this->getTableName() . '.' . $this->fieldModel->getColumnName();
145
	}
146 4
147 4
	/**
148
	 * Get column name from source.
149
	 *
150 4
	 * @return string
151
	 */
152
	public function getColumnNameFromSource(): string
153
	{
154
		[$fieldName, $fieldModuleName, $sourceFieldName] = array_pad(explode(':', $this->value), 3, '');
0 ignored issues
show
Bug introduced by
It seems like $this->value can also be of type array; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

154
		[$fieldName, $fieldModuleName, $sourceFieldName] = array_pad(explode(':', /** @scrutinizer ignore-type */ $this->value), 3, '');
Loading history...
155
		if ($sourceFieldName) {
156
			$fieldModel = $this->queryGenerator->getRelatedModuleField($fieldName, $fieldModuleName);
157
			$this->queryGenerator->addRelatedJoin([
158
				'sourceField' => $sourceFieldName,
159
				'relatedModule' => $fieldModuleName,
160
				'relatedField' => $fieldName,
161
			]);
162
		} else {
163
			$fieldModel = $this->queryGenerator->getModuleField($fieldName);
164
			$this->queryGenerator->addTableToQuery($fieldModel->getTableName());
165
		}
166
		return $fieldModel ? ($fieldModel->getTableName() . $sourceFieldName . '.' . $fieldModel->getColumnName()) : '';
167
	}
168 4
169
	/**
170 4
	 * Get table name.
171 4
	 *
172 4
	 * @return string
173 4
	 */
174
	public function getTableName(): string
175
	{
176
		if ($this->tableName) {
177
			return $this->tableName;
178
		}
179
		$table = $this->fieldModel->getTableName();
180
		if ($this->related) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->related of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
181
			$table .= $this->related['sourceField'];
182
		}
183
		return $this->tableName = $table;
184 2
	}
185
186 2
	/**
187
	 * Set table name.
188
	 *
189 2
	 * @param string $tableName
190
	 */
191
	public function setTableName($tableName): void
192 2
	{
193
		$this->tableName = $tableName;
194
	}
195
196
	/**
197
	 * Get condition.
198
	 *
199
	 * @param string|null $operator
200 2
	 *
201
	 * @return array|bool
202 2
	 */
203
	public function getCondition(?string $operator = null)
204
	{
205
		$fn = 'operator' . ucfirst($operator ?? $this->operator);
206
		if (method_exists($this, $fn)) {
207
			Log::trace("Entering to $fn in " . __CLASS__);
208
			return $this->{$fn}();
209
		}
210 4
		Log::error("Not found operator: $fn in  " . __CLASS__);
211
		return false;
212 4
	}
213 4
214
	/**
215
	 * Auto operator, it allows you to use formulas: * and _.
216
	 *
217
	 * @return array
218
	 */
219
	public function operatorA(): array
220 2
	{
221
		return $this->getCondition($this->getOperator());
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getCondition($this->getOperator()) could return the type boolean which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
222 2
	}
223
224
	/**
225
	 * Search for a specified pattern in a column.
226
	 * Wildcard - asterisk.
227
	 *
228
	 * @return array
229
	 */
230 2
	public function operatorWca(): array
231
	{
232 2
		return ['like', $this->getColumnName(), str_replace('*', '%', "%{$this->getValue()}%"), false];
233
	}
234
235
	/**
236
	 * Get value.
237
	 *
238
	 * @return mixed
239
	 */
240
	public function getValue()
241
	{
242
		return $this->value;
243
	}
244
245
	/**
246
	 * Set value.
247
	 *
248
	 * @param mixed $value
249
	 *
250 2
	 * @return $this
251
	 */
252 2
	public function setValue($value)
253 2
	{
254 2
		$this->value = $value;
255
		return $this;
256
	}
257
258
	/**
259
	 * Contains operator.
260
	 *
261
	 * @return array
262
	 */
263
	public function operatorC(): array
264
	{
265
		return ['like', $this->getColumnName(), $this->getValue()];
266
	}
267
268
	/**
269
	 * Equals operator.
270
	 *
271
	 * @return array
272
	 */
273
	public function operatorE(): array
274
	{
275
		return [$this->getColumnName() => $this->getValue()];
276
	}
277
278
	/**
279
	 * Not equal operator.
280
	 *
281
	 * @return array
282
	 */
283
	public function operatorN(): array
284
	{
285
		$value = $this->getValue();
286
		return [(\is_array($value) ? 'not in' : '<>'), $this->getColumnName(), $value];
287
	}
288
289
	/**
290
	 * Starts with operator.
291
	 *
292
	 * @return array
293
	 */
294
	public function operatorS()
295
	{
296
		return ['like', $this->getColumnName(), $this->getValue() . '%', false];
0 ignored issues
show
Bug introduced by
Are you sure $this->getValue() 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

296
		return ['like', $this->getColumnName(), /** @scrutinizer ignore-type */ $this->getValue() . '%', false];
Loading history...
297
	}
298
299
	/**
300
	 * Ends with operator.
301
	 *
302
	 * @return array
303
	 */
304
	public function operatorEw()
305
	{
306
		return ['like', $this->getColumnName(), '%' . $this->getValue(), false];
0 ignored issues
show
Bug introduced by
Are you sure $this->getValue() 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

306
		return ['like', $this->getColumnName(), '%' . /** @scrutinizer ignore-type */ $this->getValue(), false];
Loading history...
307
	}
308
309
	/**
310
	 * Is empty operator.
311
	 *
312
	 * @return array
313
	 */
314
	public function operatorY(): array
315
	{
316
		return ['or',
317
			[$this->getColumnName() => null],
318
			['=', $this->getColumnName(), ''],
319
		];
320
	}
321
322
	/**
323
	 * Is not empty operator.
324
	 *
325
	 * @return array
326
	 */
327
	public function operatorNy(): array
328
	{
329
		return ['and',
330
			['not', [$this->getColumnName() => null]],
331
			['<>', $this->getColumnName(), ''],
332
		];
333
	}
334
335
	/**
336
	 * Does not contain operator.
337
	 *
338
	 * @return array
339
	 */
340
	public function operatorK(): array
341
	{
342
		return ['not like', $this->getColumnName(), $this->getValue()];
343
	}
344
345
	/**
346
	 * Is equal to selected field operator.
347
	 *
348
	 * @return array
349
	 */
350
	public function operatorEf(): array
351
	{
352
		return [$this->getColumnName() => new \yii\db\Expression($this->getColumnNameFromSource())];
353
	}
354
355
	/**
356
	 * Is not equal to selected field operator.
357
	 *
358
	 * @return array
359
	 */
360
	public function operatorNf(): array
361
	{
362
		return ['<>', $this->getColumnName(), new \yii\db\Expression($this->getColumnNameFromSource())];
363
	}
364
365
	/**
366
	 * Get field model.
367
	 *
368
	 * @return \Vtiger_Field_Model
369
	 */
370
	public function getField()
371
	{
372
		return $this->fieldModel;
373
	}
374
375
	/**
376
	 * Invoked when object is cloning.
377
	 */
378
	public function __clone()
379
	{
380
		$this->fullColumnName = null;
381
		$this->tableName = null;
382
	}
383
384
	/**
385
	 * Gets real operator.
386
	 *
387
	 * @return string
388
	 */
389
	public function getOperator(): string
390
	{
391
		$operator = $this->operator;
392
		if ('a' === $this->operator) {
393
			$operator = 'c';
394
			if (false !== strpos($this->getValue(), '*')) {
0 ignored issues
show
Bug introduced by
It seems like $this->getValue() can also be of type array; however, parameter $haystack of strpos() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

394
			if (false !== strpos(/** @scrutinizer ignore-type */ $this->getValue(), '*')) {
Loading history...
395
				$operator = 'wca';
396
			}
397
		}
398
		return $operator;
399
	}
400
}
401