diff --git a/src/Query/Scopes/Filters/Fields/Date.php b/src/Query/Scopes/Filters/Fields/Date.php index de6e55e6c9..1382c06315 100644 --- a/src/Query/Scopes/Filters/Fields/Date.php +++ b/src/Query/Scopes/Filters/Fields/Date.php @@ -17,6 +17,8 @@ public function fieldItems() '<' => __('Before'), '>' => __('After'), 'between' => __('Between'), + 'null' => __('Empty'), + 'not-null' => __('Not empty'), ], ], 'value' => [ @@ -54,7 +56,11 @@ public function apply($query, $handle, $values) $value = Carbon::parse($values['value']); - $query->where($handle, $operator, $value); + match ($operator) { + 'null' => $query->whereNull($handle), + 'not-null' => $query->whereNotNull($handle), + default => $query->where($handle, $operator, $value), + }; } public function badge($values) diff --git a/src/Query/Scopes/Filters/Fields/Entries.php b/src/Query/Scopes/Filters/Fields/Entries.php index 538ad0f88c..3d9fba7f8b 100644 --- a/src/Query/Scopes/Filters/Fields/Entries.php +++ b/src/Query/Scopes/Filters/Fields/Entries.php @@ -25,6 +25,8 @@ public function fieldItems() 'like' => __('Contains'), '=' => __('Is'), '!=' => __('Isn\'t'), + 'null' => __('Empty'), + 'not-null' => __('Not empty'), ], 'default' => 'like', ], @@ -32,8 +34,9 @@ public function fieldItems() 'type' => 'text', 'placeholder' => __('Value'), 'if' => [ - 'operator' => 'not empty', + 'operator' => 'contains_any like, =, !=', ], + 'required' => false, ], ]; } @@ -45,6 +48,15 @@ public function apply($query, $handle, $values) $operator = $values['operator']; $value = $values['value']; + if (in_array($operator, ['null', 'not-null'])) { + match ($operator) { + 'null' => $query->whereNull($handle), + 'not-null' => $query->whereNotNull($handle), + }; + + return; + } + if ($operator === 'like') { $value = Str::ensureLeft($value, '%'); $value = Str::ensureRight($value, '%'); diff --git a/src/Query/Scopes/Filters/Fields/FieldtypeFilter.php b/src/Query/Scopes/Filters/Fields/FieldtypeFilter.php index bc114b210a..b21516c480 100644 --- a/src/Query/Scopes/Filters/Fields/FieldtypeFilter.php +++ b/src/Query/Scopes/Filters/Fields/FieldtypeFilter.php @@ -27,6 +27,8 @@ public function fieldItems() 'like' => __('Contains'), '=' => __('Is'), '<>' => __('Isn\'t'), + 'null' => __('Empty'), + 'not-null' => __('Not empty'), ], 'default' => 'like', ], @@ -34,8 +36,9 @@ public function fieldItems() 'type' => 'text', 'placeholder' => __('Value'), 'if' => [ - 'operator' => 'not empty', + 'operator' => 'contains_any like, =, <>', ], + 'required' => false, ], ]; } @@ -50,7 +53,11 @@ public function apply($query, $handle, $values) $value = Str::ensureRight($value, '%'); } - $query->where($handle, $operator, $value); + match ($operator) { + 'null' => $query->whereNull($handle), + 'not-null' => $query->whereNotNull($handle), + default => $query->where($handle, $operator, $value), + }; } public function badge($values) diff --git a/src/Query/Scopes/Filters/Fields/Number.php b/src/Query/Scopes/Filters/Fields/Number.php index e4f655d599..2ed26c4482 100644 --- a/src/Query/Scopes/Filters/Fields/Number.php +++ b/src/Query/Scopes/Filters/Fields/Number.php @@ -21,6 +21,8 @@ public function fieldItems() '>=' => __('Greater than or equals'), '<' => __('Less than'), '<=' => __('Less than or equals'), + 'null' => __('Empty'), + 'not-null' => __('Not empty'), ], 'default' => '=', ], @@ -28,7 +30,7 @@ public function fieldItems() 'type' => $this->valueFieldtype(), 'placeholder' => __('Value'), 'if' => [ - 'operator' => 'not empty', + 'operator' => 'contains_any <>, >, >=, <, <=, =', ], ], ]; @@ -39,7 +41,11 @@ public function apply($query, $handle, $values) $operator = $values['operator']; $value = $values['value']; - $query->where($handle, $operator, $value); + match ($operator) { + 'null' => $query->whereNull($handle), + 'not-null' => $query->whereNotNull($handle), + default => $query->where($handle, $operator, $value), + }; } public function badge($values) diff --git a/src/Query/Scopes/Filters/Fields/Template.php b/src/Query/Scopes/Filters/Fields/Template.php index da1aaba5b4..80e4358389 100644 --- a/src/Query/Scopes/Filters/Fields/Template.php +++ b/src/Query/Scopes/Filters/Fields/Template.php @@ -2,19 +2,37 @@ namespace Statamic\Query\Scopes\Filters\Fields; +use Statamic\Support\Arr; + class Template extends FieldtypeFilter { public function fieldItems() { return [ + 'operator' => [ + 'type' => 'select', + 'placeholder' => __('Select Operator'), + 'options' => [ + '=' => __('Is'), + '<>' => __('Isn\'t'), + 'null' => __('Empty'), + 'not-null' => __('Not empty'), + ], + 'default' => '=', + ], 'value' => [ 'type' => 'template', + 'if' => [ + 'operator' => 'contains_any <>, =', + ], + 'required' => false, ], ]; } public function apply($query, $handle, $values) { + $operator = $values['operator']; $template = $values['value']; $variations = [ @@ -22,15 +40,21 @@ public function apply($query, $handle, $values) str_replace('/', '.', $template), ]; - $query->whereIn($handle, $variations); + match ($operator) { + '=' => $query->whereIn($handle, $variations), + '<>' => $query->whereNotIn($handle, $variations), + 'null' => $query->whereNull($handle), + 'not-null' => $query->whereNotNull($handle), + }; } public function badge($values) { $field = $this->fieldtype->field()->display(); - $operator = __('Is'); + $operator = $values['operator']; + $translatedOperator = Arr::get($this->fieldItems(), "operator.options.{$operator}"); $value = $values['value']; - return strtolower($field).' '.strtolower($operator).' '.$value; + return $field.' '.strtolower($translatedOperator).' '.$value; } } diff --git a/src/Query/Scopes/Filters/Fields/Terms.php b/src/Query/Scopes/Filters/Fields/Terms.php index 81f813b71b..9b96f2ecc1 100644 --- a/src/Query/Scopes/Filters/Fields/Terms.php +++ b/src/Query/Scopes/Filters/Fields/Terms.php @@ -3,29 +3,55 @@ namespace Statamic\Query\Scopes\Filters\Fields; use Statamic\Facades; +use Statamic\Support\Arr; class Terms extends FieldtypeFilter { public function fieldItems() { return [ + 'operator' => [ + 'type' => 'select', + 'options' => [ + 'like' => __('Contains'), + 'null' => __('Empty'), + 'not-null' => __('Not empty'), + ], + 'default' => 'like', + ], 'term' => [ 'type' => 'select', 'options' => $this->options()->all(), - 'placeholder' => __('Contains'), + 'placeholder' => __('Term'), 'clearable' => true, + 'if' => [ + 'operator' => 'contains_any like', + ], ], ]; } public function apply($query, $handle, $values) { - $query->whereJsonContains($handle, $values['term']); + $operator = $values['operator']; + + match ($operator) { + 'like' => $query->whereJsonContains($handle, $values['term']), + 'null' => $query->whereNull($handle), + 'not-null' => $query->whereNotNull($handle), + }; } public function badge($values) { $field = $this->fieldtype->field()->display(); + $operator = $values['operator']; + + if (in_array($operator, ['null', 'not-null'])) { + $translatedOperator = Arr::get($this->fieldItems(), "operator.options.{$operator}"); + + return $field.' '.strtolower($translatedOperator); + } $id = $this->fieldtype->usingSingleTaxonomy() ? $this->fieldtype->taxonomies()[0].'::'.$values['term'] diff --git a/src/Query/Scopes/Filters/Fields/Textarea.php b/src/Query/Scopes/Filters/Fields/Textarea.php index 6fa3acaeb7..6fb13d5a7a 100644 --- a/src/Query/Scopes/Filters/Fields/Textarea.php +++ b/src/Query/Scopes/Filters/Fields/Textarea.php @@ -2,6 +2,7 @@ namespace Statamic\Query\Scopes\Filters\Fields; +use Statamic\Support\Arr; use Statamic\Support\Str; class Textarea extends FieldtypeFilter @@ -9,29 +10,50 @@ class Textarea extends FieldtypeFilter public function fieldItems() { return [ + 'operator' => [ + 'type' => 'select', + 'options' => [ + 'like' => __('Contains'), + 'null' => __('Empty'), + 'not-null' => __('Not empty'), + ], + 'default' => 'like', + ], 'value' => [ 'type' => 'text', - 'placeholder' => __('Contains'), + 'placeholder' => __('Value'), + 'if' => [ + 'operator' => 'like', + ], + 'required' => false, ], ]; } public function apply($query, $handle, $values) { + $operator = $values['operator']; $value = $values['value']; - $value = Str::ensureLeft($value, '%'); - $value = Str::ensureRight($value, '%'); + if ($operator === 'like') { + $value = Str::ensureLeft($value, '%'); + $value = Str::ensureRight($value, '%'); + } - $query->where($handle, 'like', $value); + match ($operator) { + 'null' => $query->whereNull($handle), + 'not-null' => $query->whereNotNull($handle), + default => $query->where($handle, $operator, $value), + }; } public function badge($values) { $field = $this->fieldtype->field()->display(); - $operator = __('Contains'); + $operator = $values['operator']; + $translatedOperator = Arr::get($this->fieldItems(), "operator.options.{$operator}"); $value = $values['value']; - return strtolower($field).' '.strtolower($operator).' '.$value; + return $field.' '.strtolower($translatedOperator).' '.$value; } } diff --git a/src/Query/Scopes/Filters/Fields/User.php b/src/Query/Scopes/Filters/Fields/User.php index 33f67504c5..8b94b54be5 100644 --- a/src/Query/Scopes/Filters/Fields/User.php +++ b/src/Query/Scopes/Filters/Fields/User.php @@ -3,22 +3,48 @@ namespace Statamic\Query\Scopes\Filters\Fields; use Statamic\Facades\User as Users; +use Statamic\Support\Arr; class User extends FieldtypeFilter { public function fieldItems() { return [ + 'operator' => [ + 'type' => 'select', + 'placeholder' => __('Select Operator'), + 'options' => [ + '=' => __('Is'), + 'null' => __('Empty'), + 'not-null' => __('Not empty'), + ], + 'default' => '=', + ], 'value' => [ 'type' => 'users', 'max_items' => 1, 'mode' => 'select', + 'if' => [ + 'operator' => 'contains_any like, =, !=', + ], + 'required' => false, ], ]; } public function apply($query, $handle, $values) { + $operator = $values['operator']; + + if (in_array($operator, ['null', 'not-null'])) { + match ($operator) { + 'null' => $query->whereNull($handle), + 'not-null' => $query->whereNotNull($handle), + }; + + return; + } + if (! $user = $values['value']) { return; } @@ -30,12 +56,19 @@ public function apply($query, $handle, $values) public function badge($values) { + $field = $this->fieldtype->field()->display(); + $operator = $values['operator']; + + if (in_array($operator, ['null', 'not-null'])) { + $translatedOperator = Arr::get($this->fieldItems(), "operator.options.{$operator}"); + + return $field.' '.strtolower($translatedOperator); + } + if (! $user = $values['value']) { return null; } - $field = $this->fieldtype->field()->display(); - $operator = __('Is'); $user = Users::find($user)->name(); return $field.' '.strtolower($operator).' '.$user;