Friday, March 3, 2017

Using Laravel service provider to override connector classes

I'm working in Laravel 5.2 and I'm trying to make it work with Vertica. A couple of months ago, my colleague and I came up with this solution, but we're now trying to make things a little less hacky and use service providers to make things work so we can actually upgrade Laravel more easily. So what we've done so far is this:

1) Create two new classes that extends their counterparts:

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;
    }
}

Now, we're trying to define a service provider to essentially tell Laravel to use our classes instead of the default ones... but so far without success. 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 register method of our VerticaServiceProvider gets called, but obviously, the binding inside is wrong since our classes are not getting called. Anyone has any idea what we're doing wrong?



via Osuwariboy

Advertisement