You are here

flag.install in Flag 7.2

Flag module install/schema/update hooks.

File

flag.install
View source
<?php

/**
 * @file
 * Flag module install/schema/update hooks.
 */

/**
 * Implements hook_install().
 */
function flag_install() {
}

/**
 * Implements hook_uninstall().
 */
function flag_uninstall() {
  $result = db_select('variable', 'v')
    ->fields('v', array(
    'name',
  ))
    ->condition('name', 'flag_%', 'LIKE')
    ->execute();
  foreach ($result as $row) {
    variable_del($row->name);
  }
  drupal_set_message(t('Flag has been uninstalled.'));
}

/**
 * Implements hook_enable().
 *
 * We create the demonstration flag on enable, so hook implementations in flag
 * module will fire correctly, as the APIs are not available on install.
 */
function flag_enable() {

  // Load the flag API in case we want to use it when enabling.
  include_once drupal_get_path('module', 'flag') . '/flag.module';
  if (!flag_get_flags()) {

    // Install a demonstration flag only if no flag exists. This is to prevent
    // a case where a disables and enables the module, and the demonstration
    // flag is overwritten or re-created.
    $flag = flag_flag::factory_by_content_type('node');
    $configuration = array(
      'name' => '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' => _flag_install_get_suggested_node_types(),
    );
    $flag
      ->form_input($configuration);
    $flag
      ->save();
  }
}

/**
 * Returns some node types to which the demonstration 'bookmarks' flag will apply.
 */
function _flag_install_get_suggested_node_types() {
  $preferred = array(
    'article',
    'story',
    'forum',
    'blog',
  );
  $existing = array_intersect($preferred, array_keys(node_type_get_types()));
  if (!$existing) {

    // As a last resort, take the first preference.
    return array(
      $preferred[0],
    );
  }
  return $existing;
}

/**
 * Implements 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'] = array(
        'title' => $t('Flag'),
        'severity' => REQUIREMENT_ERROR,
        'description' => _flag_flag_content_message(),
      );
    }
  }
  if ($phase == 'runtime') {
    if (module_exists('translation') && !module_exists('translation_helpers')) {
      $requirements['flag_translation'] = array(
        'title' => $t('Flag'),
        'severity' => REQUIREMENT_ERROR,
        'description' => $t('To have the flag module work with translations, you need to install and enable the <a href="http://drupal.org/project/translation_helpers">Translation helpers</a> module.'),
        'value' => $t('Translation helpers module not found.'),
      );
    }
    if (module_exists('session_api')) {
      if (file_exists('./robots.txt')) {
        $flag_path = url('flag') . '/';
        $robots_string = 'Disallow: ' . $flag_path;
        $contents = file_get_contents('./robots.txt');
        if (strpos($contents, $robots_string) === FALSE) {
          $requirements['flag_robots'] = array(
            'title' => $t('Flag robots.txt problem'),
            'severity' => REQUIREMENT_WARNING,
            'description' => $t('Flag module may currently be used with anonymous users, however the robots.txt file does not exclude the "@flag-path" path, which may cause search engines to randomly flag and unflag content when they index the site. It is highly recommended to add "@robots-string" to your robots.txt file (located in the root of your Drupal installation).', array(
              '@flag-path' => $flag_path,
              '@robots-string' => $robots_string,
            )),
            'value' => $t('Search engines flagging content'),
          );
        }
      }
    }
  }
  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 <em>Flag</em> module. However, you have the <em>\"Flag content\"</em> module installed, and these two modules aren't compatible (because they happen to use a database table by the same name). To install the <em>Flag</em> module, you'll first have to disable and then <a href='@uninstall-url'>uninstall</a> the <em>\"Flag content\"</em> module.", array(
    '@uninstall-url' => url('admin/modules/uninstall'),
  ));
}

/**
 * Implements hook_schema().
 */
