From e45f4d22b3731a09936bec603921877558bd90c1 Mon Sep 17 00:00:00 2001
From: Florent Torregrosa <florent.torregrosa@smile.fr>
Date: Fri, 18 Oct 2019 18:19:05 +0200
Subject: [PATCH] Issue #2888320 by Dakwamine, Rookie Rodrigo, MattDanger,
 Jim.M, davidferlay: Add support for Token and plural in Views Global result
 summary plugin

---
 .../views/config/schema/views.area.schema.yml | 12 +++
 .../views/src/Plugin/views/area/Result.php    | 67 +++++++++++++-
 .../views.view.test_area_result.yml           |  8 ++
 .../test_views/views.view.test_mini_pager.yml |  4 +
 .../test_views/views.view.test_token_view.yml |  4 +
 ...ews.view.views_area_single_plural_test.yml | 87 +++++++++++++++++++
 .../src/Kernel/Handler/AreaResultTest.php     | 44 +++++++++-
 core/modules/views/views.install              | 41 +++++++++
 8 files changed, 263 insertions(+), 4 deletions(-)
 create mode 100644 core/modules/views/tests/modules/views_test_config/test_views/views.view.views_area_single_plural_test.yml

diff --git a/core/modules/views/config/schema/views.area.schema.yml b/core/modules/views/config/schema/views.area.schema.yml
index 51042e9587..34b4b33d1f 100644
--- a/core/modules/views/config/schema/views.area.schema.yml
+++ b/core/modules/views/config/schema/views.area.schema.yml
@@ -50,6 +50,18 @@ views.area.result:
     content:
       type: text
       label: 'The shown text of the result summary area'
+    tokenize:
+      type: boolean
+      label: 'Should replacement tokens be used from the first row'
+    format_plural:
+      type: boolean
+      label: 'Format plural'
+    format_plural_text:
+      type: text
+      label: 'Text to use for the plural form'
+    format_plural_count:
+      type: text
+      label: 'Count token'
 
 views.area.title:
   type: views_area
diff --git a/core/modules/views/src/Plugin/views/area/Result.php b/core/modules/views/src/Plugin/views/area/Result.php
index e8d1947732..f2746a0d0c 100644
--- a/core/modules/views/src/Plugin/views/area/Result.php
+++ b/core/modules/views/src/Plugin/views/area/Result.php
@@ -5,6 +5,7 @@
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
 use Drupal\views\Plugin\views\style\DefaultSummary;
 
 /**
@@ -14,7 +15,7 @@
  *
  * @ViewsArea("result")
  */
