Score:2

How to create a view filter which display nodes if "field1" - "field2" < $amount

sa flag

I have a content type with 2 fields: field1 and field2

I would like to create a view filter which display node based on a calculation on those two fields.

The filter should display only nodes if field1 - field2 is lower then a given amount.

Here is my try: At the end of the code, I don't know how to create the query

 class Myfilter extends FilterPluginBase implements ContainerFactoryPluginInterface {

  protected ViewsHandlerManager $joinHandler;

  private int $amount;

  public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match, ViewsHandlerManager $join_handler) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->joinHandler = $join_handler;
    $this->amount = 0;
    if (($node = $route_match->getParameter('node')) && ($node->bundle()=='my_bundle')) {
      $this->amount = $node->get('field_inv_amount')->value;
    }

  }

  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration, $plugin_id, $plugin_definition,
      $container->get('current_route_match'),
      $container->get('plugin.manager.views.join')
    );
  }

  public function query() {
    //parent::query();
    
    $fields = [
      'field1',
      'field2',
    ];
    foreach ($fields as $field) {
      $table_field_name = 'node__' . $field;
      $configuration = [
        'table' => $table_field_name,
        'field' => 'nid',
        'left_table' => 'node_field_data',
        'left_field' => 'nid',
        'operator' => '=',
      ];
      $join = $this->joinHandler->createInstance('standard', $configuration);
      $this->query->addRelationship($table_field_name, $join, 'node_field_data');
    }
    // I am stuck here... field1-field2 should be < $this->amount
    $this->query->addWhere( ???? );
  }

}

Any hint will be appreciated

beltouche avatar
cn flag
As an alternative, you might consider leveraging https://www.drupal.org/project/computed_field, and filter on the computed field.
Baud avatar
sa flag
@beltouche thank you. I can also populate a normal field during node_presave, but as I have many cases like this one, I would prefer to understand how to create those kind of query. (I regular sql, it is easy, so I assume it can be done with the $query object)
Score:1
ua flag

You have a few errors:

The 'field' => 'nid', should be 'field' => 'entity_id',

The $join = line needs to use Drupal\views\Views::pluginManager('join')


You can using addWhereExpression, working example:

  public function query() {

    $fields = [
      'field_num1',
      'field_num2',
    ];

    foreach ($fields as $field) {
      $table_field_name = 'node__' . $field;
      $configuration = [
        'table' => $table_field_name,
        'field' => 'entity_id',
        'left_table' => 'node_field_data',
        'left_field' => 'nid',
        'operator' => '=',
      ];
      $join = $this->joinHandler->createInstance('standard', $configuration);
      $this->query->addRelationship($table_field_name, $join, 'node_field_data');
    }

    // Substracts and filters to less than amount.
    $this->query->addWhereExpression('AND', 'node__field_num1.field_num1_value - node__field_num2.field_num2_value <' . $this->amount);

  }
Baud avatar
sa flag
Many thanks!, it works like a charm! A small note: `$this->joinHandler` doesn't need to be replaced by `Drupal\views\Views::pluginManager('join')` because I used DI : `$container->get('plugin.manager.views.join')` is doing the same job.
No Sssweat avatar
ua flag
Oh yes [Dependency Injection](https://www.drupal.org/docs/drupal-apis/services-and-dependency-injection/services-and-dependency-injection-in-drupal-8#s-injecting-dependencies-into-controllers-forms-and-blocks), somehow I overlooked that.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.