0

Fatal error: Declaration of Drupal\migrate_upgrade\MigrateUpgradeDrushRunner::create(Psr\Container\ContainerInterface $container, $options = Array) must be compatible with Drupal\Core\DependencyInjection\ContainerInjectionInterface::create(Symfony\Component\DependencyInjection\ContainerInterface $container)

Below is MigrateUpgradeCommands.php file where I am creating an instance of new MigrateUpgradeDrushRunner() and passing two arguments $options and $this->logger

    class MigrateUpgradeCommands extends DrushCommands {
    /**
       * Logger service.
       *
       * @var \Drupal\Core\Logger\LoggerChannelInterface
       */
      protected $logger;

      /**
       * MigrateUpgradeCommands constructor.
       *
       * @param \Drupal\Core\State\StateInterface $state
       *   State service.
       * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerChannelFactoryInterface
       *   The logger.factory service.
       */
      public function __construct(StateInterface $state, LoggerChannelFactoryInterface $loggerFactory) {
        $this->state = $state;
        $this->logger = $loggerFactory->get('drush');
      }
/**
   * Perform one or more upgrade processes.
   *
   * @command migrate:upgrade
   *
   * @usage drush migrate-upgrade --legacy-db-url='mysql://root:pass@127.0.0.1/d6'
   *   Upgrade a Drupal 6 database to Drupal 8
   * @usage drush migrate-upgrade --legacy-db-key='drupal_7'
   *   Upgrade Drupal 7 database where the connection to Drupal 7 has already
   * been created in settings.php ($databases['drupal_7'])
   * @usage drush migrate-upgrade --legacy-db-url='mysql://root:pass@127.0.0.1/d7' --configure-only --migration-prefix=d7_custom_ --legacy-root=https://www.example.com
   *   Generate migrations for a custom migration from Drupal 7 to Drupal 8
   *
   * @validate-module-enabled migrate_upgrade
   *
   * @aliases migrate-upgrade, mup
   *
   * @throws \Exception
   *   When an error occurs.
   */
  public function upgrade(array $options = []) {
    $runner = new MigrateUpgradeDrushRunner($options, $this->logger);

    $runner->configure();
    if ($options['configure-only']) {
      $runner->export();
    }
    else {
      $runner->import();
      $this->state->set('migrate_drupal_ui.performed', \Drupal::time()->getRequestTime());
    }
    // Remove the global database state.
    $this->state->delete('migrate.fallback_state_key');
  }

    }

Now file MigrateUpgradeDrushRunner.php

class MigrateUpgradeDrushRunner implements ContainerInjectionInterface {
  /**
   * Logger channel.
   *
   * @var \Drupal\Core\Logger\LoggerChannelInterface
   */
  protected $logger;

  public static function create(ContainerInterface $container, $options = []) {
    return new static(
      $container->get('logger.factory'),
      $options
    );
  }

  /**
   * MigrateUpgradeDrushRunner constructor.
   *
   * @param array $options
   *   Drush options parameters.
   * @param \Drupal\Core\Logger\LoggerChannelInterface $logger
   *   Drush logger.
   */
  public function __construct(array $options = [], LoggerChannelInterface $logger) {
    $this->setOptions($options);
    $this->logger = $logger;
  }


}

Basically, how can I inject Container into MigrateUpgradeDrushRunner so that I can fetch logger.factory service and pass it in the construct ?

  • The error basically means you are not conforming to the interface contract because you are passing too many arguments to create. – Kevin Nov 23 '19 at 21:49
  • I think you should add $logger argument to your create method. – berramou Nov 23 '19 at 22:23
  • 2
    Remove $options form __construct and create arguments and add setter and getter function for the protected $options variable. You can also define the MigrateUpgradeDrushRunner as a service and inject it to the MigrateUpgradeCommands. Read more about services and dependency injection in Drupal 8: drupal.org/docs/8/api/services-and-dependency-injection/… – quex Nov 24 '19 at 0:00
2

Instead of adding $options to your create method you shall add a method to set the options.

Take a look at this code to see how you can inject $logger in your class:

class MigrateUpgradeDrushRunner implements ContainerInjectionInterface {

  /**
   * The logger channel factory.
   * 
   * @var LoggerChannelFactoryInterface 
   */
  protected $logger;

  /**
   * The options.
   * 
   * @var array
   */
  protected $options = [];

  /**
   * MigrateUpgradeDrushRunner constructor.
   * 
   * @param LoggerChannelFactoryInterface $logger
   *   The logger channel factory.
   */
  public function __construct(LoggerChannelFactoryInterface $logger) {
    $this->logger = $logger;
  }

  /**
   * {@inheritDoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('logger.factory')
    );
  }


  /**
   * Set the options.
   *
   * @params array $options
   *   The options.
   */
  public function setOptions(array $options) {
    // Do something...
  }

}
2

There are too many possible answers because you can inject dependencies in different ways. Normally Drupal uses the container injecting method for Controllers and Plugins, but your class is neither of it. So it is unclear what you are trying to achieve.

You can however use this also for other classes, like this utility class to update config entities. Then you have to use the class resolver to instantiate the class, which you see in the annotations of the class:

namespace Drupal\Core\Config\Entity;

use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * A utility class to make updating configuration entities simple.
 *
 * Use this in a post update function like so:
 * @code
 * // Ensure Taxonomy module installed before trying to update vocabularies.
 * if (\Drupal::moduleHandler()->moduleExists('taxonomy')) {
 *   // Update the dependencies of all Vocabulary configuration entities.
 *   \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'taxonomy_vocabulary');
 * }
 * @endcode
 *
 * The number of entities processed in each batch is determined by the
 * 'entity_update_batch_size' setting.
 *
 * @see default.settings.php
 */
class ConfigEntityUpdater implements ContainerInjectionInterface {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The number of entities to process in each batch.
   * @var int
   */
  protected $batchSize;

  /**
   * ConfigEntityUpdater constructor.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param int $batch_size
   *   The number of entities to process in each batch.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, $batch_size) {
    $this->entityTypeManager = $entity_type_manager;
    $this->batchSize = $batch_size;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager'),
      $container->get('settings')->get('entity_update_batch_size', 50)
    );
  }

  ...

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.