You are here

bootstrap_tour.install in Bootstrap Tour 7.2

Same filename and directory in other branches
  1. 7 bootstrap_tour.install

File

bootstrap_tour.install
View source
<?php

/**
 * Implements hook_install().
 */
function bootstrap_tour_install() {
  module_load_include('inc', 'inline_entity_form', 'includes/entity.inline_entity_form');
  module_load_include('inc', 'bootstrap_tour', 'includes/bootstrap_tour.controller');
  bootstrap_tour_setup_step_field();
}

/**
 * Implements hook_uninstall().
 */
function bootstrap_tour_uninstall() {
  field_attach_delete_bundle('bootstrap_tour', 'bootstrap_tour');
}

/**
 * Upgrade old 1.x tours to the new 2.x Entity format, then delete the old DB table.
 */
function bootstrap_tour_update_7200() {
  module_load_include('inc', 'inline_entity_form', 'includes/entity.inline_entity_form');
  module_load_include('inc', 'bootstrap_tour', 'includes/bootstrap_tour.controller');
  if (!module_exists('inline_entity_form') && !module_enable(array(
    'inline_entity_form',
  ))) {

    // If you drop in 2.x and try to run updates, Drupal won't complain even though
    // 2.x has a hard dependency on Inline Entity Form. So, we check for that explicitly.
    throw new DrupalUpdateException(t('Bootstrap Tour 2.x requires the Inline Entity Form module which is not installed.'));
    return;
  }

  // Rename bootstrap_tour table so doesn't conflict
  // @see bootstrap_tour_schema().
  if (db_table_exists('bootstrap_tour')) {
    db_rename_table('bootstrap_tour', 'bootstrap_tour_old');
    drupal_get_complete_schema(TRUE);

    // Make sure relavent caches are clear
    cache_clear_all('features_api', 'cache');
    cache_clear_all('entity_info', 'cache', TRUE);
    drupal_static_reset('entity_get_info');
    drupal_static_reset('features_get_components');
    drupal_static_reset('features_get_components_by_key');
  }

  // First we need to create the two new tables.
  db_create_table('bootstrap_tour_tour', bootstrap_tour_db_tour_table());
  db_create_table('bootstrap_tour_step', bootstrap_tour_db_step_table());
  bootstrap_tour_setup_step_field();

  // Now we need to load all of the 1.x tours and re-save them as 2.x entities.
  $old_tours = bootstrap_tour_load_legacy_tours();
  foreach ($old_tours as $tour) {
    $tour = (array) $tour;
    $steps = $tour['steps'];
    unset($tour['steps']);

    // Steps are their own entities now so we need to save them as such.
    foreach ($steps as $index => $step) {
      $new_step = entity_create('bootstrap_tour_step', array(
        'path' => isset($step['path']) ? $step['path'] : '',
        'selector' => $step['selector'],
        'placement' => $step['placement'],
        'title' => $step['title'],
        'content' => $step['content'],
        'content_text_format' => $step['format'],
      ));
      $new_step
        ->save();
      if (!empty($new_step->bootstrap_tour_step_id)) {
        $tour['bootstrap_tour_step_reference'][LANGUAGE_NONE][$index]['target_id'] = $new_step->bootstrap_tour_step_id;
      }
    }
    $entity = entity_create('bootstrap_tour', $tour);
    $entity->old_tour = $tour;
    $entity
      ->save();
  }

  // Now we need to make sure the numbers of old vs. new match so that we can be
  // sure the upgrade went successfully. If so, we can delete the old DB table.
  $new_tours = entity_load('bootstrap_tour');
  if ($count = count($old_tours)) {
    if (count($new_tours) === $count) {
      db_drop_table('bootstrap_tour_old');
      return t('If you have any Tours in exported Features, you will have to recreate them now.');
    }
    else {
      throw new DrupalUpdateException(t('Bootstrap Tour failed to upgrade old tours to the new format.'));
    }
  }
}

/**
 * Remove orphaned steps.
 */
function bootstrap_tour_update_7201() {
  $subquery = ' NOT in (SELECT bootstrap_tour_step_reference_target_id FROM {field_revision_bootstrap_tour_step_reference})';
  foreach (array_keys(field_info_instances('bootstrap_tour_step', 'bootstrap_tour_step')) as $field_name) {
    db_query("DELETE from {field_data_" . $field_name . "} WHERE entity_type = 'bootstrap_tour_step' AND entity_id " . $subquery);
    db_query("DELETE from {field_revision_" . $field_name . "} WHERE entity_type = 'bootstrap_tour_step' AND entity_id " . $subquery);
  }
  db_query('DELETE from {bootstrap_tour_step} WHERE bootstrap_tour_step_id ' . $subquery);
}

