summaryrefslogtreecommitdiffstats
path: root/views_natural_sort.module
blob: b6f1a12f8755297f358eb614d21da65fb2d1c684 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
<?php

/**
 * @file
 * Contains views_natural_sort.module..
 */

use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Entity\EntityInterface;

/**
 * Implements hook_help().
 */
function views_natural_sort_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    // Main module help for the views_natural_sort module.
    case 'help.page.views_natural_sort':
      $output = '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('Sort results naturally on a node&#039;s title skipping articles like &quot;the&quot; and &quot;a.&quot;') . '</p>';
      return $output;

    default:
  }
}

/**
 * Implements hook_module_implements_alter().
 */
function views_natural_sort_module_implements_alter(&$implements, $hook) {
  if ($hook == 'views_data_alter') {
    // Make views natural sort always last so we get all the up to date info.
    $group = $implements['views_natural_sort'];
    unset($implements['views_natural_sort']);
    $implements['views_natural_sort'] = $group;
  }
}

/**
 * Implements hook_views_natural_sort_get_entry_types().
 * @Not-Rewritten
 */
function views_natural_sort_views_natural_sort_get_entry_types() {
  $supported_entity_properties = views_natural_sort_get_views_configurable_properties();
  $entry_types = array();
  foreach ($supported_entity_properties as $entity_type => $properties) {
    foreach ($properties as $property => $schema_info) {
      $entry_types[] = array(
        'entity_type' => $entity_type,
        'field' => $property,
      );
    }
  }
  return $entry_types;
}

/**
 * Implements hook_views_natural_sort_get_rebuild_data();
 * @Not-Rewritten
 */
function views_natural_sort_views_natural_sort_get_rebuild_data($entry_type){
  $supported_entity_properties = views_natural_sort_get_views_configurable_properties();
  if (empty($supported_entity_properties[$entry_type['entity_type']]) ||
    empty($supported_entity_properties[$entry_type['entity_type']][$entry_type['field']])) {
    return array();
  }


  $query = Drupal::entityQuery($entity_type['entity_type']);

  $entity_ids = $query->execute();

  $storage = \Drupal::entityManager()->getStorage($entity_type['entity_type']);
  $data = array();

  foreach ($entity_ids as $entity_id) {
    $entity = $storage->load($entity_id);
    $data[] = array(
      'eid' => $entity_id,
      'entity_type' => $entry_type['entity_type'],
      'field' => $entry_type['field'],
      'delta' => 0,
      'content' => $entity->{$entry_type['field']}->getValue(),
    );
  }

  return $data;
}

/**
 * Implements hook_entity_insert().
 *
 * This keeps our natural sort index up to date.
 */
function views_natural_sort_entity_insert(EntityInterface $entity) {
  $service = Drupal::service('views_natural_sort.service');
  $supported_entity_properties = $service->getSupportedEntityProperties();
  if (isset($supported_entity_properties[$entity->getEntityTypeId()])) {
    $service->storeIndexRecordsFromEntity($entity);
  }
}

/**
 * Implementation of hook_entity_update().
 *
 * This keeps our natural sort index up to date.
 */
function views_natural_sort_entity_update(EntityInterface $entity) {
  views_natural_sort_entity_insert($entity);
}

/**
 * Implementation of hook_entity_delete().
 *
 * This keeps our natural sort index clean.
 */
function views_natural_sort_entity_delete(EntityInterface $entity) {
  views_natural_sort_remove($entry = array(
    'eid' => $entity->id(),
    'entity_type' => $entity->getEntityTypeId(),
  ));
}

/**
 * Store Multiple views_natural_sort entries
 *
 * @param array $index_entries
 *   An array of entries to store in the views_natural_sort table.
 *
 * @see views_natural_sort_store
 * @Not-Rewritten
 */
function views_natural_sort_store_multiple(array $index_entries) {
  foreach($index_entries as $entry) {
    views_natural_sort_store($entry);
  }
}

/**
 * Save an entry to the database that represents a views_natural_sort index
 *
 * @param array $index_entry
 *   Mirrors the views_natural_sort table
 *     $eid - Entity Id of the item referenced
 *     $entity_type - The Entity Type. Ex. node
 *     $field - reference to the property or field name
 *     $delta - the item number in that field or property
 *     $content - The transformed data that a field will
 *                be sorted by.
 * @Not-Rewritten
 */
function views_natural_sort_store(array $index_entry) {
  // This should take a formatted object and store it into the views_natural_sort table.
  $string = views_natural_sort_transform($index_entry);

  // The size limit on the content field for views_natural_sort is sometimes not
  // enough. Let's truncate all data down to that size. I personally feel the
  // inaccuracy is an acceptable loss, as the bigger the string gets, the less
  // permanent the sort.
  //
  // TODO: Have this pick up off of the schema so if someone does a
  // hook_schema_alter() on me.
  return db_merge('views_natural_sort')
    ->key(array(
      'eid' => $index_entry['eid'],
      'entity_type' => $index_entry['entity_type'],
      'field' => $index_entry['field'],
      'delta' => $index_entry['delta'],
    ))
    ->fields(array(
      'eid' => $index_entry['eid'],
      'entity_type' => $index_entry['entity_type'],
      'field' => $index_entry['field'],
      'delta' => $index_entry['delta'],
      'content' => substr($string, 0, 255),
    ))
    ->execute();
}

/**
 * Remove a views_natural_sort index entry based on keys
 *
 * @param array $index_entry
 *   Mirrors the views_natural_sort table
 *     $eid - Entity Id of the item referenced
 *     $entity_type - The Entity Type. Ex. node
 *     $field - (optional) reference to the property or field name
 *     $delta - (optional)the item number in that field or property
 *   If an optional parameter doesn't exist, this is treated as a wild card
 *   delete
 * @Not-Rewritten
 */
