Newer
Older
* Views Natural Sort module.
*/
/*
* Provides a views filter that sorts titles by a more natural manner by
* ignoring articles like "The" and "A.".
*
* Normal sort:
* A Chorus Line
* All American
* Fiddler on the Roof
* Oklahoma!
* The King And I.
*
* Natural sort:
* All American
* A Chorus Line
* Fiddler on the Roof
* The King And I
* Oklahoma!
*/
/**
* Implements hook_menu().
*/
function views_natural_sort_menu() {
$items = array();
$items['admin/structure/views/settings/views_natural_sort'] = array(
'title' => 'Natural Sort',
'description' => 'Set the settings for how particular transformations should behave.',
'page callback' => 'views_natural_sort_settings_page',
'access callback' => 'user_access',
'access arguments' => array('administer views'),
'file' => 'views_natural_sort.admin.inc',
'type' => MENU_LOCAL_TASK,
/**
* Implements hook_views_api().
*/
function views_natural_sort_views_api() {
return array(
Allan Chappell
committed
'api' => 3.0,
);
}
* Implements hook_implements_alter().
Allan Chappell
committed
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().
function views_natural_sort_views_natural_sort_get_entry_types() {
$supported_entity_properties = views_natural_sort_get_views_configurable_properties();
Allan Chappell
committed
$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_queue_rebuild_data().
function views_natural_sort_views_natural_sort_queue_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();
}
$queue = views_natural_sort_get_queue();
$query = new EntityFieldQuery();
$result = $query->entityCondition('entity_type', $entry_type['entity_type'])
->execute();
$entity_ids = array();
if (isset($result[$entry_type['entity_type']])) {
$entity_ids = array_keys($result[$entry_type['entity_type']]);
}
foreach ($entity_ids as $entity_id) {
$results = entity_load($entry_type['entity_type'], array($entity_id));
$entity = reset($results);
Allan Chappell
committed
$field_name = $entry_type['field'];
$queue->createItem(array(
'eid' => $entity_id,
'entity_type' => $entry_type['entity_type'],
Allan Chappell
committed
'field' => $field_name,
'delta' => 0,
Allan Chappell
committed
'content' => $entity->$field_name,
}
}
/**
* Implements hook_entity_insert().
*
* This keeps our natural sort index up to date.
*/
function views_natural_sort_entity_insert($entity, $type) {
$supported_entity_properties = views_natural_sort_get_views_configurable_properties();
if (empty($supported_entity_properties[$type])) {
return;
}
foreach ($supported_entity_properties[$type] as $property => $property_info) {
// Proposed by hgoto in #2672538. Made it in before he got credit.
if (isset($entity->{$property})) {
views_natural_sort_store(views_natural_sort_entity_to_vns($entity, $type, $property));
}
}
}
/**
* Implements hook_entity_update().
*
* This keeps our natural sort index up to date.
*/
function views_natural_sort_entity_update($entity, $type) {
views_natural_sort_entity_insert($entity, $type);
}
/**
* Implements hook_entity_delete().
*
* This keep sour natural sort index clean.
*/
function views_natural_sort_entity_delete($entity, $type) {
Allan Chappell
committed
$entity_info = entity_get_info($type);
$id_field = $entity_info['entity keys']['id'];
views_natural_sort_remove($entry = array(
'eid' => $entity->$id_field,
'entity_type' => $type,
));
}
Allan Chappell
committed
/**
* Implements hook_cron_queue_info().
*/
function views_natural_sort_cron_queue_info() {
return array(
'views_natural_sort_index_queue' => array(
'worker callback' => 'views_natural_sort_process_index_queue',
'skip on cron' => TRUE,
),
);
}
/**
* Queue worker callback for views_natural_sort_index_queue.
*
* @see callback_queue_worker
*/
function views_natural_sort_process_index_queue($data) {
if (is_array($data)) {
views_natural_sort_store($data);
}
}
/**
* 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
*/
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.
*/
function views_natural_sort_store(array $index_entry) {
// This should take a formatted object and store it into the
// views_natural_sort table.
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
$string = views_natural_sort_transform($index_entry);
// The size limit on the content field for views_natual_sort is sometimes not
// enough. Lets 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 care
function views_natural_sort_remove(array $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.
*
* Encoding rquires a set of transformations. Those transformations perform
* functionality such as:
* - Leading articles in common languages are ingored: 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
*/
function views_natural_sort_transform(array $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.
*/
function views_natural_sort_get_transformations(array $index_entry) {
$transformations = array(
'views_natural_sort_remove_beginning_words',
'views_natural_sort_remove_words',
'views_natural_sort_remove_symbols',
'views_natural_sort_numbers',
);
if (variable_get('views_natural_sort_days_of_the_week_enabled', FALSE)) {
$transformations[] = "views_natural_sort_days_of_the_week_sort_days";
}
// Allow other modules to modify the transformation that happens here if
// needed.
drupal_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 (
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
* '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',
* ),
* ),
function views_natural_sort_get_supported_entity_properties() {
$supported_properties = &drupal_static(__FUNCTION__, array());
if (empty($supported_properties)) {
$entity_property_info = entity_get_property_info();
$entity_info = entity_get_info();
foreach ($entity_property_info as $entity_type => $info) {
if (empty($supported_properties[$entity_type])) {
$supported_properties[$entity_type] = array();
}
$properties = $info['properties'];
foreach ($properties as $property => $property_info) {
Allan Chappell
committed
$property_info += entity_property_info_defaults();
if ($property_info['type'] != 'text' || empty($property_info['schema field'])) {
continue;
}
$schema = drupal_get_schema($entity_info[$entity_type]['base table']);
$schema_field = $property_info['schema field'];
Allan Chappell
committed
if (empty($schema['fields'][$schema_field]) || $schema['fields'][$schema_field]['type'] != 'varchar') {
continue;
}
$supported_properties[$entity_type][$property] = array(
'base_table' => $entity_info[$entity_type]['base table'],
'schema_field' => $property_info['schema field'],
);
}
}
}
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 initianalized yet.
*
* @see views_natural_sort_get_supported_entity_properties
*/
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();
$views_data = views_fetch_data();
if (empty($views_data)) {
return FALSE;
}
foreach ($supported_entity_properties as $entity => $properties) {
foreach ($properties as $property => $schema_info) {
if (!empty($views_data[$schema_info['base_table']][$schema_info['schema_field']]) &&
!empty($views_data[$schema_info['base_table']][$schema_info['schema_field']]['sort']) &&
!empty($views_data[$schema_info['base_table']][$schema_info['schema_field']]['sort']['handler']) &&
in_array($views_data[$schema_info['base_table']][$schema_info['schema_field']]['sort']['handler'], array('views_natural_sort_handler_sort', 'views_handler_sort'))) {
$views_configurable_properties[$entity][$property] = $schema_info;
}
}
}
}
return $views_configurable_properties;
}
/**
* A helper function for creating a VNS record for storage.
*
* @param object $entity
* An object representing an entity.
* @param string $entity_type
* The machine name for an entity type.
* The machine name for the field the data belongs to.
*
* @return array
* An array that represents the VNS table row to be inserted.
*/
function views_natural_sort_entity_to_vns($entity, $entity_type, $field) {
$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");
}
$entity_info = entity_get_info($entity_type);
$id_field = $entity_info['entity keys']['id'];
return array(
'eid' => $entity->$id_field,
'entity_type' => $entity_type,
'field' => $field,
'delta' => 0,
'content' => $entity->$field,
);
}
* Get the queue used to store natural sort index jobs.
*/
function views_natural_sort_get_queue() {
return DrupalQueue::get('views_natural_sort_index_queue');
}