Software Design Question regarding DI Container

Hello everybody :smile:

TLDR: How to use the DI Container to inject services depending on values which are only known in runtime.

First of all let me swiftly explain what my service does:

I have a service called AlfredFTP which basically lets me check given (S)FTP Login data if they are correct or not.

I separated each check logic into their own connection variants which are

  • Plain FTP
  • FTP with implicit SSL/TLS
  • FTP with explicit SSL/TLS
  • SFTP

So in my AlfredFTP base class I basically do

      switch( $this->login_data->connection_type_id ) {
        case static::CONN_ID_FTP:
          $this->check_ftp_data();
          break;

        case static::CONN_ID_FTP_IMPLICIT:
          $this->check_implicit_ftp_data();
          break;

        case static::CONN_ID_FTP_EXPLICIT:
          $this->check_explicit_ftp_data();
          break;

        case static::CONN_ID_SFTP:
          $this->check_sftp_data();
          break;

Now in each of those functions I do some think like

    $ftp = new FTP( $this->categoryHelper );
    $is_valid = $ftp->is_valid( $this->login_data );

    if( $is_valid ):
        // more logic
    endif;

but as you see I “hardcoded” the new FTP( $this->categoryHelper ); part in there.

This is what I want to change to more easily make my service class testable via mocked services in phpunit.

But I just can’t get my head around how I should do that or how I should refactor my service class to make that possible because depending on the value present in $this->login_data->connection_type_id I want to have a object from a different class.

I am sure this is somehow possible so I really would appreciate if someone could enlighten me :smile:

Thanks to the help of @ADmad in Slack/Discord I now found my solution in the registry pattern :smile:
http://rizqi.id/laravel-registry-pattern

1 Like