Laravel Service Container: контекстная привязка для родительского класса, применяется ко всем дочерним классам - PullRequest
0 голосов
/ 07 сентября 2018

Я пытаюсь реализовать контекстную привязку реализации DatabaseConnectionClass на основе репозитория, который в этом нуждается.

Это необходимо, чтобы хранилища, извлекающие данные из разных баз данных, могли делать это с помощью соответствующего соединения.

Мой интерфейс подключения к базе данных такой же, как и у

/**
 * Interface DatabaseConnectionInterface
 *
 * @package App\Database\Connection
 */
interface DatabaseConnectionInterface {

    /**
     * Get the database connection
     *
     * @return Connection
     */
    public function getConnection(): Connection;

}

Мой базовый репозиторий

/**
 * Class MiRepository
 *
 * Base repository centralising connection injection
 *
 * @package App\Repositories\Mi
 */
class MiRepository {

    /**
     * The connection to the database
     *
     * @var DatabaseConnectionInterface
     */
    protected $connection;

    /**
     * MiRepository constructor.
     *
     * @param DatabaseConnectionInterface $connection
     */
    public function __construct(DatabaseConnectionInterface $connection){
        $this->connection = $connection->getConnection();
    }

}

Расширение хранилища

/**
 * Class SchemeRepository
 *
 * @package App\Mi\Repositories
 */
class SchemeRepository extends MiRepository {

    /**
     * Find and return all stored SchemeValidator
     *
     * @return Scheme[]|NULL
     */
    public function findAll(): ?array {
        $results = $this->connection->select('EXEC [webapi_get_products_schemes]');

        if(empty($results)){
            return NULL;
        }

        $schemes = array();
        foreach($results as $result){
            $schemes[] = Scheme::create($result->SCHEMENAME);
        }

        return $schemes;
    }

}

Служба контейнера привязки

/**
 * Class MiServiceProvider
 *
 * @package App\Providers
 */
class MiServiceProvider extends ServiceProvider
{

    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->when(MiRepository::class)
            ->needs(DatabaseConnectionInterface::class)
            ->give(function(){
                return new MiDatabaseConnection();
            });
    }
}

Проблема в том, что когда я пытаюсь внедрить расширение базового репозитория, я не думаю, что контекстная привязка сработала, и я получаю исключение

Target [App\\Common\\Database\\Connection\\DatabaseConnectionInterface] is not instantiable ...

Кто-нибудь сталкивался с этой проблемой раньше и знал, как использовать контекстную привязку в родительском классе и сработала ли она для всех детей?

Я знаю, что этого можно добиться путем реализации определений контекстной привязки для всех дочерних классов, однако это выглядит немного неуклюже.

Заранее спасибо!

1 Ответ

0 голосов
/ 08 сентября 2018

Насколько я знаю, поскольку PHP и внедрение зависимостей в целом полагаются на рефлексию, чтобы узнать, какие классы ищут конструкторы, он в основном выполняет поиск по строковому шаблону, чтобы найти правильную привязку. Поскольку вы не определили связанную строку для своих расширенных классов, она не может найти связанную функцию связывания. Поэтому я подозреваю, что то, что вы хотите сделать, не сработает.

Обходной путь, чтобы избежать слишком большого количества повторяющегося кода, может быть:

public function register()
{
    foreach($repo in ['Foo', 'Bar', 'Baz']) {

        $this->app->when($repo . Repository::class)
            ->needs(DatabaseConnectionInterface::class)
            ->give(function () use ($repo) {
                $theClass = $repo . 'DatabaseConnection';
                return new $theClass();
            });
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...