'bookmarks',
'global' => 0,
'show_on_page' => 1,
'show_on_teaser' => 1,
'show_on_form' => 1,
// The following UI labels aren't wrapped in t() because they are written
// to the DB in English. They are passed to t() later, thus allowing for
// multilingual sites.
'title' => 'Bookmarks',
'flag_short' => 'Bookmark this',
'flag_long' => 'Add this post to your bookmarks',
'flag_message' => 'This post has been added to your bookmarks',
'unflag_short' => 'Unbookmark this',
'unflag_long' => 'Remove this post from your bookmarks',
'unflag_message' => 'This post has been removed from your bookmarks',
'types' => array('story', 'forum', 'blog'),
);
$flag->form_input($configuration);
$flag->save();
}
if ($success) {
drupal_set_message(st('Flag module installed tables successfully.'));
}
else {
drupal_set_message(st('The installation of Flag module failed.'), 'error');
}
}
/**
* Implementation of hook_uninstall().
*/
function flag_uninstall() {
drupal_uninstall_schema('flag');
$result = db_query("SELECT name FROM {variable} WHERE name LIKE 'flag_%'");
while ($row = db_fetch_object($result)) {
variable_del($row->name);
}
drupal_set_message(t('Flag has been uninstalled.'));
}
/**
* Implementation of hook_requirements().
*
* Prevent installing this module if the "Flag content" module is installed as well.
*/
function flag_requirements($phase) {
$requirements = array();
$t = get_t();
if ($phase == 'install') {
if (!defined('MAINTENANCE_MODE') && _flag_flag_content_installed()) {
$requirements['flag_content_clash']['title'] = $t('Flag');
$requirements['flag_content_clash']['severity'] = REQUIREMENT_ERROR;
$requirements['flag_content_clash']['description'] = _flag_flag_content_message();
}
}
if ($phase == 'runtime' && module_exists('translation') && !module_exists('translation_helpers')) {
$requirements['flag_translation']['title'] = $t('Flag');
$requirements['flag_translation']['severity'] = REQUIREMENT_ERROR;
$requirements['flag_translation']['description'] = $t('To have the flag module work with translations, you need to install and enable the Translation helpers module.');
$requirements['flag_translation']['value'] = $t('Translation helpers module not found.');
}
return $requirements;
}
/**
* Returns TRUE if the "Flag content" module, which we aren't compatible with,
* is installed.
*/
function _flag_flag_content_installed() {
$version = @drupal_get_installed_schema_version('flag_content', TRUE);
return (isset($version) && $version != SCHEMA_UNINSTALLED);
}
function _flag_flag_content_message() {
$t = get_t();
return $t("You are trying to install the Flag module. However, you have the \"Flag content\" module installed, and these two modules aren't compatible (because they happen to use a database table by the same name). To install the Flag module, you'll first have to disable and then uninstall the \"Flag content\" module.", array('@uninstall-url' => url('admin/build/modules/uninstall')));
}
/**
* Implementation of hook_schema().
*/
function flag_schema() {
$schema = array();
$schema['flags'] = array(
'fields' => array(
'fid' => array(
'type' => 'serial',
'size' => 'small',
'unsigned' => TRUE,
'not null' => TRUE,
),
'content_type' => array(
'type' => 'varchar',
'length' => '32',
'not null' => TRUE,
'default' => '',
),
'name' => array(
'type' => 'varchar',
'length' => '32',
'not null' => FALSE,
'default' => '',
),
'title' => array(
'type' => 'varchar',
'length' => '255',
'not null' => FALSE,
'default' => '',
),
'roles' => array(
'type' => 'varchar',
'length' => '255',
'not null' => FALSE,
'default' => '',
),
'global' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => FALSE,
'default' => 0,
),
'options' => array(
'type' => 'text',
'not null' => FALSE,
),
),
'primary key' => array('fid'),
'unique keys' => array(
'name' => array('name'),
),
);
$schema['flag_content'] = array(
'fields' => array(
'fcid' => array(
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
'fid' => array(
'type' => 'int',
'size' => 'small',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'content_type' => array(
'type' => 'varchar',
'length' => '32',
'not null' => TRUE,
'default' => '',
),
'content_id' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'uid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'timestamp' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'disp-size' => 11,
)
),
'primary key' => array('fcid'),
'unique keys' => array(
'fid_content_type_content_id_uid' => array('fid', 'content_type', 'content_id', 'uid'),
),
'indexes' => array(
'content_type_content_id' => array('content_type', 'content_id'),
'content_type_uid' => array('content_type', 'uid'),
),
);
$schema['flag_types'] = array(
'fields' => array(
'fid' => array(
'type' => 'int',
'size' => 'small',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'type' => array(
'type' => 'varchar',
'length' => '32',
'not null' => TRUE,
'default' => '')
),
'indexes' => array(
'fid' => array('fid'),
),
);
$schema['flag_counts'] = array(
'fields' => array(
'fid' => array(
'type' => 'int',
'size' => 'small',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'content_type' => array(
'type' => 'varchar',
'length' => '32',
'not null' => TRUE,
'default' => '',
),
'content_id' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'disp-width' => '10',
),
'count' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'disp-width' => '10',
)
),
'primary key' => array('fid', 'content_type', 'content_id'),
'indexes' => array(
'fid_content_type' => array('fid', 'content_type'),
'content_type_content_id' => array('content_type', 'content_id'),
),
);
return $schema;
}
/**
* Add auto-increment to the flags.fid column for users upgrading from Drupal 5.
*
* Delete obsolete actions provided by beta3.
*
* Note: To ease maintenance, this code is compatible with both D5 and D6.
*
* Check out #305391 for a discussion about this code.
*/
function flag_update_6000() {
$ret = array();
// Convert the flags.fid column to auto-increment.
db_drop_primary_key($ret, 'flags');
db_change_field($ret, 'flags', 'fid', 'fid', array(
'type' => 'serial',
'size' => 'small',
'unsigned' => TRUE,
'not null' => TRUE,
), array('primary key' => array('fid')));
// This conditional ensures we have Actions 2.x, not Actions 1.x.
//
// At the beginning we had only db_table_exists() checks here. However, it
// turned out that db_table_exists() fails when the $db_prefix string contains
// a dot. So module_exists() and function_exists() are added, as backup.
if (module_exists('trigger') || function_exists('_actions_get_hook_aids') || db_table_exists('actions_assignments') || db_table_exists('trigger_assignments')) {
// Step 1: Find all actions we need to delete.
$aids = array();
// We can't just search for "actions of type flag" because this isn't future-compatible.
$res = db_query("SELECT aid FROM {actions} WHERE callback IN ('flag_action_email', 'flag_action_delete', 'flag_action_unpublish', 'flag_action_moderate')");
while ($row = db_fetch_object($res)) {
$aids[] = $row->aid;
}
if (!$aids) {
$ret[] = array(
'success' => TRUE,
'query' => t('No old actions to remove.'),
);
}
else {
$ret[] = array(
'success' => TRUE,
'query' => t('Deleting the following actions: @aids', array('@aids' => implode(', ', $aids))),
);
}
// Step 2: Delete them through API.
// We can't do `if (module_exists('actions'))`: this code should work for D6 as
// well, and it doesn't have an Actions module.
if (function_exists('actions_delete')) {
foreach ($aids as $aid) {
actions_delete($aid);
$ret[] = array(
'success' => TRUE,
'query' => t('actions_delete("@aid") called.', array('@aid' => $aid)),
);
}
}
// Step 3: Delete them through SQL, in case Actions/Trigger aren't enabled.
foreach ($aids as $aid) {
foreach (array('actions', 'actions_assignments', 'trigger_assignments') as $table) {
if (db_table_exists($table)) {
$ret[] = _flag_update_sql("DELETE FROM {{$table}} WHERE aid = '%s'", $aid);
}
}
}
// Note: No need to delete from the {actions_aid} table; Actions doesn't do that.
// Step 4: Remove a bogus record possibly created because of a bug (see
// http://drupal.org/node/271460).
foreach (array('actions_assignments', 'trigger_assignments') as $table) {
if (db_table_exists($table)) {
$ret[] = _flag_update_sql("DELETE FROM {{$table}} WHERE hook = 'flag' AND aid = ''");
}
}
}
else {
$ret[] = array(
'success' => TRUE,
'query' => t('Cleanup of Actions tables is unneeded.'),
);
}
return $ret;
}
/**
* Move flag messages and link titles into the options array.
*/
function flag_update_6001() {
$ret = array();
if (_flag_column_exists('flags', 'flag_short')) {
$result = db_query("SELECT * FROM {flags}");
while ($flag = db_fetch_object($result)) {
$options = unserialize($flag->options);
$options['flag_short'] = $flag->flag_short;
$options['flag_long'] = $flag->flag_long;
$options['flag_message'] = $flag->flag_message;
$options['unflag_short'] = $flag->unflag_short;
$options['unflag_long'] = $flag->unflag_long;
$options['unflag_message'] = $flag->unflag_message;
db_query("UPDATE {flags} SET options = '%s' WHERE fid = %d", serialize($options), $flag->fid);
}
db_drop_field($ret, 'flags', 'flag_short');
db_drop_field($ret, 'flags', 'flag_long');
db_drop_field($ret, 'flags', 'flag_message');
db_drop_field($ret, 'flags', 'unflag_short');
db_drop_field($ret, 'flags', 'unflag_long');
db_drop_field($ret, 'flags', 'unflag_message');
}
return $ret;
}
/**
* Add a 'serial' primary key, fcid, to the flag_content table.
*/
function flag_update_6002() {
$ret = array();
if (!_flag_column_exists('flag_content', 'fcid')) {
db_drop_primary_key($ret, 'flag_content');
db_add_field($ret, 'flag_content', 'fcid', array(
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
), array(
'primary key' => array('fcid'),
)
);
db_add_unique_key($ret, 'flag_content', 'fid_content_type_content_id_uid', array('fid', 'content_type', 'content_id', 'uid'));
}
return $ret;
}
/**
* Remove the previous default views that are no longer bundled with Flag.
*
* These views are saved to the database so that they are preserved.
*/
function flag_update_6003() {
$ret = array();
// Bail out if Views doesn't exist.
if (!function_exists('views_get_view')) {
return $ret;
}
drupal_load('module', 'flag');
$flags = flag_get_flags();
foreach ($flags as $name => $flag) {
if ($view = views_get_view('flags_'. $name)) {
if (!$view->disabled && $view->type == t('Default')) {
$view->save();
$ret[] = array('success' => TRUE, 'query' => t('The view %name as been saved to the database. Flag no longer provides this view by default.', array('%name' => $view->name)));
}
}
}
return $ret;
}
/**
* Add auto-increment to the flags.fid column for users upgrading from Drupal 5.
*/
function flag_update_6004() {
// Update removed and included in flag_update_6000()
return array();
}
/**
* Remove count = 0 rows from the flag_counts table for consistency.
*/
function flag_update_6005() {
$ret = array();
$ret[] = update_sql("DELETE FROM {flag_counts} WHERE count = 0");
return $ret;
}
// This is a replacement for update_sql(). The latter doesn't support placeholders.
function _flag_update_sql($sql) {
$args = func_get_args();
array_shift($args);
$result = db_query($sql, $args);
// Users are going to see '%s' and '%d' in the report and they're going to
// think there's a bug. So lets replace the placeholders with something less
// suspicious.
$sql = strtr($sql, array('%s' => '***', '%d' => '***'));
return array('success' => $result !== FALSE, 'query' => check_plain($sql));
}
// D5/6 compatible version of db_column_exists().
function _flag_column_exists($table, $column) {
if (function_exists('db_column_exists')) {
return db_column_exists($table, $column);
}
switch ($GLOBALS['db_type']) {
case 'mysql':
case 'mysqli':
return (bool) db_fetch_object(db_query("SHOW COLUMNS FROM {flags} LIKE 'flag_short'"));
case 'pgsql':
return (bool) db_result(db_query("SELECT COUNT(pg_attribute.attname) FROM pg_class, pg_attribute WHERE pg_attribute.attrelid = pg_class.oid AND pg_class.relname = '{". db_escape_table($table) ."}' AND attname = '". db_escape_table($column) ."'"));
}
}