-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathFilterLike.php
117 lines (102 loc) · 3.21 KB
/
FilterLike.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<?php
/**
* @link https://github.com/illuminatech
* @copyright Copyright (c) 2019 Illuminatech
* @license [New BSD License](http://www.opensource.org/licenses/bsd-license.php)
*/
namespace Illuminatech\DataProvider\Filters;
use Illuminate\Database\PostgresConnection;
use Illuminatech\DataProvider\Exceptions\InvalidQueryException;
/**
* FilterLike performs string comparison using operator 'LIKE'.
*
* By default it sanitizes request value and performs search for string partial match.
*
* Usage example:
*
* ```php
* DataProvider(Item::class)
* ->filters([
* 'name' => new FilterLike('name'),
* 'allow_user_regex' => new FilterLike('name', false),
* 'for_postgres' => new FilterLike('name', true, 'ilike'),
* ]);
* ```
*
* @see \Illuminatech\DataProvider\Filters\FilterSearch
*
* @author Paul Klimov <[email protected]>
* @since 1.0
*/
class FilterLike extends FilterRelatedRecursive
{
/**
* @var bool whether to escape special search chars like '%' in filter value or allow passing them.
* If enabled value will be wrapped in '%' for the search.
*/
public $escape = true;
/**
* @var string|null operator name to be used, e.g. 'like' or 'ilike'.
* If not set ite will be detected from given data source.
*/
public $operator;
public function __construct(string $target, bool $escape = true, ?string $operator = null)
{
parent::__construct($target);
$this->escape = $escape;
$this->operator = $operator;
}
/**
* {@inheritdoc}
*/
protected function applyInternal(object $source, string $target, string $name, $value): object
{
if (!is_scalar($value)) {
throw new InvalidQueryException('Filter "' . $name . '" requires scalar value.');
}
if ($this->escape) {
$value = $this->escape($value);
}
$operator = $this->operator ?? $this->detectOperator($source);
return $source->where($target, $operator, $value);
}
/**
* Escapes given value according to 'LIKE' SQL operator syntax.
*
* @param string $value raw value.
* @return string escaped value.
*/
protected function escape($value): string
{
$value = strtr(
$value,
[
'%' => '\%',
'_' => '\_',
'\\' => '\\\\',
]
);
return '%' . $value . '%';
}
/**
* @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder|\Illuminate\Support\Collection|object $source data source.
* @return string operator name.
*/
protected function detectOperator(object $source): string
{
$connection = null;
if (method_exists($source, 'getConnection')) {
$connection = $source->getConnection();
}
if (method_exists($source, 'getModel')) {
$model = $source->getModel();
if (method_exists($model, 'getConnection')) {
$connection = $model->getConnection();
}
}
if (isset($connection) && $connection instanceof PostgresConnection) {
return 'ilike';
}
return 'like';
}
}