Using Laravel Service Provider to Override Connector Classes

I am working in Laravel 5.2 and I am trying to get it to work with Vertica. A couple of months ago my colleague and I came up with this solution, but now we are trying to make things a little less hacky and use service providers to make things work so we can update Laravel faster. So what we have done so far:

1) Create two new classes that extend your copies:

New BaseConnector:

namespace App\Vertica;
include 'clsPDOVertica.php';

use Illuminate\Support\Arr;
use \Illuminate\Database\Connectors\Connector as BaseConnector;

class Connector extends BaseConnector
{
    /**
     * Create a new PDO connection.
     *
     * @param  string  $dsn
     * @param  array   $config
     * @param  array   $options
     * @return \PDO
     */
    public function createConnection($dsn, array $config, array $options)
    {
        $username = Arr::get($config, 'username');

        $password = Arr::get($config, 'password');

        return new PDOVertica($dsn, $username, $password, $options);
    }
}

      

New PostgresConnector:

namespace App\Vertica;

use \Illuminate\Database\Connectors\PostgresConnector as BasePostgresConnector;

class PostgresConnector extends BasePostgresConnector
{

    /**
     * Create a DSN string from a configuration.
     *
     * @param  array   $config
     * @return string
     */
    protected function getDsn(array $config)
    {
        // First we will create the basic DSN setup as well as the port if it is in
        // in the configuration options. This will give us the basic DSN we will
        // need to establish the PDO connections and return them back for use.
        extract($config, EXTR_SKIP);

        $host = isset($host) ? "host={$host};" : '';

        $dsn = "Driver={$driverpath};{$host}Database={$database}";

        // If a port was specified, we will add it to this Postgres DSN connections
        // format. Once we have done that we are ready to return this connection
        // string back out for usage, as this has been fully constructed here.
        if (isset($config['port'])) {
            $dsn .= ";port={$port}";
        }

        if (isset($config['sslmode'])) {
            $dsn .= ";sslmode={$sslmode}";
        }

        return $dsn;
    }
}

      

We're now trying to define a service provider to essentially tell Laravel to use our classes instead of the default ones ... but no luck so far. Here's the code for the provider:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class VerticaServiceProvider extends ServiceProvider
{
    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function register()
    {
        // dd(new \Illuminate\Database\Connectors\PostgresConnector);
        $this->app->singleton('\Illuminate\Database\Connectors\Connector', function()
        {
            return new \App\Vertica\Connector();
        });

        $this->app->singleton('\Illuminate\Database\Connectors\PostgresConnector', function()
        {
            return new \App\Vertica\PostgresConnector();
        });
    }
}

      

So far, the registration method of our VerticaServiceProvider is being called, but obviously the binding internally is not correct since our classes are not being called. Does anyone know what we are doing wrong?

+1


source to share


1 answer


Laravel does not allow classes Connector

from the container, so trying to override the connector by class name will not work.

You can see in Illuminate/Database/Connectors/ConnectionFactory::createConnector

how connectors are resolved. Laravel just executes return new PostgresConnector

(or any of them is driver-friendly) so it doesn't appear in a container for the class name.

However, before "new" up a Connector

, it checks the container to see if there is a connector associated with the driver with a string 'db.connector.[driver]'

where [driver]

is the name of the driver db.



So instead of trying to bind the class name in the container, you need to bind a string 'db.connector.your-driver-name'

. So, if you created your own driver (for example vertica

), you must bind your connector to 'db.connector.vertica'

. Or, if you want to overwrite the built-in postgres connector, you must bind your connector to 'db.connector.pgsql'

.

Assuming you are trying to overwrite the postgres connector, your service provider registration method would look like this:

public function register()
{
    $this->app->bind('db.connector.pgsql', \App\Vertica\PostgresConnector::class);
}

      

+3


source







All Articles