-class Result extends AreaPluginBase {
+class Result extends TokenizeAreaPluginBase {
 
   /**
    * {@inheritdoc}
@@ -25,6 +26,9 @@ protected function defineOptions() {
     $options['content'] = [
       'default' => $this->t('Displaying @start - @end of @total'),
     ];
+    $options['format_plural'] = ['default' => FALSE];
+    $options['format_plural_count'] = ['default' => '@total'];
+    $options['format_plural_text'] = ['default' => ''];
 
     return $options;
   }
@@ -47,6 +51,16 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
         '@page_count -- the total page count',
       ],
     ];
+    $format_plural_count_options = [
+      '@start',
+      '@end',
+      '@total',
+      '@name',
+      '@per_page',
+      '@current_page',
+      '@current_record_count',
+      '@page_count',
+    ];
     $list = \Drupal::service('renderer')->render($item_list);
     $form['content'] = [
       '#title' => $this->t('Display'),
@@ -55,6 +69,36 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
       '#default_value' => $this->options['content'],
       '#description' => $this->t('You may use HTML code in this field. The following tokens are supported:') . $list,
     ];
+    $form['format_plural'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Format plural'),
+      '#description' => $this->t('If checked, special handling will be used for plurality.'),
+      '#default_value' => $this->options['format_plural'],
+    ];
+    $form['format_plural_count'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Count token'),
+      '#description' => $this->t('Token used to select plural format.'),
+      '#default_value' => (isset($this->options['format_plural_count']) ? $this->options['format_plural_count'] : ''),
+      '#options' => array_combine($format_plural_count_options, $format_plural_count_options),
+      '#states' => [
+        'visible' => [
+          ':input[name="options[format_plural]"]' => ['checked' => TRUE],
+        ],
+      ],
+    ];
+    $form['format_plural_text'] = [
+      '#title' => $this->t('Plural form'),
+      '#type' => 'textarea',
+      '#rows' => 3,
+      '#default_value' => $this->options['format_plural_text'],
+      '#description' => $this->t('Text to use for the plural form.'),
+      '#states' => [
+        'visible' => [
+          ':input[name="options[format_plural]"]' => ['checked' => TRUE],
+        ],
+      ],
+    ];
   }
 
   /**
@@ -75,7 +119,6 @@ public function render($empty = FALSE) {
       return [];
     }
     $output = '';
-    $format = $this->options['content'];
     // Calculate the page totals.
     $current_page = (int) $this->view->getCurrentPage() + 1;
     $per_page = (int) $this->view->getItemsPerPage();
@@ -112,12 +155,30 @@ public function render($empty = FALSE) {
     $replacements['@current_page'] = $current_page;
     $replacements['@current_record_count'] = $current_record_count;
     $replacements['@page_count'] = $page_count;
+    // If the format_plural is checked, special handling will be used for
+    // plurality.
+    if (isset($this->options['format_plural']) && $this->options['format_plural']) {
+      $format = PluralTranslatableMarkup::createFromTranslatedString(
+        $replacements[$this->options['format_plural_count']],
+        implode(
+          PluralTranslatableMarkup::DELIMITER,
+          [
+            $this->options['content'],
+            $this->options['format_plural_text'],
+          ]
+        )
+      );
+    }
+    else {
+      $format = $this->options['content'];
+    }
+
     // Send the output.
     if (!empty($total) || !empty($this->options['empty'])) {
       $output .= Xss::filterAdmin(str_replace(array_keys($replacements), array_values($replacements), $format));
       // Return as render array.
       return [
-        '#markup' => $output,
+        '#markup' => $this->tokenizeValue($output),
       ];
     }
 
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_area_result.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_area_result.yml
index 8ca5628583..093e658799 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_area_result.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_area_result.yml
@@ -51,7 +51,11 @@ display:
           group_type: group
           admin_label: ''
           empty: true
+          tokenize: false
           content: "start: @start | end: @end | total: @total | label: @label | per page: @per_page | current page: @current_page | current record count: @current_record_count | page count: @page_count"
+          format_plural: false
+          format_plural_count: ''
+          format_plural_text: ''
           plugin_id: result
     display_plugin: default
     display_title: Master
@@ -71,7 +75,11 @@ display:
           group_type: group
           admin_label: ''
           empty: false
+          tokenize: false
           content: "start: @start | end: @end | total: @total | label: @label | per page: @per_page | current page: @current_page | current record count: @current_record_count | page count: @page_count"
+          format_plural: false
+          format_plural_count: ''
+          format_plural_text: ''
           plugin_id: result
     display_plugin: page
     display_title: 'Page 1'
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_mini_pager.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_mini_pager.yml
index 289f83db97..deada535cc 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_mini_pager.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_mini_pager.yml
@@ -139,5 +139,9 @@ display:
           group_type: group
           admin_label: ''
           empty: false
+          tokenize: false
           content: 'Displaying @start - @end of @total'
+          format_plural: false
+          format_plural_count: ''
+          format_plural_text: ''
           plugin_id: result
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_token_view.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_token_view.yml
index b2e3c7d58b..121706a6c4 100644
--- a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_token_view.yml
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_token_view.yml
@@ -213,7 +213,11 @@ display:
           group_type: group
           admin_label: ''
           empty: true
+          tokenize: false
           content: "Displaying @start - @end of @total\n\n%1-result-!1"
+          format_plural: false
+          format_plural_count: ''
+          format_plural_text: ''
           plugin_id: result
         title:
           id: title
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.views_area_single_plural_test.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.views_area_single_plural_test.yml
new file mode 100644
index 0000000000..b07b980780
--- /dev/null
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.views_area_single_plural_test.yml
@@ -0,0 +1,87 @@
+langcode: en
+status: true
+dependencies: {  }
+id: views_area_single_plural_test
+label: ''
+module: views
+description: ''
+tag: ''
+base_table: views_test_data
+base_field: nid
+core: '8'
+display:
+  default:
+    display_options:
+      defaults:
+        fields: false
+        pager: false
+        sorts: false
+      fields:
+        id:
+          field: id
+          id: id
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+      pager:
+        options:
+          offset: 0
+        type: none
+      sorts:
+        id:
+          field: id
+          id: id
+          order: ASC
+          relationship: none
+          table: views_test_data
+          plugin_id: numeric
+      empty:
+        title:
+          field: title
+          id: title
+          table: views
+          plugin_id: title
+          title: test_title_empty
+      header:
+        result:
+          id: result
+          table: views
+          field: result
+          relationship: none
+          group_type: group
+          admin_label: ''
+          empty: false
+          tokenize: false
+          content: "start: @start | end: @end | total: @total | label: @label | per page: @per_page | current page: @current_page | current record count: @current_record_count | page count: @page_count | single text"
+          format_plural: true
+          format_plural_count: '@total'
+          format_plural_text: 'start: @start | end: @end | total: @total | label: @label | per page: @per_page | current page: @current_page | current record count: @current_record_count | page count: @page_count | plural text'
+          plugin_id: result
+    display_plugin: default
+    display_title: Master
+    id: default
+    position: 0
+  page_1:
+    display_options:
+      path: views-area-single-plural-test
+      defaults:
+        header: false
+      header:
+        result:
+          id: result
+          table: views
+          field: result
+          relationship: none
+          group_type: group
+          admin_label: ''
+          empty: false
+          tokenize: false
+          content: "start: @start | end: @end | total: @total | label: @label | per page: @per_page | current page: @current_page | current record count: @current_record_count | page count: @page_count | single text"
+          format_plural: true
+          format_plural_count: '@total'
+          format_plural_text: 'start: @start | end: @end | total: @total | label: @label | per page: @per_page | current page: @current_page | current record count: @current_record_count | page count: @page_count | plural text'
+          plugin_id: result
+    display_plugin: page
+    display_title: 'Page 1'
+    id: page_1
+    position: 1
diff --git a/core/modules/views/tests/src/Kernel/Handler/AreaResultTest.php b/core/modules/views/tests/src/Kernel/Handler/AreaResultTest.php
index 31e252aef2..d8bd1ebe2c 100644
--- a/core/modules/views/tests/src/Kernel/Handler/AreaResultTest.php
+++ b/core/modules/views/tests/src/Kernel/Handler/AreaResultTest.php
@@ -16,7 +16,10 @@ class AreaResultTest extends ViewsKernelTestBase {
   /**
    * {@inheritdoc}
    */
-  public static $testViews = ['test_area_result'];
+  public static $testViews = [
+    'test_area_result',
+    'views_area_single_plural_test',
+  ];
 
   /**
    * Tests the results area handler.
@@ -72,4 +75,43 @@ public function testResultEmpty() {
     $this->assertNoRaw('<header>');
   }
 
+  /**
+   * Test the result of Result Summary.
+   */
+  public function testResultSummary() {
+    $view = Views::getView('views_area_single_plural_test');
+
+    // Test view for a single render.
+    $view->setDisplay('default');
+
+    // Add a filter that will make the result set to one.
+    $view->displayHandlers->get('default')->overrideOption('filters', [
+      'name' => [
+        'id' => 'name',
+        'table' => 'views_test_data',
+        'field' => 'name',
+        'relationship' => 'none',
+        'operator' => '=',
+        'value' => 'John',
+      ],
+    ]);
+
+    $this->executeView($view);
+    $output = $view->render();
+    $output = \Drupal::service('renderer')->renderRoot($output);
+    $this->setRawContent($output);
+    $this->assertText('start: 1 | end: 1 | total: 1 | label: views_area_single_plural_test | per page: 0 | current page: 1 | current record count: 1 | page count: 1 | single text');
+
+    // Reload the view to delete the filter.
+    $view = Views::getView('views_area_single_plural_test');
+
+    // Test view for plural render.
+    $view->setDisplay('page_1');
+    $this->executeView($view);
+    $output = $view->render();
+    $output = \Drupal::service('renderer')->renderRoot($output);
+    $this->setRawContent($output);
+    $this->assertText('start: 1 | end: 5 | total: 5 | label: views_area_single_plural_test | per page: 0 | current page: 1 | current record count: 5 | page count: 1 | plural text');
+  }
+
 }
diff --git a/core/modules/views/views.install b/core/modules/views/views.install
index 002ad01321..69d86da099 100644
--- a/core/modules/views/views.install
+++ b/core/modules/views/views.install
@@ -532,3 +532,44 @@ function views_update_8500() {
     }
   }
 }
