t('Image gallery'), 'relationship' => array( 'title' => t('Latest image'), 'label' => t('Cover image, latest'), 'help' => t('Relate an image gallery to its most recently updated node (does not consider child galleries).'), 'handler' => 'image_gallery_handler_relationship_gallery_cover', 'base' => 'node', 'field' => 'nid', 'correlated field' => 'tid', 'subquery order' => ' gallery_cover_node.created DESC ', ), ); $data['term_data']['image_gallery_cover_oldest'] = array( 'group' => t('Image gallery'), 'relationship' => array( 'title' => t('Oldest image'), 'label' => t('Cover image, oldest'), 'help' => t('Relate an image gallery to its oldest node (does not consider child galleries).'), 'handler' => 'image_gallery_handler_relationship_gallery_cover', 'base' => 'node', 'field' => 'nid', 'correlated field' => 'tid', 'subquery order' => ' gallery_cover_node.created ASC ', ), ); $data['term_data']['image_gallery_cover_node_title'] = array( 'group' => t('Image gallery'), 'relationship' => array( 'title' => t('First image by title'), 'label' => t('Cover image, first by title'), 'help' => t('Relate an image gallery to its first node when sorted by title (does not consider child galleries).'), 'handler' => 'image_gallery_handler_relationship_gallery_cover', 'base' => 'node', 'field' => 'nid', 'correlated field' => 'tid', 'subquery order' => ' gallery_cover_node.title ASC ', ), ); // ---------------------------------------------------------------------- // Simple fields. // Gallery count. $data['term_data']['image_gallery_count'] = array( 'group' => t('Image gallery'), 'field' => array( 'title' => t('Count'), 'help' => t('Count of items in a gallery.'), 'handler' => 'image_gallery_handler_field_gallery_count', ), ); // ---------------------------------------------------------------------- // Fields for cover image. // // These use a combination of code and separate queries to get a cover node. // This makes them more powerful that using the relationship cover node, // as we can consider child galleries recursively rather than just // flattening all descendant galleries. // We can also do complex things such as grab the top-most node from the // gallery according to how the view for that gallery sorts them. // The downside however is that without a relationship, the fields here are // all you've got. // To add more fields, define them on term_data and optionally add handlers. // See image_gallery_handler_field_gallery_cover for more information. $data['term_data']['image_gallery_latest_thumbnail'] = array( 'group' => t('Image gallery'), 'field' => array( 'title' => t('Latest image'), 'help' => t('The most recently posted image in the gallery or its child galleries.'), 'handler' => 'image_gallery_handler_field_gallery_cover_thumbnail', 'order clause' => 'n.sticky DESC, n.created DESC', ), ); $data['term_data']['image_gallery_latest_time'] = array( 'group' => t('Image gallery'), 'field' => array( 'title' => t('Last updated time'), 'help' => t('The time of the most recently posted image in the gallery or its child galleries.'), 'handler' => 'image_gallery_handler_field_gallery_cover_latest_time', 'order clause' => 'n.sticky DESC, n.created DESC', ), ); $data['term_data']['image_gallery_first_title'] = array( 'group' => t('Image gallery'), 'field' => array( 'title' => t('First image by title'), 'help' => t('The first posted image in the gallery or its child galleries.'), 'handler' => 'image_gallery_handler_field_gallery_cover_thumbnail', 'order clause' => 'n.sticky DESC, n.title ASC', ), ); $data['term_data']['image_gallery_oldest_thumbnail'] = array( 'group' => t('Image gallery'), 'field' => array( 'title' => t('Oldest image'), 'help' => t('The first posted image in the gallery or its child galleries.'), 'handler' => 'image_gallery_handler_field_gallery_cover_thumbnail', 'order clause' => 'n.sticky DESC, n.created ASC', ), ); } /** * Implementation of hook_views_handlers(). */ function image_gallery_views_handlers() { return array( 'info' => array( 'path' => drupal_get_path('module', 'image_gallery') . '/views', ), 'handlers' => array( 'image_gallery_handler_field_gallery_count' => array( 'parent' => 'views_handler_field_taxonomy', ), 'image_gallery_handler_field_gallery_cover' => array( 'parent' => 'views_handler_field_taxonomy', ), 'image_gallery_handler_field_gallery_cover_thumbnail' => array( 'parent' => 'image_gallery_handler_field_gallery_cover', ), 'image_gallery_handler_field_gallery_cover_latest_time' => array( 'parent' => 'image_gallery_handler_field_gallery_cover', ), 'image_gallery_handler_relationship_gallery_cover' => array( 'parent' => 'views_handler_relationship', ), 'image_gallery_plugin_display_image_gallery' => array( 'parent' => 'views_plugin_display_page', ), ), ); } /** * Implementation of hook_views_plugins(). */ function image_gallery_views_plugins() { return array( 'display' => array( /** * The image gallery display: like a page, but with a subgallery * list embedded above it. * Uses a handler rather than a tpl file. */ 'image_gallery' => array( 'title' => t('Gallery page'), 'help' => t('Display the view as a gallery of images, with a URL and menu links.'), 'parent' => 'page', 'handler' => 'image_gallery_plugin_display_image_gallery', 'theme' => 'views_view', 'uses hook menu' => TRUE, 'use ajax' => TRUE, 'use pager' => TRUE, 'accept attachments' => TRUE, 'admin' => t('Page'), // @todo ? 'help topic' => 'display-page', 'path' => drupal_get_path('module', 'image_gallery') . '/views', ), ), 'style' => array( /** * A list style for term lists. */ 'image_gallery_terms' => array( 'title' => 'Subgallery list', 'help' => t('Displays subgalleries in a formatted list.'), 'parent' => 'list', 'handler' => 'views_plugin_style_list', 'theme path' => drupal_get_path('module', 'image_gallery') . '/views/theme', 'theme file' => 'theme.inc', 'theme' => 'image_gallery_view_image_gallery_terms', 'uses row plugin' => TRUE, 'uses options' => TRUE, 'type' => 'normal', 'help topic' => 'style-list', ), ), ); } /** * Join handler for relationships that join with a subquery as the left field. * To use this join, set 'left query' in the definition as a subquery to go on * the left side of the JOIN condition, ie: * LEFT JOIN node node_term_data ON ([YOUR SUBQUERY HERE]) = node_term_data.nid * This should ultimately be replaced with the stuff for general groupwise * max relationships in views: @see . */ class image_gallery_join_subquery extends views_join { // PHP 4 doesn't call constructors of the base class automatically from a // constructor of a derived class. It is your responsibility to propagate // the call to constructors upstream where appropriate. function construct($table = NULL, $left_table = NULL, $left_field = NULL, $field = NULL, $extra = array(), $type = 'LEFT') { parent::construct($table, $left_table, $left_field, $field, $extra, $type); $this->left_query = $this->definition['left query']; } /** * Build the SQL for the join this object represents. */ function join($table, &$query) { $left = $query->get_table_info($this->left_table); $output = " $this->type JOIN {" . $this->table . "} $table[alias] ON ($this->left_query) = $table[alias].$this->field"; // Tack on the extra. if (isset($this->extra)) { if (is_array($this->extra)) { $extras = array(); foreach ($this->extra as $info) { $extra = ''; // Figure out the table name. Remember, only use aliases provided // if at all possible. $join_table = ''; if (!array_key_exists('table', $info)) { $join_table = $table['alias'] . '.'; } elseif (isset($info['table'])) { $join_table = $info['table'] . '.'; } // And now deal with the value and the operator. Set $q to // a single-quote for non-numeric values and the // empty-string for numeric values, then wrap all values in $q. $raw_value = $this->db_safe($info['value']); $q = (empty($info['numeric']) ? "'" : ''); if (is_array($raw_value)) { $operator = !empty($info['operator']) ? $info['operator'] : 'IN'; // Transform from IN() notation to = notation if just one value. if (count($raw_value) == 1) { $value = $q . array_shift($raw_value) . $q; $operator = $operator == 'NOT IN' ? '!=' : '='; } else { $value = "($q" . implode("$q, $q", $raw_value) . "$q)"; } } else { $operator = !empty($info['operator']) ? $info['operator'] : '='; $value = "$q$raw_value$q"; } $extras[] = "$join_table$info[field] $operator $value"; } if ($extras) { if (count($extras) == 1) { $output .= ' AND ' . array_shift($extras); } else { $output .= ' AND (' . implode(' ' . $this->extra_type . ' ', $extras) . ')'; } } } else if ($this->extra && is_string($this->extra)) { $output .= " AND ($this->extra)"; } } return $output; } }