├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── config └── optimize-init-db-connection.php └── src ├── LaravelOptimizeInitDbConnectionServiceProvider.php └── OptimizedMySqlConnector.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-optimize-init-db-connection` will be documented in this file. 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) huynt57 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This package for optimize Laravel Init Database Connection 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/huy-nguyen/laravel-optimize-init-db-connection.svg?style=flat-square)](https://packagist.org/packages/huy-nguyen/laravel-optimize-init-db-connection) 4 | [![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/huynt57/laravel-optimize-init-db-connection/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/huynt57/laravel-optimize-init-db-connection/actions/workflows/run-tests.yml) 5 | [![Total Downloads](https://img.shields.io/packagist/dt/huy-nguyen/laravel-optimize-init-db-connection.svg?style=flat-square)](https://packagist.org/packages/huy-nguyen/laravel-optimize-init-db-connection) 6 | 7 | 8 | 9 | As mentioned in PR [50044](https://github.com/laravel/framework/pull/50044), this package was implemented for lower Laravel version (PHP >= 7.2, Laravel >= 6) 10 | 11 | > "The current code does multiple round-trips to set all the variables we need for our config, both because there are multiple commands to run, but also because it's using prepare, for many of them - each use of prepare and execute causes 3 round trips - one to prepare, one to execute, and one to close statement (on garbage collection of the statement in PHP land). The MySQL SET command supports setting multiple things in a comma separated fashion. Refactoring to do this enables us to just run one SET statement against the server. This can make a real difference in a cloud situation such as AWS Lambda talking to an RDS database where we have to go cross-AZ with low single digit ms latency, instead of sub-ms latency. This also reduces load on the DB (fewer statements to execute), so spinning up a bunch of Lambdas in a burst will be less of a burden." 12 | 13 | 14 | ## Installation 15 | 16 | You can install the package via composer: 17 | 18 | ```bash 19 | composer require huy-nguyen/laravel-optimize-init-db-connection 20 | ``` 21 | 22 | You can publish the config file with: 23 | 24 | ```bash 25 | php artisan vendor:publish --tag="optimize-init-db-connection-config" 26 | ``` 27 | 28 | This is the contents of the published config file: 29 | 30 | ```php 31 | return [ 32 | 'driver' => 'mysql', 33 | ]; 34 | ``` 35 | 36 | ## Usage 37 | 38 | As default, this package will change your "mysql" connection. You can setup new database connection by: 39 | 40 | Change your configuration (```php config/optimize-init-db-connection.php ```) 41 | ```php 42 | return [ 43 | 'driver' => 'optimize-mysql', 44 | ]; 45 | ``` 46 | Update your driver connection to ```optimize-mysql ```: 47 | ```php 48 | 'mysql' => [ 49 | 'driver' => 'optimize-mysql', 50 | 'url' => env('DATABASE_URL'), 51 | 'host' => env('DB_HOST', '127.0.0.1'), 52 | 'port' => env('DB_PORT', '3306'), 53 | 'database' => env('DB_DATABASE', 'forge'), 54 | 'username' => env('DB_USERNAME', 'forge'), 55 | 'password' => env('DB_PASSWORD', ''), 56 | 'unix_socket' => env('DB_SOCKET', ''), 57 | 'charset' => 'utf8mb4', 58 | 'collation' => 'utf8mb4_unicode_ci', 59 | 'prefix' => '', 60 | 'prefix_indexes' => true, 61 | 'strict' => false, 62 | 'engine' => null, 63 | 'options' => [] 64 | ], 65 | ``` 66 | 67 | ## Testing 68 | 69 | ```bash 70 | composer test 71 | ``` 72 | 73 | ## Changelog 74 | 75 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 76 | 77 | ## Contributing 78 | 79 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 80 | 81 | ## Security Vulnerabilities 82 | 83 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 84 | 85 | ## Credits 86 | 87 | - [huynt57](https://github.com/huynt57) 88 | - [All Contributors](../../contributors) 89 | 90 | ## License 91 | 92 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 93 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "huy-nguyen/laravel-optimize-init-db-connection", 3 | "description": "A package for optimize Laravel init database connection", 4 | "keywords": [ 5 | "huynt57", 6 | "laravel", 7 | "laravel-optimize-init-db-connection" 8 | ], 9 | "homepage": "https://github.com/huy-nguyen/laravel-optimize-init-db-connection", 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "huynt57", 14 | "email": "huynt57@gmail.com", 15 | "role": "Developer" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=7.2", 20 | "illuminate/support": ">=6.0", 21 | "illuminate/database": ">=6.0" 22 | }, 23 | "require-dev": { 24 | "phpunit/phpunit": ">=8.5", 25 | "mockery/mockery": ">=1.3.6" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "Huynt57\\LaravelOptimizeInitDbConnection\\": "src/", 30 | "Huynt57\\LaravelOptimizeInitDbConnection\\Database\\Factories\\": "database/factories/" 31 | } 32 | }, 33 | "autoload-dev": { 34 | "psr-4": { 35 | "Huynt57\\LaravelOptimizeInitDbConnection\\Tests\\": "tests/" 36 | } 37 | }, 38 | "scripts": { 39 | "test": "./vendor/bin/phpunit" 40 | }, 41 | "config": { 42 | "sort-packages": true 43 | }, 44 | "extra": { 45 | "laravel": { 46 | "providers": [ 47 | "Huynt57\\LaravelOptimizeInitDbConnection\\LaravelOptimizeInitDbConnectionServiceProvider" 48 | ], 49 | "aliases": { 50 | "LaravelOptimizeInitDbConnection": "Huynt57\\LaravelOptimizeInitDbConnection\\Facades\\LaravelOptimizeInitDbConnection" 51 | } 52 | } 53 | }, 54 | "minimum-stability": "dev", 55 | "prefer-stable": true 56 | } 57 | -------------------------------------------------------------------------------- /config/optimize-init-db-connection.php: -------------------------------------------------------------------------------- 1 | 'mysql', 6 | ]; 7 | -------------------------------------------------------------------------------- /src/LaravelOptimizeInitDbConnectionServiceProvider.php: -------------------------------------------------------------------------------- 1 | mergeConfigFrom(__DIR__ . "/../config/{$configFileName}.php", $configFileName); 15 | $this->registerDriver(); 16 | } 17 | 18 | public function boot() 19 | { 20 | $configFileName = 'optimize-init-db-connection'; 21 | $this->publishes([ 22 | __DIR__ . "/../config/{$configFileName}.php" => config_path('optimize-init-db-connection.php'), 23 | ]); 24 | } 25 | 26 | private function registerDriver(): void 27 | { 28 | $factory = function ($connection, $database, $prefix, $config) { 29 | return new MySqlConnection($connection, $database, $prefix, $config); 30 | }; 31 | 32 | $driverName = config('optimize-init-db-connection.driver') ?? 'mysql'; 33 | 34 | Connection::resolverFor($driverName, $factory); 35 | 36 | $this->app->bind('db.connector.' . $driverName, OptimizedMySqlConnector::class); 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/OptimizedMySqlConnector.php: -------------------------------------------------------------------------------- 1 | getDsn($config); 13 | 14 | $options = $this->getOptions($config); 15 | 16 | // We need to grab the PDO options that should be used while making the brand 17 | // new connection instance. The PDO options control various aspects of the 18 | // connection's behavior, and some might be specified by the developers. 19 | $connection = $this->createConnection($dsn, $config, $options); 20 | 21 | if (! empty($config['database'])) { 22 | $connection->exec("USE `{$config['database']}`;"); 23 | } 24 | 25 | $this->configureConnection($connection, $config); 26 | 27 | return $connection; 28 | } 29 | 30 | /** 31 | * Configure the connection. 32 | * 33 | * @param \PDO $connection 34 | * @param array $config 35 | * @return void 36 | */ 37 | protected function configureConnection($connection, array $config): void 38 | { 39 | $statements = []; 40 | 41 | // First, we set the transaction isolation level. 42 | if (isset($config['isolation_level'])) { 43 | $statements[] = sprintf('SESSION TRANSACTION ISOLATION LEVEL %s', $config['isolation_level']); 44 | } 45 | 46 | // Now, we set the charset and possibly the collation. 47 | if (isset($config['charset'])) { 48 | if (isset($config['collation'])) { 49 | $statements[] = sprintf("NAMES '%s' COLLATE '%s'", $config['charset'], $config['collation']); 50 | } else { 51 | $statements[] = sprintf("NAMES '%s'", $config['charset']); 52 | } 53 | } 54 | 55 | // Next, we will check to see if a timezone has been specified in this config 56 | // and if it has we will issue a statement to modify the timezone with the 57 | // database. Setting this DB timezone is an optional configuration item. 58 | if (isset($config['timezone'])) { 59 | $statements[] = sprintf("time_zone='%s'", $config['timezone']); 60 | } 61 | 62 | // Next, we set the correct sql_mode mode according to the config. 63 | $sqlMode = $this->getSqlMode($connection, $config); 64 | if (null !== $sqlMode) { 65 | $statements[] = sprintf("SESSION sql_mode='%s'", $sqlMode); 66 | } 67 | 68 | // Finally, execute a single SET command with all our statements. 69 | if ([] !== $statements) { 70 | $connection->exec(sprintf('SET %s;', implode(', ', $statements))); 71 | } 72 | } 73 | 74 | /** 75 | * Get the sql_mode value. 76 | * 77 | * @param \PDO $connection 78 | * @param array $config 79 | * @return string|null 80 | */ 81 | protected function getSqlMode($connection, $config) 82 | { 83 | if (isset($config['modes'])) { 84 | return implode(',', $config['modes']); 85 | } 86 | 87 | if (!isset($config['strict'])) { 88 | return null; 89 | } 90 | 91 | if (!$config['strict']) { 92 | return 'NO_ENGINE_SUBSTITUTION'; 93 | } 94 | 95 | $version = $config['version'] ?? $connection->getAttribute(PDO::ATTR_SERVER_VERSION); 96 | 97 | if (version_compare($version, '8.0.11') >= 0) { 98 | return 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'; 99 | } 100 | 101 | return 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'; 102 | } 103 | 104 | 105 | } 106 | --------------------------------------------------------------------------------