Hi, I have like 10 flagging options per node.

With my views I do things like

Create exposed filters for each node.

If I have exposed filters for each 5 Flags, i do this:

1) Create a relationship in views

flags: flag a by any user
X10

2) create exposed filter with and grouping
x10

3)create filters not exposed with or grouping
x10

So in the end I have 10 relationships, and 30 filters. It takes a long time to create a view like this.

I would much rather create a single relationship

something like:

Relationships:

A) Relationship ==== show me a relationship to all flags (not on a flag per flag type basis)

filter:
A) Content has any flagged content (all flagging types) true or false
B) Any of flagged content if flagged by current user

Attached is my ridiculously big view.

If there is an alternative to flag by flag relationships and filters, please let me know. I am using drupal 7 / views 3

CommentFileSizeAuthor
big.txt40.25 KBAntiNSA
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

AntiNSA created an issue. See original summary.

joachim’s picture

Priority: Critical » Normal

There isn't.

In theory, you could create one.

AntiNSA’s picture

I know there is a way to filter for terms, or entire vocabularies with taxonomy. It seems as though there should be a way to do this or something similiar... filter for individual flags or any lags, or as mention above. I dont have the ability to make such a mod... if anyone else does I could really use it. The way Im doing it is completely unefficient... Yet I kow no other way,,

trentl’s picture

I've seen a couple of posts about this and was facing the same issue, as I wanted to be able to offer an advanced filter in order to allow search on one or multiple flags. I wrote a rudimentary module to make it possible and thought I would share.

Note that this is not that robust, so it likely requires a bit more logic to make it so, but this will provide those looking for a solution with a starting point. I'm sure there is some clean up that could be done. :-)

1) create your .info file (I named my module "flag_assist"). Requires Views and Flag module.
2) create .install
This creates a database table in order to create a relationship between content (node) and flag. If you require the relationship to be something other than the node table (e.g. taxonomy) this won't work and will need to be modified to fit your needs.

/**
 * Implements hook_schema().
 */
function flag_assist_schema() {
  
  $schema = array();
   
  $schema['flag_assist'] = array(
    'description' => 'The flag assist base table for the information we want exposed to Views.',
    'fields' => array(
    	'fa_id' => array(
    		'description' => 'Serialized key field for data table',
    		'type' => 'serial',
    		'unsigned' => TRUE,
    		'not null' => TRUE,
    	),
		'nid' => array(
			'description' => 'Node {node}.nid of the data record related to the Flag.',
			'type' => 'int',
			'unsigned' => TRUE,
			'not null' => TRUE,
		),
		'fid' => array(
			'description' => 'Flag ID of the Flag related to the {node}.nid.',
			'type' => 'int',
			'unsigned' => TRUE,
			'not null' => FALSE,
			'default' => NULL,
		),
		'name' => array(
			'description' => 'The name of the flag.',
			'type' => 'varchar',
			'length' => 255,
			'not null' => FALSE,
		),
    ),
    'indexes' => array(
    	'flag_id_group' => array (
    		'fa_id',
    		'fid',
    		'nid',
    	),
    ),
    'primary key' => array(
    	'fa_id',
    ),
  );
  
  return $schema;
}

3. Create your .module file
This populates the flag_assist table with the nid, fid and flag name allowing it to act as an intermediary between content and flag.

/**
 * Implements hook_views_api().
 */
function flag_assist_views_api(){
	return array(
		'api' => 3,
		'path' => drupal_get_path('module', 'flag_assist') . '/includes',
	);
}
/**
 * Implements hook_flag_flag()
 */
function flag_assist_flag_flag($flag, $content_id, $account, $flagging) {
	// insert new flag relation
	db_insert('flag_assist')
	->fields(array(
		'nid' => $content_id,
		'fid' => $flag->fid,
		'name' => $flag->name,
	))
	->execute();
}
/**
 * Implements hook_flag_unflag()
 */
function flag_assist_flag_unflag($flag, $content_id, $account, $flagging) {
	// flag changed, delete the flag relation
	db_delete('flag_assist')
	->condition('nid', $content_id, '=')
	->condition('fid', $flag->fid, '=')
	->execute();
}
/**
 * Implements options for our view list().
 * returns @array
 */
function get_flag_names($field) {
	$results = db_query("SELECT DISTINCT {$field} FROM {flag}")->fetchAll();
	$options = array();
	foreach($results as $result) {
		foreach($result as $key => $value) {
			$options[$value] = $value;
		}
	}
	return $options;
}

4. Add your .inc files.

A) -> set up your view relationships, etc. I set this up to work both ways to allow for various view creation.

/**
 * Implements hook_views_data().
 */