function views_natural_sort_remove($index_entry) {
  $query = db_delete('views_natural_sort')
    ->condition('eid', $index_entry['eid'])
    ->condition('entity_type', $index_entry['entity_type']);
  if (isset($index_entry['field'])) {
    $query->condition('field', $index_entry['field']);
  }
  if (isset($index_entry['delta'])) {
    $query->condition('delta', $index_entry['delta']);
  }
  $query->execute();
}

/**
 * Encodes a string into an ascii-sortable string such as:
 *  - Leading articles in common languages are ignored: The A An El La Le Il
 *  - Unimportant punctuation is ignored: # ' " ( )
 *  - Unimportant words are ignored: and of or
 *
 * @param array $index_entry
 *   Mirrors the views_natural_sort table
 *     $eid - Entity Id of the item referenced
 *     $entity_type - The Entity Type. Ex. node
 *     $field - reference to the property or field name
 *     $delta - the item number in that field or property
 *
 * @return string
 *   The transformed string
 * @Not-Rewritten
 */
function views_natural_sort_transform($index_entry) {
  // Get copy the original string.
  $string = $index_entry['content'];
  module_load_include('inc', 'views_natural_sort', 'views_natural_sort');
  foreach (views_natural_sort_get_transformations($index_entry) as $transformation_method) {
    $string = $transformation_method($string);
  }
  return $string;
}

/**
 * Get the full list of transformations to run when saving a natural sort entry.
 * @param array $index_entry
 *   The original entry to be written to the views_natural_sort table.
 *     $eid - Entity Id of the item referenced
 *     $entity_type - The Entity Type. Ex. node
 *     $field - reference to the property or field name
 *     $delta - the item number in that field or property
 *     $content - The transformed data that a field will
 *                be sorted by.
 *
 * @return array
 *   The final list of transformations.
 * @STUBBED
 */
function views_natural_sort_get_transformations($index_entry) {
  $transformations = array(
    'views_natural_sort_remove_beginning_words',
    'views_natural_sort_remove_words',
    'views_natural_sort_remove_symbols',
    'views_natural_sort_numbers',
  );
  // Allow other modules to modify the transformation that happens here if
  // needed.
  Drupal::moduleHandler()->alter('views_natural_sort_transformations', $transformations, $index_entry);
  return $transformations;
}

/**
 * Retrieve the full list of entities and properties that can be supported.
 *
 * @return array
 *  An array of property information keyed by entity machine name. Example:
 *  array (
 *    'node' => array (
 *      'type' => array (
 *        'base_table' => 'node',
 *        'schema_field' => 'type',
 *      ),
 *      'title' => array (
 *        'base_table' => 'node',
 *        'schema_field' => 'title',
 *      ),
 *      'language' => array (
 *        'base_table' => 'node',
 *        'schema_field' => 'language',
 *      ),
 *    ),
 *    'user' => array (
 *      'name' => array (
 *        'base_table' => 'users',
 *        'schema_field' => 'name',
 *      ),
 *      'mail' => array (
 *        'base_table' => 'users',
 *        'schema_field' => 'mail',
 *      ),
 *      'theme' => array (
 *        'base_table' => 'users',
 *        'schema_field' => 'theme',
 *      ),
 *    ),
 *    'file' => array (
 *      'name' => array (
 *        'base_table' => 'file_managed',
 *        'schema_field' => 'filename',
 *      ),
 *      'mime' => array (
 *        'base_table' => 'file_managed',
 *        'schema_field' => 'filemime',
 *      ),
 *    ),
 *  )
 * @STUBBED
 */
function views_natural_sort_get_supported_entity_properties() {
  $supported_properties = &drupal_static(__FUNCTION__, array());
  if (empty($supported_properties)) {
    $supported_properties = [
      'node' => [
        'title' => [
          'base_table' => 'node_field_data',
          'schema_field' => 'title',
        ],
      ],
    ];
  }
  return $supported_properties;
}

/**
 * Returns a list of properties that we know views will allow us to alter.
 *
 * This list of properties is more realistic than "supported properties" because
 * it factors in what views actually contains handlers for. This is used by
 * all the administration functions to determine what properties need to be
 * affected by VNS.
 *
 * @return mixed
 *   Returns an array formatted as views_natural_sort_get_supported_entity_properties
 *   or FALSE when views hasn't been initialized yet.
 *
 * @see views_natural_sort_get_supported_entity_properties
 * @STUBBED
 */
function views_natural_sort_get_views_configurable_properties() {
  $views_configurable_properties = &drupal_static(__FUNCTION__, array());
  if (empty($supported_properties)) {
    $supported_entity_properties = views_natural_sort_get_supported_entity_properties();
  }
  return $supported_entity_properties;
}

/**
 * A helper function for creating a VNS record for storage.
 *
 * @param stdClass $entity
 * @param string $field
 *
 * @return array
 *   An array that represents the VNS table row to be inserted.
 */
function views_natural_sort_entity_to_vns(EntityInterface $entity, $field) {
  $entity_type = $entity->getEntityTypeId();
  $supported_entity_properties = views_natural_sort_get_views_configurable_properties();
  if (empty($supported_entity_properties[$entity_type]) ||
    empty($supported_entity_properties[$entity_type][$field])) {
    throw new Exception("$entity_type -> $field doesn't exist. Cannot create Views Natural Sort record");
  }
  $data = [];
  foreach ($entity->get($field)->getValue() as $delta => $value) {
    $data[] = [
      'eid' => $entity->id(),
      'entity_type' => $entity_type,
      'field' => $field,
      'delta' => $delta,
      // This may have to be passed in if it's not always ['value'].
      'content' => $value['value'],
    ];
  }
  return $data;
}