美文网首页
lumen DB-Facades

lumen DB-Facades

作者: 小东班吉 | 来源:发表于2019-07-17 18:44 被阅读0次

    Facades 门面

    app.php 中$app->withFacades()开启门面模式就可以使用DB类

    public function withFacades($aliases = true, $userAliases = [])
    {
        Facade::setFacadeApplication($this);
    
        if ($aliases) {
            $this->withAliases($userAliases);
        }
    }
    
    \Illuminate\Support\Facades\Facade::setFacadeApplication
    

    可以看出,其实就是把app对象赋值给Facade类的app属性,而在Application实例话,启动容器的时候已经把db作为别名注入进去了,\Laravel\Lumen\Application::registerContainerAliases然后在使用DB类调用数据库函数的时候其实就是使用app对象app['db']这样调用数据库。

    DB类实现Facade的一个方法,返回的就是一个数据库类的别名\Illuminate\Support\Facades\DB::getFacadeAccessor例如:

    DB::select('SELECT *FROM users WHERE 1 LIMIT 1')
    

    其实就是调用Facades类的__callStatic方法,__callStatic方法里\Illuminate\Support\Facades\Facade::getFacadeRoot获取一个db对象,然后调用相应的方法,把查询的参数传进去。

    public static function __callStatic($method, $args)
    {
        $instance = static::getFacadeRoot();
    
        if (! $instance) {
            throw new RuntimeException('A facade root has not been set.');
        }
    
        return $instance->$method(...$args);
    }
    

    db别名绑定的是Illuminate\Database\DatabaseManager这个数据库管理类,这个类是一个公共类,同时支持其他数据库驱动,如'mysql', 'pgsql', 'sqlite', 'sqlsrv',默认在config.php配置的是mysql,在查询的时候就指的是mysql的驱动,如select查询调用DatabaseManager类的call方法,如果没有指定connections,会取默认的数据库连接,比如不同数据库之间的查询,由config文件的database.default这个控制,根据数据库名称从configure里面取出一个链接的配置类容。那么db是在什么时候注册进去的呢,这个其实只是在一开始做类一个绑定,在应用的时候通过make方法取出一个实例来。

    protected function registerContainerAliases()
        {
            $this->aliases = [
                'Illuminate\Database\DatabaseManager' => 'db',
            ];
        }
    
    public function make($abstract, array $parameters = [])
    {
        $abstract = $this->getAlias($abstract);
    
        if (array_key_exists($abstract, $this->availableBindings) &&
            ! array_key_exists($this->availableBindings[$abstract], $this->ranServiceBinders)) {
            $this->{$method = $this->availableBindings[$abstract]}();
    
            $this->ranServiceBinders[$method] = true;
        }
    
        return parent::make($abstract, $parameters);
    }
    
    /**
    * The available container bindings and their respective load methods.
    *
    * @var array
    */
    public $availableBindings = [
        'db' => 'registerDatabaseBindings',
    ];
    
    protected function registerDatabaseBindings()
        {
            $this->singleton('db', function () {
                return $this->loadComponent(
                    'database', [
                        'Illuminate\Database\DatabaseServiceProvider',
                        'Illuminate\Pagination\PaginationServiceProvider',
                    ], 'db'
                );
            });
        } 
        
        /**
         * \Illuminate\Database\DatabaseServiceProvider::registerConnectionServices
         * Register the primary database bindings.
         *
         * @return void
         */
        protected function registerConnectionServices()
        {
            // The connection factory is used to create the actual connection instances on
            // the database. We will inject the factory into the manager so that it may
            // make the connections while they are actually needed and not of before.
            $this->app->singleton('db.factory', function ($app) {
                return new ConnectionFactory($app);
            });
    
            // The database manager is used to resolve various connections, since multiple
            // connections might be managed. It also implements the connection resolver
            // interface which may be used by other components requiring connections.
            $this->app->singleton('db', function ($app) {
                return new DatabaseManager($app, $app['db.factory']);
            });
    
            $this->app->bind('db.connection', function ($app) {
                return $app['db']->connection();
            });
        }
    

    DatabaseManager这里调用call方法的时候会去获取默认的connection,\Illuminate\Database\DatabaseManager::makeConnection这个方法就是为了获取一个数据库连接的实例,this->factory->make(config, $name) 这里的factory就是ConnectionFactory类,调用它里面的make方法,参数就是数据库的配置数组,和名称,这里就是名称就是mysql,\Illuminate\Database\Connectors\ConnectionFactory::createConnection个方法就是去连接数据库了,MySqlConnection继承了\Illuminate\Database\Connection这个类,调用它的select方法执行sql。ConnectionFactory是一个生产连接的工厂类,\Illuminate\Database\ConnectionInterface这个接口在\Illuminate\Database\Connection基础类上实现了它,然后不同的数据库驱动又继承了基础的connection类。

    ORM 对象关系模型

    app.php 中$app->withEloquent()开启orm关系模式

    和门面一样,在app对象实例化的时候已经绑定了db的别名,开启orm的时候通过make方法取出数据库的实例,db就是在make的时候去寻找系统已经绑定的数组,注入容器,运行加载的方法,比如db就是这个\Laravel\Lumen\Application::registerDatabaseBindings方法,这个方法里加载了数据库的配置文件以及注册数据库服务,返回一个db的实例。

    class DatabaseServiceProvider extends ServiceProvider
    {
        public function boot()
        {
            Model::setConnectionResolver($this->app['db']);
    
            Model::setEventDispatcher($this->app['events']);
        }
    
        public function register()
        {
            Model::clearBootedModels();
    
            $this->registerConnectionServices();
    
            $this->registerEloquentFactory();
    
            $this->registerQueueableEntityResolver();
        }
    
        protected function registerConnectionServices()
        {
            $this->app->singleton('db.factory', function ($app) {
                return new ConnectionFactory($app);
            });
            $this->app->singleton('db', function ($app) {
                return new DatabaseManager($app, $app['db.factory']);
            });
    
            $this->app->bind('db.connection', function ($app) {
                return $app['db']->connection();
            });
        }
    
        protected function registerEloquentFactory()
        {
            $this->app->singleton(FakerGenerator::class, function ($app) {
                return FakerFactory::create($app['config']->get('app.faker_locale', 'en_US'));
            });
    
            $this->app->singleton(EloquentFactory::class, function ($app) {
                return EloquentFactory::construct(
                    $app->make(FakerGenerator::class), $this->app->databasePath('factories')
                );
            });
        }
    
        protected function registerQueueableEntityResolver()
        {
            $this->app->singleton(EntityResolver::class, function () {
                return new QueueEntityResolver;
            });
        }
    }
    

    \Illuminate\Database\DatabaseServiceProvider注册的时候运行boot方法,db的实例在这设置给\Illuminate\Database\Eloquent\Model类中,register方法中先清除已启动的实例,接下来就是一系列数据库相关的注册到容器中,应用的时候,我们所有的模型类都会实现\Illuminate\Database\Eloquent\Model,它使用了其他orm操作运算的一些trait类(trait类会覆盖类继承的方法,当前类的中法又会覆盖trait中的方法,这也是php解决单继承做的一个扩展)。

    相关文章

      网友评论

          本文标题:lumen DB-Facades

          本文链接:https://www.haomeiwen.com/subject/ravclctx.html