function flag_assist_views_data() {
    $data = array();

    $data['flag_assist']['table']['group'] = t('Flags Related to Nodes');
    $data['flag_assist']['table']['base'] = array(
        'title' => t('Flag Assist'),
        'help' => t('This table acts as the bridge between the data nodes and their flags.'),
    );

    $data['flag_assist']['nid'] = array(
        'title' => t('Data Node ID'),
        'help' => t('Node ID of the data record related to the Flag.'),
        'field' => array(
        	'handler' => 'views_handler_field_node',
        	'click sortable' => TRUE,
        ),
        'argument' => array(
        	'handler' => 'views_handler_argument_node_nid',
        	'numeric' => TRUE,
        	'validate type' => 'nid',
        ),
        'sort' => array(
        	'handler' => 'views_handler_sort', 
        ),
        'filter' => array(
    		'handler' => 'views_handler_filter_numeric',
    	),
    	'relationship' => array(
    		'base' => 'node',
    		'base field' => 'nid',
    		'handler' => 'views_handler_relationship', 
    		'label' => t('Node ID Related to Flag'),
    	),
    );
    
    $data['flag_assist']['fid'] = array(
        'title' => t('Flag ID of Flag'),
        'help' => t('Flag id of the Flag related to the node.'),
        'field' => array(
        	'handler' => 'views_handler_field_numeric',
        ),
    	// so that we can make this a contextual filter
    	'argument' => array(
    		'handler' => 'views_handler_argument_numeric',
    	),
        'sort' => array(
        	'handler' => 'views_handler_sort_group_by_numeric', 
        ),
        'filter' => array(
    		'handler' => 'views_handler_filter_group_by_numeric',
    	),
    	'relationship' => array(
    		'base' => 'flag',
    		'base field' => 'fid',
    		'handler' => 'views_handler_relationship', 
    		'label' => t('Flag ID Related to Node'),
    	),
    ); 
    $data['flag_assist']['name'] = array(
        'title' => t('The Name of the Flag'),
        'help' => t('The name of the Flag related to the node.'),
        'field' => array(
        	'handler' => 'views_handler_field',
        ),
        'sort' => array(
        	'handler' => 'views_handler_sort', 
        ),
        'filter' => array(
    		'handler' => 'flag_assist_handler_filter_flag_names',
    	),
    	'relationship' => array(
    		'base' => 'flag',
    		'base field' => 'name',
    		'handler' => 'views_handler_relationship', 
    		'label' => t('Flag Name Related to Node'),
    	),
    ); 
    
    // allows for reverse join from node to flag_assist table. 
	$data['flag_assist']['table']['join'] = array(
		'node' => array(
		  	'left_field' => 'nid',
		  	'field' => 'nid',
		),
	);


    return $data;
  
}  

B) This provides the filter options to views for your flags.

/**
 * Filter class which allows to filter by certain type of flags.
 */
class flag_assist_handler_filter_flag_names extends views_handler_filter_in_operator {
  // overwrite the get_value_options function.
	function get_value_options() {
		if (isset($this->value_options)) {
			return;
		}
		$this->value_options = get_flag_names('name');
	}
}

Hope this helps someone that may be seeking the same solution.

joachim’s picture

I'm afraid I don't understand what your module is doing at all.

Your flag_assist table seems to be duplicating what is in the flagging table -- the relationship between the flag and the node. That's all exposed to views too.

trentl’s picture

The flagging table, while exposed to views, requires you to add a relationship on a "per flag basis". As the initial user posted -> "A) Relationship ==== show me a relationship to all flags (not on a flag per flag type basis)"

My module acts as a lookup table and allows you to filter on one, or more flags and creates a generic relationship to all of the actual flag names without having to set up each flag as a relationship. So now I have a filter on my view (which can be exposed) so that an end user can check one, two or three flags and filter on those values in conjunction with each other. While I could do this by adding each individual flag as a relationship, I would have to return to my view each time I added a new flag and add that to the view. Now I don't have to do that. I can add a new flag and it is automatically added to my view and my exposed filter selection for that view.

While I may be missing something, I was unable to identify a way to do this with the existing module architecture. Which the initial reply to this thread stated didn't exist. Instead of hunting for hours, I made my own solution.

joachim’s picture

Your 'flag_assist' table duplicates the 'flagging' table. You have:

- primary key
- flag id
- flag name
- node ID

The 'flagging' table has:

- primary key
- flag id
- flagged entity ID

Admittedly it doesn't have the flag name, but the flag name and flag ID are in correspondence, so you can either look that up first, or do a join to {flag}.

What you have that isn't in Flag is a flag filter on the data. But that could be added to the {flagging} table itself. The data is already there, you just need a new views filter.

trentl’s picture

My approach may be incorrect, and I did try to add a new filter, but the issue was that I had to add each individual flag to my view for it to be recognized by the filter. My solution, albeit primitive and likely a bit convoluted, solved my issue, as I can add a new flag at anytime and not have to return to my view and update it to include the new flag.

I appreciate all of your contributions to this module. It's a great module and really fits my needs for end-user tagging of site content.