'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, ); return $items; } /** * Implements hook_views_api(). */ function views_natural_sort_views_api() { return array( 'api' => 3.0, ); } /** * Implements hook_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(). */ 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_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); $queue->createItem(array( 'eid' => $entity_id, 'entity_type' => $entry_type['entity_type'], 'field' => $entry_type['field'], 'delta' => 0, 'content' => $entity->$entry_type['field'], )); } } /** * 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) { $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, )); } /** * 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. $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 * delete. */ 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 ( * '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) { $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']; 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. * @param string $field * 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'); }