Hello! Is it possible to add custom fields to a view in the pre-render hook. I'm looking at the ViewExecutable API and nothing is standing out to me.

Thanks

Comments

just_jordan’s picture

awesome! I appreciate these

Gae58’s picture

Thanks also from me for the links you posted. I had only read the one by CodimTh and the others made me understand something more.
I created a calculated field using view_data and not views_data_alter (I need to figure out which one to use).
My need is to display the difference in days between the date present in the filter and the node date.
I did some tests by entering the date of the day in

defineOptions()  {
    $options = parent::defineOptions();
    $options['data'] = ['default' => date("Y/m/d") ] ;
}

and in the result I have with this code I have the result

$diffGiorni = floor((strtotime($this->options['data']) - strtotime($node->field_data->value)) / 86400);

I have done various research and tests to understand how to access the filter field_data_value field from the form but without success.

I also thought about getting the data from "views_exposed_form" but then I don't know how to pass it to the module or vice versa

wombatbuddy’s picture

My need is to display the difference in days between the date present in the filter and the node date.

Could you explain please what is the "node date" and what is the use case? 

Gae58’s picture

I have a view with 3 filters.
One of them is the date
In the views, the last column is a custom field with heading n ° DD, which displays the number of days given by the difference between the date field of the exposed filter and the date field of the views node
Currently the calculation is not exact because as the date of the filter in options I have put the date of the day
If in options or result I could take the value of the date field of the exposed filter I would have the exact number of days
S.S. of the views

wombatbuddy’s picture

What the operator do you use in the "Date" filter?

Gae58’s picture

<=
Less or equal

wombatbuddy’s picture

@Gae58, see the example.

The screenshots
1. https://www.drupal.org/files/views_custom_field_example-1.png
2. https://www.drupal.org/files/views_custom_field_example-2.png
3. https://www.drupal.org/files/views_custom_field_example-3.png
4. https://www.drupal.org/files/views_custom_field_example-4.png

my_module.module 

/**
 * Implements hook_views_data_alter().
 */
function my_module_views_data_alter(array &$data) {
  $data['node']['differences_in_days'] = [
    'title' => t('Differences in days'),
    'field' => [
      'title' => t('Differences in days'),
      'help' => t('Difference in days between the value of the "Date" field and "Date" filter value.'),
      'id' => 'differences_in_days',
    ],
  ];
}

DifferencesInDays.php 

<?php

namespace Drupal\my_module\Plugin\views\field;

use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\ResultRow;

/**
 * Provides Differences in days field handler.
 *
 * @ViewsField("differences_in_days")
 */
class DifferencesInDays extends FieldPluginBase {

  /**
   * {@inheritdoc}
   */
  public function query() {
    // Leave empty to avoid a query on this field.
  }

  /**
   * {@inheritdoc}
   */
  public function render(ResultRow $values) {
    // Make that the field recalculated when the filter value changes.
    $output = [
      '#cache' => [
        'contexts' => ['url.query_args:field_date_value'],
      ],
    ];

    $filterDateValue = $this->view->exposed_data['field_date_value'];
    if (empty($filterDateValue)) {
      return $output;
    }

    $filterDate = new DrupalDateTime($filterDateValue);
    if ($filterDate->hasErrors()) {
      $this->messenger::messenger()->addError($this->t('Filter value cannot be converted to date'));
      return $output;
    }

    /** @var \Drupal\node\NodeInterface $node */
    $node = $this->getEntity($values);
    if (!$node->field_date->isEmpty()) {
      $fieldDate = $node->field_date->date;
      // Get rid of the "time" component if needed.
      // $fieldDate = new DrupalDateTime($fieldDate->format('Y-m-d'));
      $output['#markup'] = $filterDate->diff($fieldDate)->days;
    }
    return $output;
  }

}
Gae58’s picture

You reproduced my need. You did a great job and I will never know how to thank you, you are truly a helpful and prepared person. I have read the code and it is largely clear to me. I have to apply it to understand some things that are not clear to me.

wombatbuddy’s picture

@Gae58, also, if you need to make the column sortable by click you can add to the plugin the clickSort() method. In our example we can add sorting by the "field_date" because it will work the same as the sorting by days.
The screenshots
5. https://www.drupal.org/files/views_custom_field_example-5.png
6. https://www.drupal.org/files/views_custom_field_example-6_0.png

DifferencesInDays.php 

/**
 * {@inheritdoc}
 */
public function clickSort($order) {
  $this->query->addOrderBy('node__field_date', 'field_date_value', $order);
}
Gae58’s picture

CIao, further learning element, I will definitely need it, thanks.
I tried your code yesterday. Locally it worked. I took it to the production site but it returned an error on index.
I continued doing some tests, but suddenly it couldn't find the view anymore. Since I tried to do other local tests, the view also disappeared here.
In production I restored only the database of a previous backup and the views were visible.
Since I don't know yet how the web part and the database are connected, I preferred to restore both the database and the web folders.

To clarify my ideas, I have two questions for you.
You told me to write the code related to the hook my_module_views_data_alter (array & $ data) in my.module.module are you referring to the file where the form_alter is managed or to the file my.module.views.inc?
I ask you this because in the .module file it is possible to manage the hook

I have seen that it can handle both hook_views_data_alter (array & $ data)
that hook_views_data_alter () but I didn't understand the difference between the two.

As soon as I restore the site, I start writing the code again

Thanks again for your great availability

Gae58’s picture

Locally I restored the site and did the tests I asked you for information.
I inserted your code in the .module file and copied the .php file to its path.
Tried and it works great. Without the .inc file it is more comfortable and I can use it directly in the .module already present.
I also tried sorting and it works.
Also tried the code at the production site and it works fine.
WombatButty, I'm learning so much from you