/**
 * Implements hook_schema().
 */
function bootstrap_tour_schema() {
  $schema = array();
  if (db_table_exists('bootstrap_tour_old')) {

    /**
     * Legacy compatibility. If the 'bootstrap_tour' table exists, then we need
     * to keep it temporarily, so that we can migrate from it to the new
     * 'bootstrap_tour_tour' and 'bootstrap_tour_step' tables. Once that
     * migration is complete, the update hook will delete this table, and then
     * it will be gone forever.
     *
     * You may be saying "why not remove this from hook_schema() though, since
     * that won't delete the table if it already exists?" and you're a very
     * smart and wise person. The answer is that we need to keep this in
     * hook_schema() because we need the "export" key to exist on it (which you
     * can see below), otherwise the ctools function to load default/featurized/
     * exported/in-code tours doesn't know that they exist and just returns NULL.
     * And since we need to load legacy 1.x tours as part of the migrating to
     * the new 2.x tables, we need ctools to know about it until that migration
     * is complete.
     *
     * However, we can't actually name it bootstrap_tour because then
     * features makes a boostrap_tour_features_api function that returns
     * it as a key, which conflicts with the one entity creates and causes
     * update errors.
     *
     * @see bootstrap_tour_load_legacy_tours();
     */
    $schema['bootstrap_tour_old'] = bootstrap_tour_db_legacy_table();
  }
  $schema['bootstrap_tour_tour'] = bootstrap_tour_db_tour_table();
  $schema['bootstrap_tour_step'] = bootstrap_tour_db_step_table();
  return $schema;
}

/**
 * Returns the table definition for the table which holds the tours.
 *
 * @return array
 */
function bootstrap_tour_db_tour_table() {
  return array(
    'description' => t('Bootstrap tours courtesy of the Bootstrap Tours module'),
    'fields' => array(
      'bootstrap_tour_id' => array(
        'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'no export' => TRUE,
      ),
      'title' => array(
        'description' => 'Human readable name for the tour used for administrative purposes.',
        'type' => 'varchar',
        'length' => '255',
      ),
      'name' => array(
        'description' => 'Unique ID for tours used to identify them programmatically, generated from the name.',
        'type' => 'varchar',
        'length' => '255',
      ),
      'description' => array(
        'description' => 'A description of the site tour, used for administrative purposes.',
        'type' => 'varchar',
        'length' => '255',
      ),
      'roles' => array(
        'description' => 'A comma separated list of roles that can access this tour.',
        'type' => 'varchar',
        'length' => '255',
      ),
      'autorun' => array(
        'description' => 'Boolean indicating whether the tour should automatically start when the start path is visited.',
        'type' => 'int',
        'not null' => TRUE,
        'default' => 1,
      ),
      'start_path' => array(
        'description' => 'The path at which the tour should begin.',
        'type' => 'varchar',
        'length' => '255',
      ),
      'enabled' => array(
        'description' => 'Boolean indicating whether the tour is enabled or disabled.',
        'type' => 'int',
        'not null' => TRUE,
        'default' => 1,
      ),
    ) + entity_exportable_schema_fields(),
    'primary key' => array(
      'bootstrap_tour_id',
    ),
    'unique keys' => array(
      'name' => array(
        'name',
      ),
    ),
  );
}

/**
 * Returns the table definition for the table which holds the tour steps.
 *
 * @return array
 */
function bootstrap_tour_db_step_table() {
  return array(
    'description' => t('Individual Bootstrap tour steps for Bootstrap Tours (many-to-one).'),
    'fields' => array(
      'bootstrap_tour_step_id' => array(
        'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'no export' => TRUE,
      ),
      'path' => array(
        'description' => 'The path upon which the step should be displayed.',
        'type' => 'varchar',
        'length' => '255',
      ),
      'selector' => array(
        'description' => 'The CSS Selector to which the step should be attached.',
        'type' => 'varchar',
        'length' => '255',
      ),
      'placement' => array(
        'description' => 'Location of the popup.',
        'type' => 'varchar',
        'length' => '6',
      ),
      'title' => array(
        'description' => 'Title of the popup.',
        'type' => 'varchar',
        'length' => '255',
      ),
      'content' => array(
        'description' => 'Content of the popup.',
        'type' => 'text',
        'size' => 'big',
      ),
      'content_text_format' => array(
        'description' => 'The text format of the content field.',
        'type' => 'varchar',
        'length' => '255',
      ),
    ),
    'primary key' => array(
      'bootstrap_tour_step_id',
    ),
  );
}

