Revision 148 | Blame | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed
<?phpnamespace Illuminate\Database;use Doctrine\DBAL\Types\Type;use Illuminate\Database\Connectors\ConnectionFactory;use Illuminate\Database\Events\ConnectionEstablished;use Illuminate\Support\Arr;use Illuminate\Support\ConfigurationUrlParser;use Illuminate\Support\Str;use Illuminate\Support\Traits\Macroable;use InvalidArgumentException;use PDO;use RuntimeException;/*** @mixin \Illuminate\Database\Connection*/class DatabaseManager implements ConnectionResolverInterface{use Macroable {__call as macroCall;}/*** The application instance.** @var \Illuminate\Contracts\Foundation\Application*/protected $app;/*** The database connection factory instance.** @var \Illuminate\Database\Connectors\ConnectionFactory*/protected $factory;/*** The active connection instances.** @var array<string, \Illuminate\Database\Connection>*/protected $connections = [];/*** The custom connection resolvers.** @var array<string, callable>*/protected $extensions = [];/*** The callback to be executed to reconnect to a database.** @var callable*/protected $reconnector;/*** The custom Doctrine column types.** @var array<string, array>*/protected $doctrineTypes = [];/*** Create a new database manager instance.** @param \Illuminate\Contracts\Foundation\Application $app* @param \Illuminate\Database\Connectors\ConnectionFactory $factory* @return void*/public function __construct($app, ConnectionFactory $factory){$this->app = $app;$this->factory = $factory;$this->reconnector = function ($connection) {$this->reconnect($connection->getNameWithReadWriteType());};}/*** Get a database connection instance.** @param string|null $name* @return \Illuminate\Database\Connection*/public function connection($name = null){[$database, $type] = $this->parseConnectionName($name);$name = $name ?: $database;// If we haven't created this connection, we'll create it based on the config// provided in the application. Once we've created the connections we will// set the "fetch mode" for PDO which determines the query return types.if (! isset($this->connections[$name])) {$this->connections[$name] = $this->configure($this->makeConnection($database), $type);if ($this->app->bound('events')) {$this->app['events']->dispatch(new ConnectionEstablished($this->connections[$name]));}}return $this->connections[$name];}/*** Parse the connection into an array of the name and read / write type.** @param string $name* @return array*/protected function parseConnectionName($name){$name = $name ?: $this->getDefaultConnection();return Str::endsWith($name, ['::read', '::write'])? explode('::', $name, 2) : [$name, null];}/*** Make the database connection instance.** @param string $name* @return \Illuminate\Database\Connection*/protected function makeConnection($name){$config = $this->configuration($name);// First we will check by the connection name to see if an extension has been// registered specifically for that connection. If it has we will call the// Closure and pass it the config allowing it to resolve the connection.if (isset($this->extensions[$name])) {return call_user_func($this->extensions[$name], $config, $name);}// Next we will check to see if an extension has been registered for a driver// and will call the Closure if so, which allows us to have a more generic// resolver for the drivers themselves which applies to all connections.if (isset($this->extensions[$driver = $config['driver']])) {return call_user_func($this->extensions[$driver], $config, $name);}return $this->factory->make($config, $name);}/*** Get the configuration for a connection.** @param string $name* @return array** @throws \InvalidArgumentException*/protected function configuration($name){$name = $name ?: $this->getDefaultConnection();// To get the database connection configuration, we will just pull each of the// connection configurations and get the configurations for the given name.// If the configuration doesn't exist, we'll throw an exception and bail.$connections = $this->app['config']['database.connections'];if (is_null($config = Arr::get($connections, $name))) {throw new InvalidArgumentException("Database connection [{$name}] not configured.");}return (new ConfigurationUrlParser)->parseConfiguration($config);}/*** Prepare the database connection instance.** @param \Illuminate\Database\Connection $connection* @param string $type* @return \Illuminate\Database\Connection*/protected function configure(Connection $connection, $type){$connection = $this->setPdoForType($connection, $type)->setReadWriteType($type);// First we'll set the fetch mode and a few other dependencies of the database// connection. This method basically just configures and prepares it to get// used by the application. Once we're finished we'll return it back out.if ($this->app->bound('events')) {$connection->setEventDispatcher($this->app['events']);}if ($this->app->bound('db.transactions')) {$connection->setTransactionManager($this->app['db.transactions']);}// Here we'll set a reconnector callback. This reconnector can be any callable// so we will set a Closure to reconnect from this manager with the name of// the connection, which will allow us to reconnect from the connections.$connection->setReconnector($this->reconnector);$this->registerConfiguredDoctrineTypes($connection);return $connection;}/*** Prepare the read / write mode for database connection instance.** @param \Illuminate\Database\Connection $connection* @param string|null $type* @return \Illuminate\Database\Connection*/protected function setPdoForType(Connection $connection, $type = null){if ($type === 'read') {$connection->setPdo($connection->getReadPdo());} elseif ($type === 'write') {$connection->setReadPdo($connection->getPdo());}return $connection;}/*** Register custom Doctrine types with the connection.** @param \Illuminate\Database\Connection $connection* @return void*/protected function registerConfiguredDoctrineTypes(Connection $connection): void{foreach ($this->app['config']->get('database.dbal.types', []) as $name => $class) {$this->registerDoctrineType($class, $name, $name);}foreach ($this->doctrineTypes as $name => [$type, $class]) {$connection->registerDoctrineType($class, $name, $type);}}/*** Register a custom Doctrine type.** @param string $class* @param string $name* @param string $type* @return void** @throws \Doctrine\DBAL\DBALException* @throws \RuntimeException*/public function registerDoctrineType(string $class, string $name, string $type): void{if (! class_exists('Doctrine\DBAL\Connection')) {throw new RuntimeException('Registering a custom Doctrine type requires Doctrine DBAL (doctrine/dbal).');}if (! Type::hasType($name)) {Type::addType($name, $class);}$this->doctrineTypes[$name] = [$type, $class];}/*** Disconnect from the given database and remove from local cache.** @param string|null $name* @return void*/public function purge($name = null){$name = $name ?: $this->getDefaultConnection();$this->disconnect($name);unset($this->connections[$name]);}/*** Disconnect from the given database.** @param string|null $name* @return void*/public function disconnect($name = null){if (isset($this->connections[$name = $name ?: $this->getDefaultConnection()])) {$this->connections[$name]->disconnect();}}/*** Reconnect to the given database.** @param string|null $name* @return \Illuminate\Database\Connection*/public function reconnect($name = null){$this->disconnect($name = $name ?: $this->getDefaultConnection());if (! isset($this->connections[$name])) {return $this->connection($name);}return $this->refreshPdoConnections($name);}/*** Set the default database connection for the callback execution.** @param string $name* @param callable $callback* @return mixed*/public function usingConnection($name, callable $callback){$previousName = $this->getDefaultConnection();$this->setDefaultConnection($name);return tap($callback(), function () use ($previousName) {$this->setDefaultConnection($previousName);});}/*** Refresh the PDO connections on a given connection.** @param string $name* @return \Illuminate\Database\Connection*/protected function refreshPdoConnections($name){[$database, $type] = $this->parseConnectionName($name);$fresh = $this->configure($this->makeConnection($database), $type);return $this->connections[$name]->setPdo($fresh->getRawPdo())->setReadPdo($fresh->getRawReadPdo());}/*** Get the default connection name.** @return string*/public function getDefaultConnection(){return $this->app['config']['database.default'];}/*** Set the default connection name.** @param string $name* @return void*/public function setDefaultConnection($name){$this->app['config']['database.default'] = $name;}/*** Get all of the support drivers.** @return string[]*/public function supportedDrivers(){return ['mysql', 'pgsql', 'sqlite', 'sqlsrv'];}/*** Get all of the drivers that are actually available.** @return string[]*/public function availableDrivers(){return array_intersect($this->supportedDrivers(),str_replace('dblib', 'sqlsrv', PDO::getAvailableDrivers()));}/*** Register an extension connection resolver.** @param string $name* @param callable $resolver* @return void*/public function extend($name, callable $resolver){$this->extensions[$name] = $resolver;}/*** Remove an extension connection resolver.** @param string $name* @return void*/public function forgetExtension($name){unset($this->extensions[$name]);}/*** Return all of the created connections.** @return array<string, \Illuminate\Database\Connection>*/public function getConnections(){return $this->connections;}/*** Set the database reconnector callback.** @param callable $reconnector* @return void*/public function setReconnector(callable $reconnector){$this->reconnector = $reconnector;}/*** Set the application instance used by the manager.** @param \Illuminate\Contracts\Foundation\Application $app* @return $this*/public function setApplication($app){$this->app = $app;return $this;}/*** Dynamically pass methods to the default connection.** @param string $method* @param array $parameters* @return mixed*/public function __call($method, $parameters){if (static::hasMacro($method)) {return $this->macroCall($method, $parameters);}return $this->connection()->$method(...$parameters);}}