You are here

public function FlippyPager::flippy_build_list in Flippy 8

Helper function: Query to get the list of flippy pagers.

Parameters

Drupal\node\Entity\Node $node: Current node object.

Return value

array A list of flippy pagers.

File

src/FlippyPager.php, line 108

Class

FlippyPager
Defines the flippy pager service.

Namespace

Drupal\flippy

Code

public function flippy_build_list(Node $node) {

  // Get all the properties from the current node.
  $master_list =& drupal_static(__FUNCTION__);
  if (!isset($master_list)) {
    $master_list = [];
  }
  if (!isset($master_list[$node
    ->id()])) {

    // Check to see if we need custom sorting.
    if ($this->flippySettings
      ->get('flippy_custom_sorting_' . $node
      ->getType())) {

      // Get order.
      $order = $this->flippySettings
        ->get('flippy_order_' . $node
        ->getType());

      // Get sort.
      $sort = $this->flippySettings
        ->get('flippy_sort_' . $node
        ->getType());
    }
    else {
      $order = 'ASC';
      $sort = 'created';
    }

    // Validate that the sort criteria is OK to use.
    // Achieve the base field from a node type.
    $sort_options = [];

    // Get all the field from a node type.
    $content_type_fields = $this->entityFieldManager
      ->getFieldDefinitions('node', $node
      ->getType());
    foreach ($content_type_fields as $sort_field) {
      if (get_class($sort_field) == 'Drupal\\Core\\Field\\BaseFieldDefinition') {

        // It is a base field.
        $schema_info = $sort_field
          ->getSchema();
      }
      if (isset($schema_info['columns']['value']) && $schema_info['columns']['value']['type'] == 'int') {
        $sort_options[] = $sort_field
          ->getName();
      }
    }
    $base_table_properties = $sort_options;
    $field_value = NULL;

    // If the sort criteria is not in the $sort_option array, we assume it's
    // a field.
    if (!in_array($sort, $base_table_properties)) {

      // Get the value of the current node's field (use the first one only)
      $current_field_items = $node->{$sort}
        ->getValue();
      if (!isset($current_field_items[0]['value'])) {

        // Should never happen, but just in case, fall back to post date
        // ascending.
        $sort = 'created';
        $order = 'ASC';
      }
      else {

        // Otherwise save the field value for later.
        $field_value = $current_field_items[0]['value'];
      }
    }

    // Depending on order, decide what before and after means.
    $before = $order == 'ASC' ? '<' : '>';
    $after = $order == 'ASC' ? '>' : '<';

    // Also decide what up and down means.
    $up = $order == 'ASC' ? 'ASC' : 'DESC';
    $down = $order == 'ASC' ? 'DESC' : 'ASC';

    // Create a starting-point EntityQuery object.
    $query = $this->entityTypeManager
      ->getStorage('node')
      ->getQuery();
    $query
      ->condition('type', $node
      ->getType())
      ->condition('status', 1)
      ->condition('langcode', $this->languageManager
      ->getCurrentLanguage()
      ->getId())
      ->condition('nid', $node
      ->id(), '!=')
      ->addTag('node_access');

    // Create the individual queries.
    $first = clone $query;
    $prev = clone $query;
    $next = clone $query;
    $last = clone $query;
    $random = clone $query;

    // We will construct the queries differently depending on whether the
    // sorting criteria is a field or a base table property.
    // If we found a field value earlier, we know we're dealing with a field.
    if (isset($field_value)) {

      // Set the conditions.
      // The first query.
      $field_value_equal_condition = $first
        ->orConditionGroup()
        ->condition($sort . '.value', $field_value, '=')
        ->condition($sort . '.value', NULL, 'IS NULL');
      $field_default_condition = $first
        ->andConditionGroup()
        ->condition('nid', $node
        ->id(), $before)
        ->condition($field_value_equal_condition);
      $field_sorting_group = $first
        ->orConditionGroup()
        ->condition($sort . '.value', $field_value, $before)
        ->condition($field_default_condition);
      $first
        ->condition($field_sorting_group);

      // The last query.
      $field_value_equal_condition = $last
        ->orConditionGroup()
        ->condition($sort . '.value', $field_value, '=')
        ->condition($sort . '.value', NULL, 'IS NULL');
      $field_default_condition = $last
        ->andConditionGroup()
        ->condition('nid', $node
        ->id(), $after)
        ->condition($field_value_equal_condition);
      $field_sorting_group = $last
        ->orConditionGroup()
        ->condition($sort . '.value', $field_value, $after)
        ->condition($field_default_condition);
      $last
        ->condition($field_sorting_group);

      // Previous query to find out the previous item based on the field,
      // using node id if the other criteria is the same.
      // The prev query.
      $field_value_equal_condition = $prev
        ->orConditionGroup()
        ->condition($sort . '.value', $field_value, '=')
        ->condition($sort . '.value', NULL, 'IS NULL');
      $field_default_condition = $prev
        ->andConditionGroup()
        ->condition('nid', $node
        ->id(), $before)
        ->condition($field_value_equal_condition);
      $field_sorting_group = $prev
        ->orConditionGroup()
        ->condition($sort . '.value', $field_value, $before)
        ->condition($field_default_condition);
      $prev
        ->condition($field_sorting_group);

      // The next query.
      $field_value_equal_condition = $next
        ->orConditionGroup()
        ->condition($sort . '.value', $field_value, '=')
        ->condition($sort . '.value', NULL, 'IS NULL');
      $field_default_condition = $next
        ->andConditionGroup()
        ->condition('nid', $node
        ->id(), $after)
        ->condition($field_value_equal_condition);
      $field_sorting_group = $next
        ->orConditionGroup()
        ->condition($sort . '.value', $field_value, $after)
        ->condition($field_default_condition);
      $next
        ->condition($field_sorting_group);

      // Set the ordering.
      $first
        ->sort($sort, $up);
      $prev
        ->sort($sort, $down);
      $next
        ->sort($sort, $up);
      $last
        ->sort($sort, $down);
    }
    else {

      // Otherwise we assume the variable is a column in the base table
      // (a property). Like above, set the conditions.
      $sort_value = $node
        ->get($sort);
      $sort_value = $sort_value
        ->getValue();

      // First and last query.
      $first
        ->condition($sort, $sort_value[0]['value'], $before);
      $last
        ->condition($sort, $sort_value[0]['value'], $after);

      // Previous query to find out the previous item based on the field,
      // using node id if the other criteria is the same.
      $field_default_condition = $prev
        ->andConditionGroup()
        ->condition($sort, $sort_value[0]['value'])
        ->condition('nid', $node
        ->id(), $before);
      $field_sorting_group = $prev
        ->orConditionGroup()
        ->condition($sort, $sort_value[0]['value'], $before)
        ->condition($field_default_condition);
      $prev
        ->condition($field_sorting_group);

      // Next query to find out the next item based on the field, using
      // node id if the other criteria is the same.
      $field_default_condition = $next
        ->andConditionGroup()
        ->condition($sort, $sort_value[0]['value'])
        ->condition('nid', $node
        ->id(), $after);
      $field_sorting_group = $next
        ->orConditionGroup()
        ->condition($sort, $sort_value[0]['value'], $after)
        ->condition($field_default_condition);
      $next
        ->condition($field_sorting_group);

      // Set the ordering.
      $first
        ->sort($sort, $up);
      $prev
        ->sort($sort, $down);
      $next
        ->sort($sort, $up);
      $last
        ->sort($sort, $down);
    }

    // Event dispatcher.
    $queries = [
      'first' => $first,
      'prev' => $prev,
      'next' => $next,
      'last' => $last,
    ];
    $event = new FlippyEvent($queries, $node);
    $this->eventDispatcher
      ->dispatch('buildFlippyQuery', $event);
    $queries = $event
      ->getQueries();

    // Execute the queries.
    $results = [];
    $results['first'] = $queries['first']
      ->range(0, 1)
      ->execute();
    $results['first'] = !empty($results['first']) ? array_values($results['first'])[0] : NULL;
    $results['prev'] = $queries['prev']
      ->range(0, 1)
      ->execute();
    $results['prev'] = !empty($results['prev']) ? array_values($results['prev'])[0] : NULL;
    $results['next'] = $queries['next']
      ->range(0, 1)
      ->execute();
    $results['next'] = !empty($results['next']) ? array_values($results['next'])[0] : NULL;
    $results['last'] = $queries['last']
      ->range(0, 1)
      ->execute();
    $results['last'] = !empty($results['last']) ? array_values($results['last'])[0] : NULL;
    $node_ids = [];
    foreach ($results as $key => $result) {

      // If the query returned no results, it means we're already
      // at the beginning/end of the pager, so ignore those.
      if (is_numeric($result)) {

        // Otherwise we save the node ID.
        $node_ids[$key] = (int) $result;
      }
      elseif (is_array($result) && count($result) > 0) {

        // Otherwise we save the node ID.
        $node_ids[$key] = $results[$key];
      }
    }

    // Make our final array of node IDs and titles.
    $list = [];

    // But only if we actually found some matches.
    if (count($node_ids) > 0) {

      // We also need titles to go with our node ids.
      $title_query = $this->connection
        ->select('node_field_data', 'nfd')
        ->fields('nfd', [
        'title',
        'nid',
      ])
        ->condition('nfd.nid', $node_ids, 'IN')
        ->execute()
        ->fetchAllAssoc('nid');
      foreach ($node_ids as $key => $nid) {
        $list[$key] = [
          'nid' => $nid,
          'title' => isset($title_query[$nid]) ? $title_query[$nid]->title : '',
        ];
      }
    }

    // Create random list.
    // TODO: orderRandom is not available in entityQuery yet.
    if ($this->flippySettings
      ->get('flippy_random_' . $node
      ->getType())) {
      $random_nids = $random
        ->execute();
      $random_nid = array_rand($random_nids, 1);

      // Find out the node title.
      $title = $this->connection
        ->select('node_field_data', 'nfd')
        ->fields('nfd', [
        'title',
      ])
        ->condition('nfd.nid', $random_nid, '=')
        ->execute()
        ->fetchField();
      $list['random'] = [
        'nid' => $random_nid,
        'title' => $title,
      ];
    }
    $master_list[$node
      ->id()] = $list;
  }
  return $master_list[$node
    ->id()];
}