function flag_schema() {
  $schema = array();
  $schema['flags'] = array(
    'description' => 'All available flags in the system.',
    'fields' => array(
      'fid' => array(
        'description' => 'The unique ID for this particular flag.',
        'type' => 'serial',
        'size' => 'small',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'content_type' => array(
        'description' => 'The flag type, such as one of "node", "comment", or "user".',
        'type' => 'varchar',
        'length' => '32',
        'not null' => TRUE,
        'default' => '',
      ),
      'name' => array(
        'description' => 'The machine-name for this flag.',
        'type' => 'varchar',
        'length' => '128',
        'not null' => FALSE,
        'default' => '',
      ),
      'title' => array(
        'description' => 'The human-readable title for this flag.',
        'type' => 'varchar',
        'length' => '255',
        'not null' => FALSE,
        'default' => '',
      ),
      'global' => array(
        'description' => 'Whether this flag state should act as a single toggle to all users across the site.',
        'type' => 'int',
        'size' => 'tiny',
        'not null' => FALSE,
        'default' => 0,
      ),
      'options' => array(
        'description' => 'The options and configuration of this flag.',
        'type' => 'text',
        'not null' => FALSE,
      ),
    ),
    'primary key' => array(
      'fid',
    ),
    'unique keys' => array(
      'name' => array(
        'name',
      ),
    ),
  );
  $schema['flag_content'] = array(
    'description' => 'Content that has been flagged.',
    'fields' => array(
      'fcid' => array(
        'description' => 'The unique ID for this particular tag.',
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'fid' => array(
        'description' => 'The unqiue flag ID this content has been flagged with, from {flags}.',
        'type' => 'int',
        'size' => 'small',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
      'content_type' => array(
        'description' => 'The flag type, one of "node", "comment", "user".',
        'type' => 'varchar',
        'length' => '128',
        'not null' => TRUE,
        'default' => '',
      ),
      'content_id' => array(
        'description' => 'The unique ID of the content, such as either the {cid}, {uid}, or {nid}.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
      'uid' => array(
        'description' => 'The user ID by whom this content was flagged.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
      'sid' => array(
        'description' => "The user's session id as stored in the session table.",
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
      'timestamp' => array(
        'description' => 'The UNIX time stamp representing when the flag was set.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
        'disp-size' => 11,
      ),
    ),
    'primary key' => array(
      'fcid',
    ),
    'unique keys' => array(
      'fid_content_id_uid_sid' => array(
        'fid',
        'content_id',
        'uid',
        'sid',
      ),
    ),
    'indexes' => array(
      'content_type_uid_sid' => array(
        'content_type',
        'uid',
        'sid',
      ),
      'content_type_content_id_uid_sid' => array(
        'content_type',
        'content_id',
        'uid',
        'sid',
      ),
      'content_id_fid' => array(
        'content_id',
        'fid',
      ),
    ),
  );
  $schema['flag_types'] = array(
    'description' => 'The types (usually as defined in {node_type}) that are affected by a flag.',
    'fields' => array(
      'fid' => array(
        'description' => 'The unqiue flag ID as defined for the flag in {flags}.',
        'type' => 'int',
        'size' => 'small',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
      'type' => array(
        'description' => 'The types (usually from {node_type}) that can be flagged by this fid.',
        'type' => 'varchar',
        'length' => '128',
        'not null' => TRUE,
        'default' => '',
      ),
    ),
    'indexes' => array(
      'fid' => array(
        'fid',
      ),
    ),
  );
  $schema['flag_counts'] = array(
    'description' => 'The number of times an item has been flagged.',
    'fields' => array(
      'fid' => array(
        'type' => 'int',
        'size' => 'small',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
      ),
      'content_type' => array(
        'description' => 'The flag type, usually one of "node", "comment", "user".',
        'type' => 'varchar',
        'length' => '128',
        'not null' => TRUE,
        'default' => '',
      ),
      'content_id' => array(
        'description' => 'The unique ID of the content, usually either the {cid}, {uid}, or {nid}.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
        'disp-width' => '10',
      ),
      'count' => array(
        'description' => 'The number of times this content has been flagged for this flag.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
        'disp-width' => '10',
      ),
      'last_updated' => array(
        'description' => 'The UNIX time stamp representing when the flag was last updated.',
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'default' => 0,
        'disp-size' => 11,
      ),
    ),
    'primary key' => array(
      'fid',
      'content_id',
    ),
    'indexes' => array(
      'fid_content_type' => array(
        'fid',
        'content_type',
      ),
      'content_type_content_id' => array(
        'content_type',
        'content_id',
      ),
      'fid_count' => array(
        'fid',
        'count',
      ),
      'fid_last_updated' => array(
        'fid',
        'last_updated',
      ),
    ),
  );
  return $schema;
}
function flag_update_last_removed() {
  return 6004;
}

/**
 * Convert role access to have separate "flag" and "unflag" permissions.
 */
function flag_update_6200() {
  if (db_field_exists('flags', 'roles')) {
    $result = db_select('flags', 'f')
      ->fields('f')
      ->execute();
    foreach ($result as $flag) {
      $roles = array_filter(explode(',', $flag->roles));
      $options = unserialize($flag->options);
      $options['roles'] = array(
        'flag' => $roles,
        'unflag' => $roles,
      );
      db_update('flags')
        ->fields(array(
        'options' => serialize($options),
      ))
        ->condition('fid', $flag->fid)
        ->execute();
    }
    db_drop_field('flags', 'roles');
  }
}

/**
 * Refine the indexes.
 *
 * The content type inclusion actually slowed down on unique key. And a count
 * index would be helpful for sorting by counts.
 */
function flag_update_6201() {

  // Remove "content type" from one key, see http://drupal.org/node/612602.
  db_drop_unique_key('flag_content', 'fid_content_type_content_id_uid');
  db_add_unique_key('flag_content', 'fid_content_id_uid', array(
    'fid',
    'content_id',
    'uid',
  ));

  // Add a count index, see http://drupal.org/node/489610.
  db_add_index('flag_counts', 'count', array(
    'count',
  ));
}

/**
 * Add the sid column and unique index on the flag_content table.
 */
function flag_update_6202() {

  // Drop the keys affected by the addition of the SID column.
  db_drop_unique_key('flag_content', 'fid_content_id_uid');
  db_drop_index('flag_content', 'content_type_uid');

  // Add the column.
  db_add_field('flag_content', 'sid', array(
    'type' => 'int',
    'unsigned' => TRUE,
    'not null' => TRUE,
    'default' => 0,
  ));

  // Re-add the removed keys.
  db_add_unique_key('flag_content', 'fid_content_id_uid_sid', array(
    'fid',
    'content_id',
    'uid',
    'sid',
  ));
  db_add_index('flag_content', 'content_type_uid_sid', array(
    'content_type',
    'uid',
    'sid',
  ));
}

/**
 * Remove count = 0 rows from the count tables.
 */
function flag_update_6203() {
  db_delete('flag_counts')
    ->condition('count', 0)
    ->execute();
}

/**
 * Remove "content type" from the flag_counts primary key.
 */
function flag_update_6204() {
  db_drop_primary_key('flag_counts');
  db_add_primary_key('flag_counts', array(
    'fid',
    'content_id',
  ));
}

/**
 * Provide a better index on the flag_content table including 'uid' and 'sid'.
 */
function flag_update_6205() {

  // This update has been removed and corrected in flag_update_6206.
  // See http://drupal.org/node/1105490.
}

/**
 * Correction to flag_update_6205(). Convert unique key to an index.
 */
function flag_update_6206() {

  // Remove the old index that did not include UID or SID.
  if (db_index_exists('flag_content', 'content_type_content_id')) {
    db_drop_index('flag_content', 'content_type_content_id');
  }

  // Remove the erroneous unique key that was added in flag_update_6205().
  if (db_index_exists('flag_content', 'content_type_content_id_uid_sid')) {
    db_drop_unique_key('flag_content', 'content_type_content_id_uid_sid');
  }
  db_add_index('flag_content', 'content_type_content_id_uid_sid', array(
    'content_type',
    'content_id',
    'uid',
    'sid',
  ));
}

/**
 * Adds column last_updated to flag_counts table.
 */
function flag_update_6207() {
  db_add_field('flag_counts', 'last_updated', array(
    'type' => 'int',
    'unsigned' => TRUE,
    'not null' => TRUE,
    'default' => 0,
    'disp-size' => 11,
  ), array(
    'indexes' => array(
      'last_updated' => array(
        'last_updated',
      ),
    ),
  ));
}

/**
 * Convert flag_count indexes to include FID for more efficient indexing.
 */
function flag_update_6208() {
  db_drop_index('flag_counts', 'count');
  db_drop_index('flag_counts', 'last_updated');
  db_add_index('flag_counts', 'fid_count', array(
    'fid',
    'count',
  ));
  db_add_index('flag_counts', 'fid_last_updated', array(
    'fid',
    'last_updated',
  ));
}

/**
 * Clear caches.
 */
function flag_update_7201() {

  // Do nothing. Update.php is going to clear caches for us.
}

/**
 * Clean-up flag records for deleted nodes and comments.
 */
function flag_update_7202() {

  // These queries can't use db_delete() because that doesn't support a
  // subquery: see http://drupal.org/node/1267508.
  // Clean-up for nodes.
  db_query("DELETE FROM {flag_content} WHERE content_type = 'node' AND NOT EXISTS (SELECT 1 FROM {node} n WHERE content_id = n.nid)");
  db_query("DELETE FROM {flag_counts} WHERE content_type = 'node' AND NOT EXISTS (SELECT 1 FROM {node} n WHERE content_id = n.nid)");

  // Clean-up for comments. Do not use module_exists() because comment module
  // could be disabled.
  if (db_table_exists('comment')) {
    db_query("DELETE FROM {flag_content} WHERE content_type = 'comment' AND NOT EXISTS (SELECT 1 FROM {comment} c WHERE content_id = c.cid)");
    db_query("DELETE FROM {flag_counts} WHERE content_type = 'comment' AND NOT EXISTS (SELECT 1 FROM {comment} c WHERE content_id = c.cid)");
  }
}

/**
 * Add an index to help with view's flag_handler_relationship when not required.
 */
function flag_update_7203() {

  // Skip if this index was also added by the 6.x-2.x branch.
  if (!db_index_exists('flag_content', 'content_id_fid')) {
    db_add_index('flag_content', 'content_id_fid', array(
      'content_id',
      'fid',
    ));
  }
}

/**
 * Increase the size of the database columns that refer to entity types or bundles.
 */
function flag_update_7204() {

  // Change the 'content_type' column on the {flags} table.
  db_change_field('flags', 'content_type', 'content_type', array(
    'description' => 'The flag type, such as one of "node", "comment", or "user".',
    'type' => 'varchar',
    'length' => '128',
    'not null' => TRUE,
    'default' => '',
  ));

  // Drop the indexes that use the 'content_type' column of the {flag_contents} table.
  db_drop_index('flag_content', 'content_type_content_id_uid_sid');
  db_drop_index('flag_content', 'content_type_uid_sid');

  // Change the 'content_type' column on the {flag_content} table.
  db_change_field('flag_content', 'content_type', 'content_type', array(
    'description' => 'The flag type, one of "node", "comment", "user".',
    'type' => 'varchar',
    'length' => '128',
    'not null' => TRUE,
    'default' => '',
  ));

  // Recreate the indexes which utilize the 'content_type' of the {flag_content} table
  db_add_index('flag_content', 'content_type_content_id_uid_sid', array(
    'content_type',
    'content_id',
    'uid',
    'sid',
  ));
  db_add_index('flag_content', 'content_type_uid_sid', array(
    'content_type',
    'uid',
    'sid',
  ));

  // Change the 'type' column on the {flag_types} table.
  db_change_field('flag_types', 'type', 'type', array(
    'description' => 'The types (usually from {node_type}) that can be flagged by this fid.',
    'type' => 'varchar',
    'length' => '128',
    'not null' => TRUE,
    'default' => '',
  ));

  // Drop the indexes that use the 'content_type' column of the {flag_counts} table.
  db_drop_index('flag_counts', 'fid_content_type');
  db_drop_index('flag_counts', 'content_type_content_id');

  // Change the 'content_type' column on the {flag_counts} table.
  db_change_field('flag_counts', 'content_type', 'content_type', array(
    'description' => 'The flag type, usually one of "node", "comment", "user".',
    'type' => 'varchar',
    'length' => '128',
    'not null' => TRUE,
    'default' => '',
  ));

  // Recreate the indexes which utilize the 'content_type' of the {flag_counts} table.
  db_add_index('flag_counts', 'fid_content_type', array(
    'fid',
    'content_type',
  ));
  db_add_index('flag_counts', 'content_type_content_id', array(
    'content_type',
    'content_id',
  ));
}

Functions

Namesort descending Description
flag_enable Implements hook_enable().
flag_install Implements hook_install().
flag_requirements Implements hook_requirements().
flag_schema Implements hook_schema().
flag_uninstall Implements hook_uninstall().
flag_update_6200 Convert role access to have separate "flag" and "unflag" permissions.
flag_update_6201 Refine the indexes.
flag_update_6202 Add the sid column and unique index on the flag_content table.
flag_update_6203 Remove count = 0 rows from the count tables.
flag_update_6204 Remove "content type" from the flag_counts primary key.
flag_update_6205 Provide a better index on the flag_content table including 'uid' and 'sid'.
flag_update_6206 Correction to flag_update_6205(). Convert unique key to an index.
flag_update_6207 Adds column last_updated to flag_counts table.
flag_update_6208 Convert flag_count indexes to include FID for more efficient indexing.
flag_update_7201 Clear caches.
flag_update_7202 Clean-up flag records for deleted nodes and comments.
flag_update_7203 Add an index to help with view's flag_handler_relationship when not required.
flag_update_7204 Increase the size of the database columns that refer to entity types or bundles.
flag_update_last_removed
_flag_flag_content_installed Returns TRUE if the "Flag content" module, which we aren't compatible with, is installed.
_flag_flag_content_message
_flag_install_get_suggested_node_types Returns some node types to which the demonstration 'bookmarks' flag will apply.