Laravel 5.1 Querying the underlying principle (query Builder) source parsing (top)

Source: Internet
Author: User
Tags closure magic call prepare sqlite unsupported

Original address

Description: This article mainly learn laravel database module Query Builder source code. In fact, Laravel designs the database through schema Builder and curd the database through Query Builder. Query Builder is not complex or mysterious, only on the basis of the PDO extension and open the closed packaging layer, providing the fluent API, so that the writing code is also very concise and smooth. Before looking at the source of Query Builder, let's explore the directory structure of the Illuminate/database package.

Development environment: Laravel5.3 + PHP7

Folder/file Description
Capsule There is only one manager class under the capsule folder, which mainly implements container instantiation, Databasemanager and connectionfactory instantiation.
Connectors Contains four DB linker: Mysqlconnector,postgresconnector,sqliteconnector,sqlserverconnector, which is one of the main components used to link corresponding db when crud
Console This file contains commands for migration and seed, such as PHP artisan db:seed, PHP artisan Migrate
Eloquent The folder contains the main implementation classes of eloquent, such as the focus of the model class, the builder class, and the relationship class of the tables contained within the Relations subfolder. is the core component and is also the most class folder
Events The folder that loads the event class
Migrations Classes that actually execute migrate related commands
Query Query Builder's code is mainly in this folder, the main class is the builder class, also includes grammars and processors two categories, according to four different DB classified
Schema is the primary participant class for the design database, the main classes are the builder class and the Blueprint class, and the grammars category, which is categorized according to four different db
Connection class Database link class, which encapsulates PDO, is an important class
Databasemanager class Registering as ' db ' in Databaseserviceprovider, usually through the manager to ' go down ' to the corresponding database implementation class, is an important class
Seeder class Operations that are primarily responsible for the seed command
instantiation of a database connection

Query Builder is mainly under the query folder, with a simple and often used code as an example to learn the principles of internal implementation:

Route::get ('/query_builder ', function () {
    //Query Builder
    return db::table (' users ')->where (' id ', ' = ', 1)- >get ();
});

