You are here

function _migrate_class_list in Migrate 6.2

Same name and namespace in other branches
  1. 7.2 migrate.module \_migrate_class_list()

For a given parent class, identify and instantiate objects for any non-abstract classes derived from the parent, returning an array of the objects indexed by class name. The array will be ordered such that any classes with dependencies are listed after the classes they are dependent on.

Parameters

$parent_class: Name of a class from which results will be derived.

Return value

Array of objects, keyed by the class name.

4 calls to _migrate_class_list()
MigrateFieldsNodeHandler::fields in plugins/destinations/fields.inc
migrate_field_handler_invoke_all in ./migrate.module
Invoke any available handlers attached to a given field type. If any handlers have dependencies defined, they will be invoked after the specified handlers.
migrate_handler_invoke_all in ./migrate.module
Invoke any available handlers attached to a given destination type. If any handlers have dependencies defined, they will be invoked after the specified handlers.
migrate_ui_handlers_form in migrate_ui/migrate_ui.pages.inc
Form for reviewing migrations.

File

./migrate.module, line 269

Code

function _migrate_class_list($parent_class) {

  // Get info on modules implementing Migrate API
  static $module_info;
  if (!isset($modules)) {
    $module_info = migrate_get_module_apis();
  }
  $modules = array_keys($module_info);
  static $class_lists = array();
  if (!isset($class_lists[$parent_class])) {
    $class_lists[$parent_class] = array();
    if ($parent_class == 'MigrateDestinationHandler') {
      $handler_key = 'destination handlers';
    }
    else {
      $handler_key = 'field handlers';
    }

    // Add explicitly-registered handler classes
    foreach ($module_info as $info) {
      if (isset($info[$handler_key]) && is_array($info[$handler_key])) {
        foreach ($info[$handler_key] as $handler_class) {
          $class_lists[$parent_class][$handler_class] = new $handler_class();
        }
      }
    }

    // Avoid scrounging the registry for handler classes if possible.
    if (variable_get('migrate_disable_autoregistration', FALSE)) {
      return $class_lists[$parent_class];
    }
    $dependent_classes = array();
    $required_classes = array();

    // Discover class names registered with Drupal by modules implementing our API
    $result = db_select('autoload_registry', 'r')
      ->fields('r', array(
      'name',
    ))
      ->condition('type', 'class')
      ->condition('module', $modules, 'IN')
      ->condition('filename', '%.test', 'NOT LIKE')
      ->execute();
    foreach ($result as $record) {

      // Validate it's an implemented subclass of the parent class
      // We can get funky errors here, ignore them (and the class that caused them)
      try {
        $class = new ReflectionClass($record->name);
      } catch (Exception $e) {
        continue;
      }
      if (!$class
        ->isAbstract() && $class
        ->isSubclassOf($parent_class)) {

        // If the constructor has required parameters, this may fail. We will
        // silently ignore - it is up to the implementor of such a class to
        // instantiate it in hook_migrations_alter().
        try {
          $object = new $record->name();
        } catch (Exception $e) {
          unset($object);
        }
        if (isset($object)) {
          $dependencies = $object
            ->getDependencies();
          if (count($dependencies) > 0) {

            // Set classes with dependencies aside for reordering
            $dependent_classes[$record->name] = $object;
            $required_classes += $dependencies;
          }
          else {

            // No dependencies, just add
            $class_lists[$parent_class][$record->name] = $object;
          }
        }
      }
    }

    // Validate that each depended-on class at least exists
    foreach ($required_classes as $class_name) {
      if (!isset($dependent_classes[$class_name]) && !isset($class_lists[$parent_class][$class_name])) {
        throw new MigrateException(t('Dependency on non-existent class !class - make sure ' . 'you have added the file defining !class to the .info file.', array(
          '!class' => $class_name,
        )));
      }
    }

    // Scan modules with dependencies - we'll take 20 passes at it before
    // giving up
    $iterations = 0;
    while (count($dependent_classes) > 0) {
      if ($iterations++ > 20) {
        $class_names = implode(',', array_keys($dependent_classes));
        throw new MigrateException(t('Failure to sort class list - most likely due ' . 'to circular dependencies involving !class_names.', array(
          '!class_names' => $class_names,
        )));
      }
      foreach ($dependent_classes as $name => $object) {
        $ready = TRUE;

        // Scan all the dependencies for this class and make sure they're all
        // in the final list
        foreach ($object
          ->getDependencies() as $dependency) {
          if (!isset($class_lists[$parent_class][$dependency])) {
            $ready = FALSE;
            break;
          }
        }
        if ($ready) {

          // Yes they are! Move this class to the final list
          $class_lists[$parent_class][$name] = $object;
          unset($dependent_classes[$name]);
        }
      }
    }
  }
  return $class_lists[$parent_class];
}