本文介绍了使用Laravel服务提供者覆盖连接器类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Laravel 5.2,并且正在尝试使其与Vertica一起使用.几个月前,我和我的同事想到了解决方案,但我们现在正尝试使事情变得更不那么骇人听闻,并使用服务提供商来使事情正常进行,以便我们实际上可以更轻松地升级Laravel.所以到目前为止,我们要做的是:

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)创建两个新类,以扩展其对应类:

1) Create two new classes that extends their counterparts:

新的BaseConnector:

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

新的PostgresConnector:

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

现在,我们正在尝试定义一个服务提供者,从本质上告诉Laravel使用我们的类而不是默认的类……但到目前为止没有成功.这是提供程序的代码:

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

到目前为止,我们的VerticaServiceProvider的register方法已被调用,但显然,由于未调用我们的类,因此内部的绑定是错误的.有人知道我们在做什么错吗?

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?

推荐答案

Laravel无法从容器中解析Connector类,因此尝试按类名覆盖连接器将不起作用.

Laravel does not resolve the Connector classes from the container, so attempting to override the connector by class name will not work.

您可以在中看到Illuminate/Database/Connectors/ConnectionFactory::createConnector 连接器的解析方式. Laravel只会执行return new PostgresConnector(或适合驱动程序的任何一个),因此它不会在容器中查找类名.

You can see in Illuminate/Database/Connectors/ConnectionFactory::createConnector how the connectors are resolved. Laravel just does a return new PostgresConnector (or whichever one is appropriate for the driver), so it does not look in the container for the class name.

但是,在它新"建立一个Connector之前,它会确实检查容器以查看是否存在使用字符串'db.connector.[driver]'绑定到驱动程序的连接器,其中[driver]是db驱动程序名称.

However, before it "new"s up a Connector, it does check the container to see if there is a connector bound to the driver using the string 'db.connector.[driver]', where [driver] is the db driver name.

因此,您无需绑定容器中的类名,而需要绑定字符串'db.connector.your-driver-name'.因此,如果您创建了自己的自定义驱动程序(例如vertica),则可以将连接器绑定到'db.connector.vertica'.或者,如果您想覆盖内置的postgres连接器,则可以将连接器绑定到'db.connector.pgsql'.

Therefore, instead of attempting to bind the class name in the container, you need to bind the string 'db.connector.your-driver-name'. So, if you created your own custom driver (e.g. vertica), you would bind your connector to 'db.connector.vertica'. Or, if you want to overwrite the built in postgres connector, you would bind your connector to 'db.connector.pgsql'.

基于您要覆盖postgres连接器的假设,您的服务提供商注册方法如下:

Based on the assumption you're trying to overwrite the postgres connector, your service provider register method would look like:

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

这篇关于使用Laravel服务提供者覆盖连接器类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-17 02:23