ILLUMINATE/SUPPORT/FACADES/DB
class DB extends facade
{
    /**
     * Get The registered name of the component .
     *
     * @return String
     *
    /protected static function Getfacadeaccessor ()
    {
        return ' db ';
    }
}

In Databaseserviceprovider has registered a service called ' db ' is Databasemanager object, then actually magic call Databasemanager in the table () method, see the __call () Magic method Source:

    $method = ' table ', $parameters = ' users ' public
    function __call ($method, $parameters)
    {
        return $this-& Gt;connection () $method (... $parameters);
    }

So the focus is connection () method, the method returned is the connection object, look at the connection () method source code:

Public function connection ($name = null) {//$name = ' mysql ', $type = null list ($name, $type) = $this

        ->parseconnectionname ($name);  For the first time in $connections[] there is no ' mysql ' = $mysql _connection, so the corresponding DB connection needs to be created according to the configuration if (! isset ($this->connections[$name]))
            
            {//The focus is makeconnection () to create a MySQL connection instance $connection = $this->makeconnection ($name);

            Since $type is null, not ' write ' or ' read ', there is nothing actually done $this->setpdofortype ($connection, $type); After you get the connection instance $connection, you also need to prepare for the instance, such as binding events, setting Connector $this->connections[$name] = $this->prepare ($co
        Nnection);
    } return $this->connections[$name];
        } protected function Parseconnectionname ($name) {$name = $name?: $this->getdefaultconnection ();  Check whether to:: Read,:: Write End return Str::endswith ($name, [':: Read ', ':: Write '])? Explode (':: ', $name, 2): [$name,NULL]; The Public Function getdefaultconnection () {///Laravel is MySQL by default, which is assumed to be a common MySQL connection return $this-&G
    t;app[' config ' [' Database.default ']; }

Through the above source know the focus is makeconnection ($name) method, the method according to the name of the incoming MySQL to instantiate a connection object, focus on makeconnection () source code:

    protected function MakeConnection ($name)
    {
        //Get configuration of ' connections.mysql ' from config/database.php
        $config = $ This->getconfig ($name);

        If you have already customized a connection, such as using the Databasemanager::extend () method to customize a ' MySQL ' connection instance in Appserviceprovider boot (), then
        use that instance, This assumes no custom
        if (isset ($this->extensions[$name]) {
            return Call_user_func ($this->extensions[$name], $ Config, $name);
        }

        $driver = ' MySQL '
        $driver = $config [' driver '];

        if (Isset ($this->extensions[$driver]) {
            return Call_user_func ($this->extensions[$driver], $config, $ name);
        }
        
        Get the MySQL connection class    
        return $this->factory->make ($config, $name) through the ConnectionFactory class Factory mode
    ;}

The

Actually finally through the \illuminate\database\connectors\connectionfactory to resolve the corresponding connection, here used the Factory mode, see the Factory class make () method source code:

 Public function make (array $config, $name = null) {$config = $this->parseconfig (

        $config, $name);
        if (Isset ($config [' read])) {return $this->createreadwriteconnection ($config);
    } return $this->createsingleconnection ($config); } protected function createsingleconnection (array $config) {//$pdo is a closure $pdo = $this->cre

        Atepdoresolver ($config);
            return $this->createconnection (//$config [' driver '] = ' mysql ', $config [' database '] = ' homestead ' (db name)
    $config [' Driver '], $pdo, $config [' database '], $config [' prefix '], $config);
            } protected function Createpdoresolver (array $config) {return function () use ($config) {
        return $this->createconnector ($config)->connect ($config);
    }; }

In-depth code discovery, and finally through the factory class CreateConnection () method to create a Connection object, CreateConnection () source code is a common fool-like factory constructor:

 protected function createconnection ($driver, $connection, $database, $prefix = ", array $config = []) {///container already bound ' db.connection.mysql ' service to parse out the service, here is not registered if ($this->container->bound ($key = " Db.connection.
        {$driver} ") {return $this->container->make ($key, [$connection, $database, $prefix, $config]); }//$driver = ' mysql ' switch ($driver) {case ' MySQL ': return new Mysqlconn
            Ection ($connection, $database, $prefix, $config);
            Case ' Pgsql ': return new Postgresconnection ($connection, $database, $prefix, $config);
            Case ' SQLite ': return new Sqliteconnection ($connection, $database, $prefix, $config);
        Case ' sqlsrv ': return new Sqlserverconnection ($connection, $database, $prefix, $config);
    } throw new InvalidArgumentException ("Unsupported driver [$driver]"); }

In short, through the above step-by-step analysis to get the connection object, Databasemanager in the __call () method of the last implementation is (new Mysqlconnection (*))->table (' users ')- >where (' id ', 1)->get ().

OK, note here that the construction parameter of the Mysqlconnection $connection is a closure, the value of the closure is the return value of Connectionfactory::createpdoresolver (), see the operation in the closure:

    protected function Createpdoresolver (array $config) {return function () use ($config) {retur
        n $this->createconnector ($config)->connect ($config);
    }; The Public Function Createconnector (array $config) {if (! isset ($config [' Driver '])) {thro
        W New InvalidArgumentException (' A driver must be specified. '); } if ($this->container->bound ($key = "db.connector.{
        $config [' Driver ']}) {return $this->container->make ($key);
            } switch ($config [' driver ']) {case ' MySQL ': return new Mysqlconnector;
            Case ' Pgsql ': return new Postgresconnector;
            Case ' SQLite ': return new Sqliteconnector;
        Case ' sqlsrv ': return new Sqlserverconnector;
    } throw new InvalidArgumentException ("unsupported driver [{$config [' Driver ']}]"); }

It's very simple to know that when the closure is executed, the behavior is actually performed similar to (new Mysqlconnector)->connect ($config).

Here, the linker instance has been mysqlconnection, and the connection is loaded with a (new Mysqlconnector)->connect ($config), which is then used to talk about its specific connection logic.

Summary: The first step to the database connection instantiation has been completed, has already got the connection instance mysqlconnection, the next step will learn how to connect () How the connector connects the database, and how to compile the execution SQL statement to get the result value of user_id 1. I'll be there.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.