/**
 * Returns the table definition for the legacy/deprecated table which held tours in 1.x.
 *
 * @return array
 */
function bootstrap_tour_db_legacy_table() {
  return array(
    'description' => t('Bootstrap tours courtesy of the Bootstrap Tours module'),
    'export' => array(
      'primary_key' => 'name',
      'api' => array(
        'owner' => 'bootstrap_tour',
        'api' => 'bootstrap_tour_tour',
        'minimum_version' => '1',
        'current_version' => '1',
      ),
      'default hook' => 'default_bootstrap_tour',
    ),
    'fields' => array(
      'name' => array(
        'type' => 'varchar',
        'length' => '255',
        'description' => 'Unique ID for tours used to identify them programmatically, generated from the name.',
      ),
      'title' => array(
        'type' => 'varchar',
        'length' => '255',
        'description' => 'Human readable name for the tour used for administrative purposes.',
      ),
      'roles' => array(
        'type' => 'varchar',
        'length' => '255',
        'description' => 'A comma separated list of roles that can access this tour.',
      ),
      'btid' => array(
        'type' => 'serial',
        'unsigned' => TRUE,
        'not null' => TRUE,
        'description' => 'Primary ID field for the table. Not used for anything except internal lookups.',
        'no export' => TRUE,
      ),
      'autorun' => array(
        'description' => 'Boolean indicating whether the tour should automatically start when the path of the first step is loaded.',
        'type' => 'int',
        'not null' => TRUE,
        'default' => 1,
      ),
      'description' => array(
        'type' => 'varchar',
        'length' => '255',
        'description' => 'A description of the site tour, used for administrative purposes.',
      ),
      'steps' => array(
        'type' => 'blob',
        'description' => 'A serialized array of tour steps.',
        'serialize' => TRUE,
      ),
    ),
    'primary key' => array(
      'btid',
    ),
    'unique keys' => array(
      'name' => array(
        'name',
      ),
    ),
  );
}
function bootstrap_tour_setup_step_field() {
  $field = array(
    'field_name' => 'bootstrap_tour_step_reference',
    'type' => 'entityreference',
    'cardinality' => FIELD_CARDINALITY_UNLIMITED,
    'settings' => array(
      'target_type' => 'bootstrap_tour_step',
      'handler_settings' => array(
        'target_bundles' => NULL,
      ),
    ),
  );
  field_create_field($field);
  $instance = array(
    'field_name' => 'bootstrap_tour_step_reference',
    'entity_type' => 'bootstrap_tour',
    'bundle' => 'bootstrap_tour',
    'label' => 'Tour Steps',
    'widget' => array(
      'weight' => '10',
      'type' => 'inline_entity_form',
      'module' => 'inline_entity_form',
      'active' => 1,
      'settings' => array(
        'fields' => array(),
        'type_settings' => array(
          'allow_existing' => 0,
          'match_operator' => 'CONTAINS',
          'delete_references' => 1,
          'override_labels' => 1,
          'label_singular' => 'step',
          'label_plural' => 'steps',
        ),
      ),
    ),
    'settings' => array(
      'target_type' => 'bootstrap_tour_step',
      'handler_settings' => array(
        'target_bundles' => NULL,
      ),
    ),
    'display' => array(
      'default' => array(
        'label' => 'inline',
        'type' => 'entityreference_label',
      ),
    ),
  );
  field_create_instance($instance);
}

/**
 * Legacy function which loads all 1.x tours from both exported Features and from the DB.
 *
 * @return array
 */
function bootstrap_tour_load_legacy_tours() {
  ctools_include('export');
  $tours = ctools_export_crud_load_all('bootstrap_tour_old');
  return $tours;
}

Functions

Namesort descending Description
bootstrap_tour_db_legacy_table Returns the table definition for the legacy/deprecated table which held tours in 1.x.
bootstrap_tour_db_step_table Returns the table definition for the table which holds the tour steps.
bootstrap_tour_db_tour_table Returns the table definition for the table which holds the tours.
bootstrap_tour_install Implements hook_install().
bootstrap_tour_load_legacy_tours Legacy function which loads all 1.x tours from both exported Features and from the DB.
bootstrap_tour_schema Implements hook_schema().
bootstrap_tour_setup_step_field
bootstrap_tour_uninstall Implements hook_uninstall().
bootstrap_tour_update_7200 Upgrade old 1.x tours to the new 2.x Entity format, then delete the old DB table.
bootstrap_tour_update_7201 Remove orphaned steps.