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.