Commit 21a95c80 authored by Will McMillian's avatar Will McMillian Committed by Tyler Struyk
Browse files

Issue #2767437 by hanoii, iStryker, pingevt, devad, kerasai,...

Issue #2767437 by hanoii, iStryker, pingevt, devad, kerasai, wmcmillian-coalmarch, ivan.prokopenko, Adrian83, ahebrank, Fernly, Marios Anagnostopoulos, frederickjh: Allow sort handler to select the view that stored the order
parent 1f6ff904
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
views.field.draggable_views_field:
  type: views_field
  label: 'Draggable Views Field'
  mapping:
    action_title:
      type: label
      label: 'Action title'
    include_exclude:
      type: string
      label: 'Available actions'
    selected_actions:
      type: string
      label: 'Available actions'

views.sort.draggable_views_sort_default:
  type: views_sort
  label: 'Draggableviews Sort Default'
  mapping:
    draggable_views_reference:
      type: string
      label: 'Views Reference'
    draggable_views_null_order:
      type: string
      label: 'NULL stacking order'
    draggable_views_pass_arguments:
      type: boolean
      label: 'Pass Contextual Filters'
+337 −0
Original line number Diff line number Diff line
diff --git a/config/schema/draggableviews.views.schema.yml b/config/schema/draggableviews.views.schema.yml
new file mode 100644
index 0000000..8e8c94f
--- /dev/null
+++ b/config/schema/draggableviews.views.schema.yml
@@ -0,0 +1,27 @@
+views.field.draggable_views_field:
+  type: views_field
+  label: 'Draggable Views Field'
+  mapping:
+    action_title:
+      type: label
+      label: 'Action title'
+    include_exclude:
+      type: string
+      label: 'Available actions'
+    selected_actions:
+      type: string
+      label: 'Available actions'
+
+views.sort.draggable_views_sort_default:
+  type: views_sort
+  label: 'Draggableviews Sort Default'
+  mapping:
+    draggable_views_reference:
+      type: string
+      label: 'Views Reference'
+    draggable_views_null_order:
+      type: string
+      label: 'NULL stacking order'
+    draggable_views_pass_arguments:
+      type: boolean
+      label: 'Pass Contextual Filters'
diff --git a/draggableviews.module b/draggableviews.module
index d724fa1..c981b9e 100644
--- a/draggableviews.module
+++ b/draggableviews.module
@@ -25,7 +25,8 @@ function draggableviews_views_data_alter(&$data) {
       'id' => 'numeric',
     ],
     'sort' => [
-      'id' => 'standard',
+      'id' => 'draggable_views_sort_default',
+      'help' => t('Sort by the weight value.'),
     ],
     'filter' => [
       'help' => t('Filter by the draggableviews weight value (Native handler only).'),
@@ -219,30 +220,3 @@ function draggableviews_views_submit(&$form, FormStateInterface $form_state) {
     \Drupal::messenger()->addMessage(t('There was an error while saving the data. Please, try again.'), 'warning');
   }
 }
-
-/**
- * Implements hook_views_query_alter().
- */
-function draggableviews_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
-  // Add additional `join condition` for fixing table join.
-  // Cannot add it in the draggableviews_views_data_alter because we need view
-  // data.
-  if ($query instanceof Sql && isset($query->getTableQueue()['draggableviews_structure'])) {
-    /** @var \Drupal\views\Plugin\views\join\Standard $join */
-    $join = $query->getTableQueue()['draggableviews_structure']['join'];
-    $join->extra = [
-      [
-        'field' => 'view_name',
-        'operator' => '=',
-        'value' => $view->id(),
-        'numeric' => FALSE,
-      ],
-      [
-        'field' => 'view_display',
-        'operator' => '=',
-        'value' => $view->current_display,
-        'numeric' => FALSE,
-      ],
-    ];
-  }
-}
diff --git a/src/Plugin/views/join/WithArgs.php b/src/Plugin/views/join/WithArgs.php
index 6f7d31f..a1acfbd 100644
--- a/src/Plugin/views/join/WithArgs.php
+++ b/src/Plugin/views/join/WithArgs.php
@@ -2,7 +2,9 @@
 
 namespace Drupal\draggableviews\Plugin\views\join;
 
