From 5c82c988fb054db3bd3aec1fa6005ef31134bf52 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Tue, 5 Mar 2024 11:39:42 +0000
Subject: [PATCH] Issue #3320569 by Spokje, mondrake, smustgrave, longwave,
 quietone, Lendude, alexpott: Add an interface for operators() on views

---
 .../user/src/Plugin/views/filter/Roles.php      |  2 ++
 .../src/Plugin/views/filter/BooleanOperator.php |  8 +++-----
 .../views/filter/FilterOperatorsInterface.php   | 17 +++++++++++++++++
 .../Plugin/views/filter/FilterPluginBase.php    |  9 +++++++++
 .../src/Plugin/views/filter/InOperator.php      |  8 ++------
 .../views/src/Plugin/views/filter/ManyToOne.php |  3 +++
 .../src/Plugin/views/filter/NumericFilter.php   |  5 ++++-
 .../src/Plugin/views/filter/StringFilter.php    |  8 ++------
 core/phpstan-baseline.neon                      |  5 -----
 9 files changed, 42 insertions(+), 23 deletions(-)
 create mode 100644 core/modules/views/src/Plugin/views/filter/FilterOperatorsInterface.php

diff --git a/core/modules/user/src/Plugin/views/filter/Roles.php b/core/modules/user/src/Plugin/views/filter/Roles.php
index 939b59c93a47..dbb80950ea76 100644
--- a/core/modules/user/src/Plugin/views/filter/Roles.php
+++ b/core/modules/user/src/Plugin/views/filter/Roles.php
@@ -68,6 +68,8 @@ public function getValueOptions() {
 
   /**
    * Override empty and not empty operator labels to be clearer for user roles.
+   *
+   * @return array[]
    */
   public function operators() {
     $operators = parent::operators();
diff --git a/core/modules/views/src/Plugin/views/filter/BooleanOperator.php b/core/modules/views/src/Plugin/views/filter/BooleanOperator.php
index 4ea7a07d1848..1ae0e7816bcc 100644
--- a/core/modules/views/src/Plugin/views/filter/BooleanOperator.php
+++ b/core/modules/views/src/Plugin/views/filter/BooleanOperator.php
@@ -24,7 +24,7 @@
  *
  * @ViewsFilter("boolean")
  */
-class BooleanOperator extends FilterPluginBase {
+class BooleanOperator extends FilterPluginBase implements FilterOperatorsInterface {
 
   /**
    * The equal query operator.
@@ -77,11 +77,9 @@ public function operatorOptions($which = 'title') {
   }
 
   /**
-   * Returns an array of operator information.
-   *
-   * @return array
+   * {@inheritdoc}
    */
-  protected function operators() {
+  public function operators() {
     return [
       '=' => [
         'title' => $this->t('Is equal to'),
diff --git a/core/modules/views/src/Plugin/views/filter/FilterOperatorsInterface.php b/core/modules/views/src/Plugin/views/filter/FilterOperatorsInterface.php
new file mode 100644
index 000000000000..2971eb6cfe82
--- /dev/null
+++ b/core/modules/views/src/Plugin/views/filter/FilterOperatorsInterface.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace Drupal\views\Plugin\views\filter;
+
+/**
+ * Provides an interface for all views filters that implement operators.
+ */
+interface FilterOperatorsInterface {
+
+  /**
+   * Returns an array of operator information, keyed by operator ID.
+   *
+   * @return array[]
+   */
+  public function operators();
+
+}
diff --git a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
index 1d24826b7581..6ab645c5d94f 100644
--- a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
+++ b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
@@ -717,6 +717,9 @@ public function validateExposeForm($form, FormStateInterface $form_state) {
    * @return bool
    */
   protected function hasValidGroupedValue(array $group) {
+    if (!method_exists($this, 'operators')) {
+      throw new \LogicException(get_class($this) . '::operators() not implemented');
+    }
     $operators = $this->operators();
     if ($operators[$group['operator']]['values'] == 0) {
       // Some filters, such as "is empty," do not require a value to be
@@ -753,6 +756,12 @@ protected function buildGroupValidate($form, FormStateInterface $form_state) {
         if (empty($group['remove'])) {
           $has_valid_value = $this->hasValidGroupedValue($group);
           if ($has_valid_value && $group['title'] == '') {
+            if (!method_exists($this, 'operators')) {
+              throw new \LogicException(get_class($this) . '::operators() not implemented');
+            }
+            if (!$this instanceof FilterOperatorsInterface) {
+              @trigger_error('Implementing operators() in class ' . get_class($this) . ' without it implementing \Drupal\views\Plugin\views\filter\FilterOperatorsInterface is deprecated in drupal:10.3.0 and will throw a LogicException in drupal:12.0.0. See https://www.drupal.org/node/3412013', E_USER_DEPRECATED);
+            }
             $operators = $this->operators();
             if ($operators[$group['operator']]['values'] == 0) {
               $form_state->setError($form['group_info']['group_items'][$id]['title'], $this->t('A label is required for the specified operator.'));
diff --git a/core/modules/views/src/Plugin/views/filter/InOperator.php b/core/modules/views/src/Plugin/views/filter/InOperator.php
index 52c198ce05a8..f706362b52c2 100644
--- a/core/modules/views/src/Plugin/views/filter/InOperator.php
+++ b/core/modules/views/src/Plugin/views/filter/InOperator.php
@@ -20,7 +20,7 @@
  *
  * @ViewsFilter("in_operator")
  */
-class InOperator extends FilterPluginBase {
+class InOperator extends FilterPluginBase implements FilterOperatorsInterface {
 
   protected $valueFormType = 'checkboxes';
 
@@ -107,11 +107,7 @@ protected function defineOptions() {
   }
 
   /**
-   * Gets the operators.
-   *
-   * This kind of construct makes it relatively easy for a child class
-   * to add or remove functionality by overriding this function and
-   * adding/removing items from this array.
+   * {@inheritdoc}
    */
   public function operators() {
     $operators = [
diff --git a/core/modules/views/src/Plugin/views/filter/ManyToOne.php b/core/modules/views/src/Plugin/views/filter/ManyToOne.php
index 5f326be154e8..0ebd5ad3df13 100644
--- a/core/modules/views/src/Plugin/views/filter/ManyToOne.php
+++ b/core/modules/views/src/Plugin/views/filter/ManyToOne.php
@@ -55,6 +55,9 @@ protected function defineOptions() {
     return $options;
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function operators() {
     $operators = [
       'or' => [
diff --git a/core/modules/views/src/Plugin/views/filter/NumericFilter.php b/core/modules/views/src/Plugin/views/filter/NumericFilter.php
index 2e34e069cf18..ecfd428369d8 100644
--- a/core/modules/views/src/Plugin/views/filter/NumericFilter.php
+++ b/core/modules/views/src/Plugin/views/filter/NumericFilter.php
@@ -11,7 +11,7 @@
  *
  * @ViewsFilter("numeric")
  */
-class NumericFilter extends FilterPluginBase {
+class NumericFilter extends FilterPluginBase implements FilterOperatorsInterface {
 
   protected $alwaysMultiple = TRUE;
 
@@ -89,6 +89,9 @@ public function buildExposeForm(&$form, FormStateInterface $form_state) {
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function operators() {
     $operators = [
       '<' => [
diff --git a/core/modules/views/src/Plugin/views/filter/StringFilter.php b/core/modules/views/src/Plugin/views/filter/StringFilter.php
index ba8fe2cf9991..58c9c03363b7 100644
--- a/core/modules/views/src/Plugin/views/filter/StringFilter.php
+++ b/core/modules/views/src/Plugin/views/filter/StringFilter.php
@@ -15,7 +15,7 @@
  *
  * @ViewsFilter("string")
  */
-class StringFilter extends FilterPluginBase {
+class StringFilter extends FilterPluginBase implements FilterOperatorsInterface {
 
   /**
    * All words separated by spaces or sentences encapsulated by double quotes.
@@ -97,11 +97,7 @@ public function buildExposeForm(&$form, FormStateInterface $form_state) {
   }
 
   /**
-   * Get the operators.
-   *
-   * This kind of construct makes it relatively easy for a child class
-   * to add or remove functionality by overriding this function and
-   * adding/removing items from this array.
+   * {@inheritdoc}
    */
   public function operators() {
     $operators = [
diff --git a/core/phpstan-baseline.neon b/core/phpstan-baseline.neon
index e1fb65600401..8f8403102410 100644
--- a/core/phpstan-baseline.neon
+++ b/core/phpstan-baseline.neon
@@ -1916,11 +1916,6 @@ parameters:
 			count: 1
 			path: modules/views/src/Plugin/views/filter/Broken.php
 
-		-
-			message: "#^Call to an undefined method Drupal\\\\views\\\\Plugin\\\\views\\\\filter\\\\FilterPluginBase\\:\\:operators\\(\\)\\.$#"
-			count: 2
-			path: modules/views/src/Plugin/views/filter/FilterPluginBase.php
-
 		-
 			message: "#^Variable \\$groups might not be defined\\.$#"
 			count: 1
-- 
GitLab