View source
<?php
function flag_flag_definitions() {
return array(
'node' => array(
'title' => t('Nodes'),
'description' => t("Nodes are a Drupal site's primary content."),
'handler' => 'flag_node',
),
'comment' => array(
'title' => t('Comments'),
'description' => t('Comments are responses to node content.'),
'handler' => 'flag_comment',
),
'user' => array(
'title' => t('Users'),
'description' => t('Users who have created accounts on your site.'),
'handler' => 'flag_user',
),
);
}
function flag_fetch_definition($content_type = NULL) {
static $cache;
if (!isset($cache)) {
$cache = module_invoke_all('flag_definitions');
if (!isset($cache['node'])) {
$cache += flag_flag_definitions();
}
}
if (isset($content_type)) {
if (isset($cache[$content_type])) {
return $cache[$content_type];
}
}
else {
return $cache;
}
}
function flag_get_types() {
static $types;
if (!isset($types)) {
$types = array_keys(flag_fetch_definition());
}
return $types;
}
function flag_create_handler($content_type) {
$definition = flag_fetch_definition($content_type);
if (isset($definition) && class_exists($definition['handler'])) {
$handler = new $definition['handler']();
}
else {
$handler = new flag_broken();
}
$handler->content_type = $content_type;
$handler
->construct();
return $handler;
}
class flag_flag {
var $fid = NULL;
var $content_type = NULL;
var $name = '';
var $title = '';
var $roles = array(
DRUPAL_AUTHENTICATED_RID,
);
var $global = FALSE;
var $types = array();
function factory_by_row($row) {
$flag = flag_create_handler($row->content_type);
foreach ($row as $field => $value) {
$flag->{$field} = $value;
}
unset($flag->options, $flag->type);
$options = (array) unserialize($row->options);
foreach ($options as $option => $value) {
$flag->{$option} = $value;
}
if (!empty($row->type)) {
$flag->types[] = $row->type;
}
$flag->roles = empty($row->roles) ? array() : explode(',', $row->roles);
return $flag;
}
function factory_by_array($config) {
$flag = flag_create_handler($config['content_type']);
foreach ($config as $option => $value) {
$flag->{$option} = $value;
}
if (is_array($config['locked'])) {
$flag->locked = drupal_map_assoc($config['locked']);
}
return $flag;
}
function factory_by_content_type($content_type) {
return flag_create_handler($content_type);
}
function default_options() {
return array(
'flag_short' => '',
'flag_long' => '',
'flag_message' => '',
'flag_confirmation' => '',
'unflag_short' => '',
'unflag_long' => '',
'unflag_message' => '',
'unflag_confirmation' => '',
'link_type' => 'toggle',
);
}
function options_form(&$form) {
}
function construct() {
$options = $this
->default_options();
foreach ($options as $option => $value) {
$this->{$option} = $value;
}
}
function form_input($form_values) {
foreach ($form_values as $field => $value) {
$this->{$field} = $value;
}
$this->roles = array_values(array_filter($this->roles));
$this->types = array_values(array_filter($this->types));
$this
->get_title(NULL, TRUE);
}
function validate() {
$this
->validate_name();
}
function validate_name() {
if (!preg_match('/^[a-z_][a-z0-9_]*$/', $this->name)) {
form_set_error('name', t('The flag name may only contain lowercase letters, underscores, and numbers.'));
}
if (!isset($this->fid)) {
$flag = flag_get_flag($this->name);
if (!empty($flag)) {
form_set_error('name', t('Flag names must be unique. This flag name is already in use.'));
}
}
}
function fetch_content($content_id, $object_to_remember = NULL) {
static $cache = array();
if (isset($object_to_remember)) {
$cache[$content_id] = $object_to_remember;
}
if (!array_key_exists($content_id, $cache)) {
$content = $this
->_load_content($content_id);
$cache[$content_id] = $content ? $content : NULL;
}
return $cache[$content_id];
}
function _load_content($content_id) {
return NULL;
}
function remember_content($content_id, $object) {
$this
->fetch_content($content_id, $object);
}
function applies_to_content_object($content) {
return FALSE;
}
function applies_to_content_id($content_id) {
return $this
->applies_to_content_object($this
->fetch_content($content_id));
}
function get_content_id($content) {
return NULL;
}
function uses_hook_link($teaser) {
if ($this->show_on_profile) {
return TRUE;
}
return FALSE;
}
function user_access($account = NULL) {
if (!isset($account)) {
$account = $GLOBALS['user'];
}
$matched_roles = array_intersect($this->roles, array_keys($account->roles));
return !empty($matched_roles) || empty($this->roles) || $account->uid == 1;
}
function flag($action, $content_id, $account = NULL, $skip_permission_check = FALSE) {
if (!isset($account)) {
$account = $GLOBALS['user'];
}
if (!$account) {
return FALSE;
}
if (!$account->uid) {
return FALSE;
}
if (!$skip_permission_check && !$this
->user_access($account)) {
return FALSE;
}
if (!$this
->applies_to_content_id($content_id)) {
return FALSE;
}
flag_get_counts(NULL, NULL, TRUE);
flag_get_user_flags(NULL, NULL, NULL, TRUE);
$uid = $this->global ? 0 : $account->uid;
$flagged = $this
->_is_flagged($content_id, $uid);
if ($action == 'unflag' && $flagged) {
$this
->_unflag($content_id, $uid);
module_invoke_all('flag', 'unflag', $this, $content_id, $account);
}
elseif ($action == 'flag' && !$flagged) {
$this
->_flag($content_id, $uid);
module_invoke_all('flag', 'flag', $this, $content_id, $account);
}
return TRUE;
}
function is_flagged($content_id, $uid = NULL) {
$uid = !isset($uid) ? $GLOBALS['user']->uid : $uid;
$user_flags = flag_get_user_flags($this->content_type, $content_id, $uid);
return isset($user_flags[$this->name]);
}
function _is_flagged($content_id, $uid) {
return db_result(db_query("SELECT fid FROM {flag_content} WHERE fid = %d AND uid = %d AND content_id = %d", $this->fid, $uid, $content_id));
}
function _flag($content_id, $uid) {
db_query("INSERT INTO {flag_content} (fid, content_type, content_id, uid, timestamp) VALUES (%d, '%s', %d, %d, %d)", $this->fid, $this->content_type, $content_id, $uid, time());
$this
->_update_count($content_id);
}
function _unflag($content_id, $uid) {
db_query("DELETE FROM {flag_content} WHERE fid = %d AND uid = %d AND content_id = %d", $this->fid, $uid, $content_id);
$this
->_update_count($content_id);
}
function _update_count($content_id) {
$count = db_result(db_query("SELECT COUNT(*) FROM {flag_content} WHERE fid = %d AND content_id = %d", $this->fid, $content_id));
$result = db_query("UPDATE {flag_counts} SET count = %d WHERE fid = %d AND content_id = %d", $count, $this->fid, $content_id);
if (!db_affected_rows()) {
db_query("INSERT INTO {flag_counts} (fid, content_type, content_id, count) VALUES (%d, '%s', %d, %d)", $this->fid, $this->content_type, $content_id, $count);
}
}
function get_count($content_id) {
$counts = flag_get_counts($this->content_type, $content_id);
return isset($counts[$this->name]) ? $counts[$this->name] : 0;
}
function get_user_count($uid) {
return db_result(db_query('SELECT COUNT(*) FROM {flag_content} WHERE fid = %d AND uid = %d', $this->fid, $uid));
}
function get_label($label, $content_id = NULL) {
if (!isset($this->{$label})) {
return;
}
$label = t($this->{$label});
if (strpos($label, '[') !== FALSE && module_exists('token')) {
$label = $this
->replace_tokens($label, array(
'global' => NULL,
), $content_id);
}
return filter_xss_admin($label);
}
function replace_tokens($label, $contexts, $content_id) {
return token_replace_multiple($label, $contexts);
}
function get_labels_token_types() {
return array(
'global',
);
}
function get_title($content_id = NULL, $reset = FALSE) {
static $titles = array();
if ($reset) {
$titles = array();
}
$slot = intval($content_id);
if (!isset($titles[$this->fid][$slot])) {
$titles[$this->fid][$slot] = $this
->get_label('title', $content_id);
}
return $titles[$this->fid][$slot];
}
function get_flag_action($content_id) {
$flag_action = new stdClass();
$flag_action->flag = $this->name;
$flag_action->content_type = $this->content_type;
$flag_action->content_id = $content_id;
return $flag_action;
}
function get_valid_actions() {
$actions = module_invoke_all('action_info');
foreach ($actions as $callback => $action) {
if ($action['type'] != $this->content_type && !isset($action['hooks'][$this->content_type])) {
unset($actions[$callback]);
}
}
return $actions;
}
function get_relevant_action_objects($content_id) {
return array();
}
function rules_get_event_arguments_definition() {
return array();
}
function rules_get_element_argument_definition() {
return array();
}
function get_views_info() {
return array();
}
function applies_to_content_id_array($content_ids) {
return array();
}
function save() {
if (isset($this->fid)) {
$this
->update();
}
else {
$this
->insert();
}
}
function update() {
db_query("UPDATE {flags} SET name = '%s', title = '%s', roles = '%s', global = %d, options = '%s' WHERE fid = %d", $this->name, $this->title, implode(',', $this->roles), $this->global, $this
->get_serialized_options(), $this->fid);
db_query("DELETE FROM {flag_types} WHERE fid = %d", $this->fid);
foreach ($this->types as $type) {
db_query("INSERT INTO {flag_types} (fid, type) VALUES (%d, '%s')", $this->fid, $type);
}
}
function insert() {
if (function_exists('db_last_insert_id')) {
db_query("INSERT INTO {flags} (content_type, name, title, roles, global, options) VALUES ('%s', '%s', '%s', '%s', %d, '%s')", $this->content_type, $this->name, $this->title, implode(',', $this->roles), $this->global, $this
->get_serialized_options());
$this->fid = db_last_insert_id('flags', 'fid');
}
else {
$this->fid = db_next_id('{flags}_fid');
db_query("INSERT INTO {flags} (fid, content_type, name, title, roles, global, options) VALUES (%d, '%s', '%s', '%s', '%s', %d, '%s')", $this->fid, $this->content_type, $this->name, $this->title, implode(',', $this->roles), $this->global, $this
->get_serialized_options());
}
foreach ($this->types as $type) {
db_query("INSERT INTO {flag_types} (fid, type) VALUES (%d, '%s')", $this->fid, $type);
}
}
function get_serialized_options() {
$option_names = array_keys($this
->default_options());
$options = array();
foreach ($option_names as $option) {
$options[$option] = $this->{$option};
}
return serialize($options);
}
function delete() {
db_query('DELETE FROM {flags} WHERE fid = %d', $this->fid);
db_query('DELETE FROM {flag_content} WHERE fid = %d', $this->fid);
db_query('DELETE FROM {flag_types} WHERE fid = %d', $this->fid);
db_query('DELETE FROM {flag_counts} WHERE fid = %d', $this->fid);
}
function disable() {
if (isset($this->module)) {
$flag_status = variable_get('flag_default_flag_status', array());
$flag_status[$this->name] = FALSE;
variable_set('flag_default_flag_status', $flag_status);
}
}
function enable() {
if (isset($this->module)) {
$flag_status = variable_get('flag_default_flag_status', array());
$flag_status[$this->name] = TRUE;
variable_set('flag_default_flag_status', $flag_status);
}
}
function theme($action, $content_id, $after_flagging = FALSE) {
if (!_flag_is_drupal_5()) {
return theme($this
->theme_suggestions(), $this, $action, $content_id, $after_flagging);
}
else {
return theme('flag', $this, $action, $content_id, $after_flagging);
}
}
function theme_suggestions() {
$suggestions = array();
$suggestions[] = 'flag__' . $this->name;
$suggestions[] = 'flag';
return $suggestions;
}
}
class flag_node extends flag_flag {
function default_options() {
$options = parent::default_options();
$options += array(
'show_on_page' => TRUE,
'show_on_teaser' => TRUE,
'show_on_form' => FALSE,
'i18n' => 0,
);
return $options;
}
function options_form(&$form) {
parent::options_form($form);
$form['i18n'] = array(
'#type' => 'radios',
'#title' => t('Internationalization'),
'#options' => array(
'1' => t('Flag translations of content as a group'),
'0' => t('Flag each translation of content separately'),
),
'#default_value' => $this->i18n,
'#description' => t('Flagging translations as a group effectively allows users to flag the original piece of content regardless of the translation they are viewing. Changing this setting will <strong>not</strong> update content that has been flagged already.'),
'#access' => module_exists('translation_helpers'),
'#weight' => 5,
);
$form['display']['show_on_teaser'] = array(
'#type' => 'checkbox',
'#title' => t('Display link on node teaser'),
'#default_value' => $this->show_on_teaser,
'#access' => empty($this->locked['show_on_teaser']),
);
$form['display']['show_on_page'] = array(
'#type' => 'checkbox',
'#title' => t('Display link on node page'),
'#default_value' => $this->show_on_page,
'#access' => empty($this->locked['show_on_page']),
);
$form['display']['show_on_form'] = array(
'#type' => 'checkbox',
'#title' => t('Display checkbox on node edit form'),
'#default_value' => $this->show_on_form,
'#description' => t('If you elect to have a checkbox on the node edit form, you may specify its initial state in the settings form <a href="@content-types-url">for each content type</a>.', array(
'@content-types-url' => url('admin/content/types'),
)),
'#access' => empty($this->locked['show_on_form']),
);
}
function _load_content($content_id) {
return is_numeric($content_id) ? node_load($content_id) : NULL;
}
function applies_to_content_object($node) {
if ($node && in_array($node->type, $this->types)) {
return TRUE;
}
return FALSE;
}
function get_content_id($node) {
return $node->nid;
}
function get_translation_id($content_id) {
if ($this->i18n) {
$node = $this
->fetch_content($content_id);
if (!empty($node->tnid)) {
$content_id = $node->tnid;
}
}
return $content_id;
}
function uses_hook_link($teaser) {
if ($teaser && $this->show_on_teaser || !$teaser && $this->show_on_page) {
return TRUE;
}
return FALSE;
}
function flag($action, $content_id, $account = NULL, $skip_permission_check = FALSE) {
$content_id = $this
->get_translation_id($content_id);
return parent::flag($action, $content_id, $account, $skip_permission_check);
}
function is_flagged($content_id, $uid = NULL) {
$content_id = $this
->get_translation_id($content_id);
return parent::is_flagged($content_id, $uid);
}
function get_labels_token_types() {
return array(
'node',
);
}
function replace_tokens($label, $contexts, $content_id) {
if ($content_id && ($node = $this
->fetch_content($content_id))) {
$contexts['node'] = $node;
}
return parent::replace_tokens($label, $contexts, $content_id);
}
function get_flag_action($content_id) {
$flag_action = parent::get_flag_action($content_id);
$node = $this
->fetch_content($content_id);
$flag_action->content_title = $node->title;
$flag_action->content_url = _flag_url('node/' . $node->nid);
return $flag_action;
}
function get_valid_actions() {
$actions = module_invoke_all('action_info');
foreach ($actions as $callback => $action) {
if ($action['type'] != 'node' && !isset($action['hooks']['nodeapi'])) {
unset($actions[$callback]);
}
}
return $actions;
}
function get_relevant_action_objects($content_id) {
return array(
'node' => $this
->fetch_content($content_id),
);
}
function rules_get_event_arguments_definition() {
return array(
'node' => array(
'type' => 'node',
'label' => t('flagged content'),
'handler' => 'flag_rules_get_event_argument',
),
);
}
function rules_get_element_argument_definition() {
return array(
'type' => 'node',
'label' => t('Flagged content'),
);
}
function get_views_info() {
return array(
'views table' => 'node',
'join field' => 'nid',
'title field' => 'title',
'title' => t('Node flag'),
'help' => t('Limit results to only those nodes flagged by a certain flag; Or display information about the flag set on a node.'),
'counter title' => t('Node flag counter'),
'counter help' => t('Include this to gain access to the flag counter field.'),
);
}
function applies_to_content_id_array($content_ids) {
$passed = array();
$content_ids = implode(',', array_map('intval', $content_ids));
$placeholders = implode(',', array_fill(0, sizeof($this->types), "'%s'"));
$result = db_query("SELECT nid FROM {node} WHERE nid IN ({$content_ids}) AND type in ({$placeholders})", $this->types);
while ($row = db_fetch_object($result)) {
$passed[$row->nid] = TRUE;
}
return $passed;
}
}
class flag_comment extends flag_flag {
function default_options() {
$options = parent::default_options();
$options += array(
'show_on_comment' => TRUE,
);
return $options;
}
function options_form(&$form) {
parent::options_form($form);
$form['display']['show_on_comment'] = array(
'#type' => 'checkbox',
'#title' => t('Display link under comment'),
'#default_value' => $this->show_on_comment,
'#access' => empty($this->locked['show_on_comment']),
);
}
function _load_content($content_id) {
return _comment_load($content_id);
}
function applies_to_content_object($comment) {
if ($comment && ($node = node_load($comment->nid)) && in_array($node->type, $this->types)) {
return TRUE;
}
return FALSE;
}
function get_content_id($comment) {
return $comment->cid;
}
function uses_hook_link($teaser) {
return $this->show_on_comment;
}
function get_labels_token_types() {
return array(
'comment',
'node',
);
}
function replace_tokens($label, $contexts, $content_id) {
if ($content_id) {
if (($comment = $this
->fetch_content($content_id)) && ($node = node_load($comment->nid))) {
$contexts['node'] = $node;
$contexts['comment'] = $comment;
}
}
return parent::replace_tokens($label, $contexts, $content_id);
}
function get_flag_action($content_id) {
$flag_action = parent::get_flag_action($content_id);
$comment = $this
->fetch_content($content_id);
$flag_action->content_title = $comment->subject;
$flag_action->content_url = _flag_url("node/{$comment->nid}/{$comment->cid}", "comment-{$comment->cid}");
return $flag_action;
}
function get_relevant_action_objects($content_id) {
$comment = $this
->fetch_content($content_id);
return array(
'comment' => $comment,
'node' => node_load($comment->nid),
);
}
function rules_get_event_arguments_definition() {
return array(
'comment' => array(
'type' => 'comment',
'label' => t('flagged comment'),
'handler' => 'flag_rules_get_event_argument',
),
'node' => array(
'type' => 'node',
'label' => t("the flagged comment's content"),
'handler' => 'flag_rules_get_comment_content',
),
);
}
function rules_get_element_argument_definition() {
return array(
'type' => 'comment',
'label' => t('Flagged comment'),
);
}
function get_views_info() {
return array(
'views table' => 'comments',
'join field' => 'cid',
'title field' => 'subject',
'title' => t('Comment flag'),
'help' => t('Limit results to only those comments flagged by a certain flag; Or display information about the flag set on a comment.'),
'counter title' => t('Comment flag counter'),
'counter help' => t('Include this to gain access to the flag counter field.'),
);
}
function applies_to_content_id_array($content_ids) {
$passed = array();
$content_ids = implode(',', array_map('intval', $content_ids));
$placeholders = implode(',', array_fill(0, sizeof($this->types), "'%s'"));
$result = db_query("SELECT cid FROM {comments} c INNER JOIN {node} n ON c.nid = n.nid WHERE cid IN ({$content_ids}) and n.type IN ({$placeholders})", $this->types);
while ($row = db_fetch_object($result)) {
$passed[$row->cid] = TRUE;
}
return $passed;
}
}
class flag_user extends flag_flag {
function default_options() {
$options = parent::default_options();
$options += array(
'show_on_profile' => TRUE,
);
return $options;
}
function options_form(&$form) {
parent::options_form($form);
$form['types'] = array(
'#type' => 'value',
'#value' => array(
0 => 0,
),
);
$form['display']['show_on_profile'] = array(
'#type' => 'checkbox',
'#title' => t('Display link on user profile page'),
'#default_value' => $this->show_on_profile,
'#access' => empty($this->locked['show_on_profile']),
);
}
function _load_content($content_id) {
return user_load(array(
'uid' => $content_id,
));
}
function applies_to_content_object($user) {
if ($user) {
return TRUE;
}
return FALSE;
}
function get_content_id($user) {
return $user->uid;
}
function uses_hook_link($teaser) {
if ($this->show_on_profile) {
return TRUE;
}
return FALSE;
}
function get_labels_token_types() {
return array(
'user',
);
}
function replace_tokens($label, $contexts, $content_id) {
if ($content_id && ($user = $this
->fetch_content($content_id))) {
$contexts['user'] = $user;
}
return parent::replace_tokens($label, $contexts, $content_id);
}
function get_flag_action($content_id) {
$flag_action = parent::get_flag_action($content_id);
$user = $this
->fetch_content($content_id);
$flag_action->content_title = $user->name;
$flag_action->content_url = _flag_url('user/' . $user->uid);
return $flag_action;
}
function get_relevant_action_objects($content_id) {
return array(
'user' => $this
->fetch_content($content_id),
);
}
function rules_get_event_arguments_definition() {
return array(
'account' => array(
'type' => 'user',
'label' => t('flagged user'),
'handler' => 'flag_rules_get_event_argument',
),
);
}
function rules_get_element_argument_definition() {
return array(
'type' => 'user',
'label' => t('Flagged user'),
);
}
function get_views_info() {
return array(
'views table' => 'users',
'join field' => 'uid',
'title field' => 'name',
'title' => t('User flag'),
'help' => t('Limit results to only those users flagged by a certain flag; Or display information about the flag set on a user.'),
'counter title' => t('User flag counter'),
'counter help' => t('Include this to gain access to the flag counter field.'),
);
}
function applies_to_content_id_array($content_ids) {
$passed = array();
foreach ($content_ids as $uid) {
if ($uid) {
$passed[$uid] = TRUE;
}
}
return $passed;
}
}
class flag_broken extends flag_flag {
function options_form(&$form) {
$form = array();
$form['error'] = array(
'#value' => '<div class="error">' . t("The module providing this flag wasn't found, or this flag type, %type, isn't valid.", array(
'%type' => $this->content_type,
)) . '</div>',
);
}
}
function _flag_is_drupal_5() {
return !function_exists('theme_get_registry');
}
function _flag_url($path, $fragment = NULL, $absolute = TRUE) {
return _flag_is_drupal_5() ? url($path, NULL, $fragment, $absolute) : url($path, array(
'absolute' => TRUE,
'fragment' => $fragment,
));
}