Problem/Motivation

Issue split from #2769407: Add Boolean field filter option 'Treat NULL values as FALSE' to expose the already existing code path for handling this for a clearer issue scope.

Proposed resolution

Views provides an option for filtering boolean fields on 'Is empty (NULL)' and 'Is not empty (NOT NULL)'

Remaining tasks

  1. Write a patch
  2. Review
  3. Commit

User interface changes

Views now offers 'Is empty (NULL)' and 'Is not empty (NOT NULL)' operators to boolean field filtering

API changes

None.

Data model changes

None.

Release notes snippet

Views now offers 'Is empty (NULL)' and 'Is not empty (NOT NULL)' operators to boolean field filtering

Issue fork drupal-3322402

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

  • 3322402-add-boolean-filters Comparechanges, plain diff MR !8551
  • 2 hidden branches
  • 10.1.x Comparecompare
  • 11.x Comparecompare

Comments

idebr created an issue. See original summary.

idebr’s picture

Issue summary: View changes
Status: Active » Needs review
StatusFileSize
new6.49 KB

Attached patch provides a Views option for filtering boolean fields on 'Is empty (NULL)' and 'Is not empty (NOT NULL)'

idebr’s picture

StatusFileSize
new2.5 KB
new8.69 KB

Attached patch adds a visibility state for values similar to other filter plugins, so the values are only displayed for 'Is equal to' and 'Is not equal to'

idebr’s picture

StatusFileSize
new757 bytes
new8.83 KB

Attached patch fixes phpstan validation.

Lendude credited akalata.

lendude’s picture

Thanks for splitting this off.

Crediting @akalata here for the work they did adding it in #2769407: Add Boolean field filter option 'Treat NULL values as FALSE' to expose the already existing code path for handling this

lendude’s picture

Status: Needs review » Reviewed & tested by the community

Checked the patch again, looks good, has nice test coverage.

This:

+  protected function operatorValues($values = 1) {

Feels a bit weak but that is how other handlers manage this too, so ¯\_(ツ)_/¯

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/views/src/Plugin/views/filter/BooleanOperator.php
@@ -210,13 +254,17 @@ public function adminSummary() {
     if (empty($this->valueOptions)) {
-      $this->getValueOptions();
+      if (in_array($this->operator, $this->operatorValues(1), TRUE)) {
+        $this->getValueOptions();
+        // Now that we have the valid options for this filter, just return the
+        // human-readable label based on the current value.  The valueOptions
+        // array is keyed with either 0 or 1, so if the current value is not
+        // empty, use the label for 1, and if it's empty, use the label for 0.
+        return $this->operator . ' ' . $this->valueOptions[!empty($this->value)];
+      }
+
+      return $this->operator;
     }
-    // Now that we have the valid options for this filter, just return the
-    // human-readable label based on the current value.  The valueOptions
-    // array is keyed with either 0 or 1, so if the current value is not
-    // empty, use the label for 1, and if it's empty, use the label for 0.
-    return $this->operator . ' ' . $this->valueOptions[!empty($this->value)];
   }

This change does not correct. Prior to this change this method would always return a string now it does not. I think this should be:

  public function adminSummary() {
    if ($this->isAGroup()) {
      return $this->t('grouped');
    }
    if (!empty($this->options['exposed'])) {
      return $this->t('exposed');
    }
    if (empty($this->valueOptions)) {
      $this->getValueOptions();
    }
    if (in_array($this->operator, $this->operatorValues(1), TRUE)) {
      $this->getValueOptions();
      // Now that we have the valid options for this filter, just return the
      // human-readable label based on the current value.  The valueOptions
      // array is keyed with either 0 or 1, so if the current value is not
      // empty, use the label for 1, and if it's empty, use the label for 0.
      return $this->operator . ' ' . $this->valueOptions[!empty($this->value)];
    }

    return $this->operator;
  }
idebr’s picture

Status: Needs work » Needs review
StatusFileSize
new1.58 KB
new8.77 KB

#8 Thanks for picking that up, the code makes more sense now.

Attached patch adds the change suggested in #8

lendude’s picture

Status: Needs review » Reviewed & tested by the community

Nice, feedback has been addressed, did some extra manual testing to check the admin label, and looks good

quietone’s picture

Status: Reviewed & tested by the community » Needs work

I tested this on Drupal 10.1.x, standard install. I added a boolean field to the Page content type and made three nodes. One with the boolean On, two where I did not touch the boolean field. I created a duplicate of the Content view, adding the boolean to the fields and the filters.

  1. with Is empty (NULL) there are no nodes displayed - I expected two nodes here, the ones where I did not tick the boolean.
  2. with Is not empty (NULL) all three nodes are displayed. - I expected 1 node here, the one where I ticked the boolean.

I guess the field value is either TRUE of FALSE. How does it become NULL? More importantly, will this confuse the user?

I then played with the filter. it worked, except when exposed.

If the filter is exposed and the operator is "is empty(NULL)' or "Is not empty (NULL)" and I go to my view, I get a Warning. I did not check the results.

Warning: Undefined array key "field_boolean_value" in Drupal\views\Plugin\views\filter\FilterPluginBase->acceptExposedInput() (line 1502 of core/modules/views/src/Plugin/views/filter/FilterPluginBase.php).

Drupal\views\Plugin\views\filter\FilterPluginBase->acceptExposedInput(Array) (Line: 188)
Drupal\views\Form\ViewsExposedForm->submitForm(Array, Object)
call_user_func_array(Array, Array) (Line: 114)
Drupal\Core\Form\FormSubmitter->executeSubmitHandlers(Array, Object

Back to because of the warning.

lendude’s picture

The error comes out of the same pile of ifs as what we are looking at here #3259090: Exposed filter equality check works differently in PHP 8.0, that really needs some coverage :(

To reproduce the NULL values you can do two thing:
* Create some content, then add a new boolean field to it. These values will now be NULL until you save the content again
* Other option, create a View with an optional relationship to something that has a boolean field. In the rows that don't have the relationship the values will be NULL

lind101’s picture

* Other option, create a View with an optional relationship to something that has a boolean field. In the rows that don't have the relationship the values will be NULL

As Lendude mentions here this is a massive gap in the current boolean filter logic, take the following scenario:

I have a View that lists multiple bundles of the same entity type, one of those bundles has a boolean field. I want to be able to filter the view to only show records that don't have that field (all but one of the bundles), or have a false value for the field. This is currently unachievable.

To my mind this is the main use case we are solving here.

lind101’s picture

+1 for the patch in #9.

Managed to successfully use the patch to acheive the above use case. I used an OR filter group containing a = FALSE condition and a IS NULL condition. Worked perfectly, thanks!

tylired’s picture

+1 for the patch in #9.

It worked perfectly to provide new operator options "Is empty (NULL)" and "Is not empty (NOT NULL)" inside of the Views Filter Criteria section.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

callen321’s picture

StatusFileSize
new8.83 KB

Re-rolled patch for Drupal 10.3

callen321’s picture

Doh! Of course the patch failed to apply for 10.1.

sokru made their first commit to this issue’s fork.

sokru changed the visibility of the branch 11.x to hidden.

sokru changed the visibility of the branch 10.1.x to hidden.

sokru’s picture

Status: Needs work » Needs review

I picked up this instead of #3098560: Add 'Is empty (NULL)' and 'Is not empty (NOT NULL)' to field Filter Operators Options since this has working tests. Otherwise the "Proposed resolution" section seems rather identical with these two issues, calling for closing either of these or refining the issue summary.

smustgrave made their first commit to this issue’s fork.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +Needs Review Queue Initiative

I marked #3098560: Add 'Is empty (NULL)' and 'Is not empty (NOT NULL)' to field Filter Operators Options as PNMI for someone to confirm this ticket fixes the same issue, if not that issue should specify what didn't make it.

For this ticket

Ran the test-only feature

1) Drupal\Tests\views\Kernel\Handler\FilterBooleanOperatorTest::testEmptyFilterBooleanOperator
Failed asserting that actual size 6 matches expected size 1.
/builds/issue/drupal-3322402/core/modules/views/tests/src/Kernel/Handler/FilterBooleanOperatorTest.php:161
FAILURES!
Tests: 3, Assertions: 13, Failures: 1.

Show the test coverage.

Checking the issue summary, it appears complete with a matching solution to the MR.

Looking at the code I applied some small typehints for the new functions and the test.

I left dataSet and schemaDefinition as those are inherited and probably could be a standalone ticket for applying throughout the repo.

Rest appears to do as advertised.

  • longwave committed b6c02433 on 11.x
    Issue #3322402 by idebr, smustgrave, Lendude, lind101, akalata, quietone...
longwave’s picture

Status: Reviewed & tested by the community » Fixed

Nice to see these small features still getting attention, I've needed this before on a similar project and had to patch in support for it.

Committed b6c0243 and pushed to 11.x. Thanks!

Not eligible for backport as it's a new feature, anything building on this has to be targetted at 11.1 and above only.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

darkodev’s picture

Sorry for posting to a closed thread, but I just came across this need and wanted to suggest a solution for the use case in #13.

You can configure two groups of AND filters and OR them. You just need to duplicate the conditions that apply to all bundles in both groups.

Group 1:
Bundle = X
AND
Condition 1
AND
Condition 2

OR

Group 2:
Bundle = Y
AND
Condition 1
AND
Condition 2
AND
Condition 3 (that only applies to Bundle Y)