Magento 2 – Preference for \Magento\Framework\DB\Adapter\AdapterInterface

dependency-injectionmagento2

I'm trying to override a Collection constructor and getting

Fatal error: Uncaught Error: Cannot instantiate interface Magento\Framework\DB\Adapter\AdapterInterface in /var/www/magento/vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php on line 93

As well as

Error: Cannot instantiate interface Magento\Framework\DB\Adapter\AdapterInterface in /var/www/magento/vendor/magento/framework/ObjectManager/Factory/AbstractFactory.php on line 93

I have tried:

  1. Look in the core for any preference for Magento\Framework\DB\Adapter\AdapterInterface with no luck.

  2. setup:di:compile with no luck.

The problem was also raised here:
How dependency injection works for Interfaces in constructors with no answer though.

Any help will much appreciated.

EDIT

So the problem was not overriding the Collection constructor.

class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{

public function __construct(
    \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory,
    \Psr\Log\LoggerInterface $logger,
    \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
    \Magento\Framework\Event\ManagerInterface $eventManager,
    \Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
    \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource = null,
     $someParam = null
)
{
    parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource);
    //$this->relationResourceModel = $resourceModel;
}

This will work.
The problem was that I was trying to inject a foreign resource model in the collection constructor

class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{
protected $relationResourceModel;

public function __construct(
    \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory,
    \Psr\Log\LoggerInterface $logger,
    \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
    \Magento\Framework\Event\ManagerInterface $eventManager,
    \Magento\Framework\DB\Adapter\AdapterInterface $connection = null,
    \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource = null,
    \Vendor\Module\Model\ResourceModel\ResourceModel $resourceModel
)
{
    parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource);
    $this->relationResourceModel = $resourceModel;
}

This will not work.
It would be nice to know the inner workings of this and why this does not work. But I chosen another approach.

Best Answer

Note that when using default arguments, any defaults should be on the right side of any non-default arguments; otherwise, things will not work as expected.

http://php.net/manual/en/functions.arguments.php

Moreover, in this case connection with type \Magento\Framework\DB\Adapter\AdapterInterface is non-injectable object.

Newable/non-injectable: Objects obtained by creating a new class instance every time. Transient objects, such as those that require external input from the user or database, fall into this category. Attempts to inject these objects produce either an error that the object could not be created or an incorrect object that is incomplete.

http://devdocs.magento.com/guides/v2.2/extension-dev-guide/depend-inj.html

Try to move required arguments before optional