+use Drupal\draggableviews\Plugin\views\sort\DraggableViewsSort;
 use Drupal\views\Plugin\views\join\JoinPluginBase;
+use Drupal\views\ViewExecutable;
 
 /**
  * Defines a join handler with arguments.
@@ -17,6 +19,8 @@ class WithArgs extends JoinPluginBase {
    * {@inheritdoc}
    */
   public function buildJoin($select_query, $table, $view_query) {
+    /** @var ViewExecutable $view */
+    $view = $view_query->view;
     $view_args = !empty($view_query->view->args) ? $view_query->view->args : [];
     $context = [
       'select_query' => &$select_query,
@@ -30,6 +34,18 @@ class WithArgs extends JoinPluginBase {
       $this->extra = [];
     }
 
+    //exclude args if arguments aren't passed
+    $includeArgs = true;
+    $sort = $view->sort ?? [];
+    foreach($sort as $sortClass) {
+      if($sortClass instanceof DraggableViewsSort) {
+        $pass = $sortClass->options['draggable_views_pass_arguments'] ?? 0;
+        if(empty($pass) || $pass ===  '0') {
+          $includeArgs = false;
+        }
+      }
+    }
+
     if (is_array($this->extra)) {
       $found = FALSE;
       foreach ($this->extra as $info) {
@@ -39,7 +55,7 @@ class WithArgs extends JoinPluginBase {
         }
       }
 
-      if (!$found) {
+      if (!$found && $includeArgs) {
         $this->extra[] = ['field' => 'args', 'value' => $view_args];
       }
     }
diff --git a/src/Plugin/views/sort/DraggableViewsSort.php b/src/Plugin/views/sort/DraggableViewsSort.php
new file mode 100644
index 0000000..df9aa0e
--- /dev/null
+++ b/src/Plugin/views/sort/DraggableViewsSort.php
@@ -0,0 +1,202 @@
+<?php
+
+namespace Drupal\draggableviews\Plugin\views\sort;
+
+use Drupal\views\Plugin\views\sort\SortPluginBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\views\Views;
+use Drupal\views\Entity\View;
+
+/**
+ * Basic sort handler for Draggableviews Weight.
+ *
+ * @ViewsSort("draggable_views_sort_default")
+ */
+class DraggableViewsSort extends SortPluginBase {
+
+  /**
+   * The relationship alias.
+   *
+   * @var string
+   */
+  public $alias;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function defineOptions() {
+    $options = parent::defineOptions();
+    $options['draggable_views_reference'] = ['default' => ''];
+    $options['draggable_views_null_order'] = ['default' => 'after'];
+    $options['draggable_views_pass_arguments'] = ['default' => 0];
+    return $options;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
+    parent::buildOptionsForm($form, $form_state);
+
+    $view_options = $this->getViewSortDataOptions();
+
+    $form['draggable_views_reference'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Draggable Views Data'),
+      '#options' => $view_options,
+      '#description' => $this->t('Draggable Views Data to sort on.'),
+      '#default_value' => $this->options['draggable_views_reference'],
+      '#weight' => -1,
+    ];
+
+    $form['draggable_views_null_order'] = [
+      '#type' => 'radios',
+      '#title' => $this->t('NULL Value Order'),
+      '#options' => [
+        'before' => "Before",
+        'after' => "After",
+      ],
+      '#description' => $this->t('If an entity does not currently belong in the list, should it be added to the list at the begining or the end.'),
+      '#default_value' => $this->options['draggable_views_null_order'],
+      '#weight' => -1,
+    ];
+
+    $form['draggable_views_pass_arguments'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Pass Contextual Filters'),
+      '#description' => $this->t('Pass contextual filters from this display to the sort display.'),
+      '#default_value' => $this->options['draggable_views_pass_arguments'],
+      '#weight' => -1,
+    ];
+  }
+
+  /**
+   * Called to add the sort to a query.
+   */
+  public function query() {
+
+    // We should variablise these somehow??
+    $base = 'draggableviews_structure';
+    $base_field = "entity_id";
+
+    // Grab our view/plugin reference.
+    list($view_id, $view_display_id) = $this->splitViewSortDataOptions($this->options['draggable_views_reference']);
+
+    $def = $this->definition;
+    $def['table'] = $base;
+    $def['field'] = $base_field;
+    $def['left_table'] = $this->query->view->storage->get('base_table');
+    $def['left_field'] = $this->query->view->storage->get('base_field');
+    $def['adjusted'] = TRUE;
+
+    $def['extra'][] = [
+      'field' => 'view_name',
+      'value' => $view_id,
+    ];
+    $def['extra'][] = [
+      'field' => 'view_display',
+      'value' => $view_display_id,
+    ];
+
+    if (!empty($this->definition['extra'])) {
+      $def['extra'] = $this->definition['extra'];
+    }
+
+    if (!empty($def['join_id'])) {
+      $id = $def['join_id'];
+    }
+    else {
+      $id = 'draggableviews_with_args';
+    }
+    $join = Views::pluginManager('join')->createInstance($id, $def);
+
+    // Use a short alias for this:
+    $alias = $def['table'];
+
+    $this->alias = $this->query->addRelationship($alias, $join, $this->query->view->storage->get('base_table'), $this->relationship);
+
+    if ($this->options['draggable_views_null_order'] == "before") {
+      $formula = "!ISNULL($this->alias.$this->realField)";
+    }
+    else {
+      $formula = "ISNULL($this->alias.$this->realField)";
+    }
+
+    // We add both to handle ordering of NULL values.
+    $this->query->addOrderBy(NULL, $formula, $this->options['order'], $this->alias . "_" . $this->realField);
+    $this->query->addOrderBy($this->alias, $this->realField, $this->options['order']);
+  }
+
+  /**
+   * Grab available draggable views.
+   */
+  protected function getViewSortDataOptions() {
+    $view_data = [];
+    $query = \Drupal::entityQuery('view');
+    $entity_ids = $query->execute();
+
+    foreach ($entity_ids as $view_id) {
+      $v = View::load($view_id);
+
+      $default_display = NULL;
+      foreach ($v->get('display') as $display_id => $display) {
+        if ($display_id == "default") {
+          $default_display = $display;
+        }
+        else {
+          // Use default if fields are not overwritten.
+          $fields = !empty($display['display_options']['fields'])
+            ? $display['display_options']['fields']
+            : $default_display['display_options']['fields'];
+          // Need to check that "fields" is an array, view may be configured to
+          // render rows otherwise.
+          if (is_array($fields) && in_array("draggableviews", array_keys($fields))) {
+            if (!isset($view_data[$view_id])) {
+              $view_data[$view_id] = [
+                'id' => $view_id,
+                'label' => $v->label(),
+                'displays' => [],
+              ];
+            }
+            $view_data[$view_id]['displays'][$display_id] = [
+              'id' => $display_id,
+              'label' => $display['display_title'],
+            ];
+          }
+        }
+      }
+    }
+
+    $view_select = [
+      'this' => "This View/Display",
+    ];
+    foreach ($view_data as $view_id => $v_data) {
+      $view_key = $v_data['label'] . " (" . $view_id . ")";
+      $view_select[$view_key] = [];
+
+      foreach ($v_data['displays'] as $display) {
+        $display_key = $view_id . ":" . $display['id'];
+
+        $view_select[$view_key][$display_key] = $display['label'];
+      }
+    }
+
+    return $view_select;
+  }
+
+  /**
+   * Split data into view/display ids.
+   */
+  protected function splitViewSortDataOptions($data) {
+    if (empty($data) || $data == "this") {
+      return [$this->view->id(), $this->view->current_display];
+    }
+
+    $explode = explode(":", $data);
+    if (count($explode) != 2) {
+      return ["", ""];
+    }
+    return $explode;
+  }
+
+}
+2 −28
Original line number Diff line number Diff line
@@ -25,7 +25,8 @@ function draggableviews_views_data_alter(&$data) {
      'id' => 'numeric',
    ],
    'sort' => [
      'id' => 'standard',
      'id' => 'draggable_views_sort_default',
      'help' => t('Sort by the weight value.'),
    ],
    'filter' => [
      'help' => t('Filter by the draggableviews weight value (Native handler only).'),
@@ -219,30 +220,3 @@ function draggableviews_views_submit(&$form, FormStateInterface $form_state) {
    \Drupal::messenger()->addMessage(t('There was an error while saving the data. Please, try again.'), 'warning');
  }
}

/**
 * Implements hook_views_query_alter().
 */
function draggableviews_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  // Add additional `join condition` for fixing table join.
  // Cannot add it in the draggableviews_views_data_alter because we need view
  // data.
  if ($query instanceof Sql && isset($query->getTableQueue()['draggableviews_structure'])) {
    /** @var \Drupal\views\Plugin\views\join\Standard $join */
    $join = $query->getTableQueue()['draggableviews_structure']['join'];
    $join->extra = [
      [
        'field' => 'view_name',
        'operator' => '=',
        'value' => $view->id(),
        'numeric' => FALSE,
      ],
      [
        'field' => 'view_display',
        'operator' => '=',
        'value' => $view->current_display,
        'numeric' => FALSE,
      ],
    ];
  }
}
+17 −1
Original line number Diff line number Diff line
@@ -2,7 +2,9 @@

namespace Drupal\draggableviews\Plugin\views\join;

use Drupal\draggableviews\Plugin\views\sort\DraggableViewsSort;
use Drupal\views\Plugin\views\join\JoinPluginBase;
use Drupal\views\ViewExecutable;

/**
 * Defines a join handler with arguments.
@@ -17,6 +19,8 @@ class WithArgs extends JoinPluginBase {
   * {@inheritdoc}
   */
  public function buildJoin($select_query, $table, $view_query) {
    /** @var ViewExecutable $view */
    $view = $view_query->view;
    $view_args = !empty($view_query->view->args) ? $view_query->view->args : [];
    $context = [
      'select_query' => &$select_query,
@@ -30,6 +34,18 @@ class WithArgs extends JoinPluginBase {
      $this->extra = [];
    }

    //exclude args if arguments aren't passed
    $includeArgs = true;
    $sort = $view->sort ?? [];
    foreach($sort as $sortClass) {
      if($sortClass instanceof DraggableViewsSort) {
        $pass = $sortClass->options['draggable_views_pass_arguments'] ?? 0;
        if(empty($pass) || $pass ===  '0') {
          $includeArgs = false;
        }
      }
    }

    if (is_array($this->extra)) {
      $found = FALSE;
      foreach ($this->extra as $info) {
@@ -39,7 +55,7 @@ class WithArgs extends JoinPluginBase {
        }
      }

      if (!$found) {
      if (!$found && $includeArgs) {
        $this->extra[] = ['field' => 'args', 'value' => $view_args];
      }
    }
+202 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\draggableviews\Plugin\views\sort;

use Drupal\views\Plugin\views\sort\SortPluginBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Views;
use Drupal\views\Entity\View;

/**
 * Basic sort handler for Draggableviews Weight.
 *
 * @ViewsSort("draggable_views_sort_default")
 */
class DraggableViewsSort extends SortPluginBase {

  /**
   * The relationship alias.
   *
   * @var string
   */
  public $alias;

  /**
   * {@inheritdoc}
   */
  protected function defineOptions() {
    $options = parent::defineOptions();
    $options['draggable_views_reference'] = ['default' => ''];
    $options['draggable_views_null_order'] = ['default' => 'after'];
    $options['draggable_views_pass_arguments'] = ['default' => 0];
    return $options;
  }

  /**
   * {@inheritdoc}
   */
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    parent::buildOptionsForm($form, $form_state);

    $view_options = $this->getViewSortDataOptions();

    $form['draggable_views_reference'] = [
      '#type' => 'select',
      '#title' => $this->t('Draggable Views Data'),
      '#options' => $view_options,
      '#description' => $this->t('Draggable Views Data to sort on.'),
      '#default_value' => $this->options['draggable_views_reference'],
      '#weight' => -1,
    ];

    $form['draggable_views_null_order'] = [
      '#type' => 'radios',
      '#title' => $this->t('NULL Value Order'),
      '#options' => [
        'before' => "Before",
        'after' => "After",
      ],
      '#description' => $this->t('If an entity does not currently belong in the list, should it be added to the list at the begining or the end.'),
      '#default_value' => $this->options['draggable_views_null_order'],
      '#weight' => -1,
    ];

    $form['draggable_views_pass_arguments'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Pass Contextual Filters'),
      '#description' => $this->t('Pass contextual filters from this display to the sort display.'),
      '#default_value' => $this->options['draggable_views_pass_arguments'],
      '#weight' => -1,
    ];
  }

  /**
   * Called to add the sort to a query.
   */
  public function query() {

    // We should variablise these somehow??
    $base = 'draggableviews_structure';
    $base_field = "entity_id";

    // Grab our view/plugin reference.
    list($view_id, $view_display_id) = $this->splitViewSortDataOptions($this->options['draggable_views_reference']);

    $def = $this->definition;
    $def['table'] = $base;
    $def['field'] = $base_field;
    $def['left_table'] = $this->query->view->storage->get('base_table');
    $def['left_field'] = $this->query->view->storage->get('base_field');
    $def['adjusted'] = TRUE;

    $def['extra'][] = [
      'field' => 'view_name',
      'value' => $view_id,
    ];
    $def['extra'][] = [
      'field' => 'view_display',
      'value' => $view_display_id,
    ];

    if (!empty($this->definition['extra'])) {
      $def['extra'] = $this->definition['extra'];
    }

    if (!empty($def['join_id'])) {
      $id = $def['join_id'];
    }
    else {
      $id = 'draggableviews_with_args';
    }
    $join = Views::pluginManager('join')->createInstance($id, $def);

    // Use a short alias for this:
    $alias = $def['table'];

    $this->alias = $this->query->addRelationship($alias, $join, $this->query->view->storage->get('base_table'), $this->relationship);

    if ($this->options['draggable_views_null_order'] == "before") {
      $formula = "!ISNULL($this->alias.$this->realField)";
    }
    else {
      $formula = "ISNULL($this->alias.$this->realField)";
    }

    // We add both to handle ordering of NULL values.
    $this->query->addOrderBy(NULL, $formula, $this->options['order'], $this->alias . "_" . $this->realField);
    $this->query->addOrderBy($this->alias, $this->realField, $this->options['order']);
  }

  /**
   * Grab available draggable views.
   */
  protected function getViewSortDataOptions() {
    $view_data = [];
    $query = \Drupal::entityQuery('view');
    $entity_ids = $query->execute();

    foreach ($entity_ids as $view_id) {
      $v = View::load($view_id);

      $default_display = NULL;
      foreach ($v->get('display') as $display_id => $display) {
        if ($display_id == "default") {
          $default_display = $display;
        }
        else {
          // Use default if fields are not overwritten.
          $fields = !empty($display['display_options']['fields'])
            ? $display['display_options']['fields']
            : $default_display['display_options']['fields'];
          // Need to check that "fields" is an array, view may be configured to
          // render rows otherwise.
          if (is_array($fields) && in_array("draggableviews", array_keys($fields))) {
            if (!isset($view_data[$view_id])) {
              $view_data[$view_id] = [
                'id' => $view_id,
                'label' => $v->label(),
                'displays' => [],
              ];
            }
            $view_data[$view_id]['displays'][$display_id] = [
              'id' => $display_id,
              'label' => $display['display_title'],
            ];
          }
        }
      }
    }

    $view_select = [
      'this' => "This View/Display",
    ];
    foreach ($view_data as $view_id => $v_data) {
      $view_key = $v_data['label'] . " (" . $view_id . ")";
      $view_select[$view_key] = [];

      foreach ($v_data['displays'] as $display) {
        $display_key = $view_id . ":" . $display['id'];

        $view_select[$view_key][$display_key] = $display['label'];
      }
    }

    return $view_select;
  }

  /**
   * Split data into view/display ids.
   */
  protected function splitViewSortDataOptions($data) {
    if (empty($data) || $data == "this") {
      return [$this->view->id(), $this->view->current_display];
    }

    $explode = explode(":", $data);
    if (count($explode) != 2) {
      return ["", ""];
    }
    return $explode;
  }

}