+
+/**
+ * Set new configuration on ResultSummary.
+ */
+function views_update_8800() {
+  $config_factory = \Drupal::configFactory();
+
+  foreach ($config_factory->listAll('views.view.') as $view_config_name) {
+    $changed = FALSE;
+
+    $view = $config_factory->getEditable($view_config_name);
+    $displays = $view->get('display');
+    foreach ($displays as $display_name => &$display) {
+      $area_types = ['header', 'footer', 'no_result_behavior'];
+      foreach ($area_types as $area_type) {
+        if (!empty($display['display_options'][$area_type])) {
+          foreach ($display['display_options'][$area_type] as &$area) {
+            if (isset($area['plugin_id']) && $area['plugin_id'] == 'result') {
+              if (!isset($area['format_plural'])) {
+                $area['format_plural'] = FALSE;
+                $changed = TRUE;
+              }
+              if (!isset($area['format_plural_count'])) {
+                $area['format_plural_count'] = '@total';
+                $changed = TRUE;
+              }
+              if (!isset($area['format_plural_text'])) {
+                $area['format_plural_text'] = '';
+                $changed = TRUE;
+              }
+            }
+          }
+        }
+      }
+    }
+    if ($changed) {
+      $view->set('display', $displays);
+      $view->save();
+    }
+  }
+}
-- 
2.17.1

