Create and use a custom config/database.php for each module in nWidart/laravel-modules

Viewed 599

Inside every module created with nWidart/laravel-modules there is a Config directory that ships with a config.php file:

<?php
    return [
        'name' => 'Contracts'
    ];

Now, the documentation states that you should write your module's configuration inside this directory, so I placed a database.php file inside with a custom connection for my module, called module1:

<?php
    
    return [
        'default' => env('DB_CONNECTION', 'mysql'),
        'connections' => [
            'module1' => [
                'driver' => 'mysql',
                'url' => env( 'DATABASE_URL' ),
                'host' => env( 'DB_MODULE1_HOST', '127.0.0.1' ),
                'port' => env( 'DB_MODULE1_PORT', '3306' ),
                'database' => env('DB_MODULE1_DATABASE', 'forge'),
                'username' => env( 'DB_MODULE1_USERNAME', 'forge' ),
                'password' => env( 'DB_MODULE1_PASSWORD', '' ),
                'unix_socket' => env( 'DB_MODULE1_SOCKET', '' ),
                'charset' => 'utf8mb4',
                'collation' => 'utf8mb4_unicode_ci',
                'prefix' => '',
                'prefix_indexes' => true,
                'strict' => true,
                'engine' => null,
                'options' => extension_loaded( 'pdo_mysql' ) ?
                    array_filter( [ PDO::MYSQL_ATTR_SSL_CA => env( 'MYSQL_ATTR_SSL_CA' ), ] ) : [],
            ],
        ],
    ];

Inside my .env file in the root of the project (because I have no idea how to create custom enviromentals for my module) I added a couple of lines:

DB_CONNECTION_MODULE1=module1
DB_MODULE1_DATABASE=module1database
DB_MODULE1_USERNAME=root
DB_MODULE1_PASSWORD=password

As an example, one of my migrations looks like this:

<?php

    use Illuminate\Support\Facades\Schema;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Database\Migrations\Migration;

    class CreateObjectivesTable extends Migration{

        /**
         * Run the migrations.
         *
         * @return void
         */
        public function up(){
            Schema::connection( env( 'DB_DATABASE_MODULE1' ) )->create( 'objectives', function( Blueprint $table ){
                $table->id();
                $table->text( 'description' );

                $table->timestamp( 'created_at' )->default( DB::raw( 'CURRENT_TIMESTAMP' ) );
                $table->timestamp( 'updated_at' )->default( DB::raw( 'CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP' ) );
            } );
        }

        /**
         * Reverse the migrations.
         *
         * @return void
         */
        public function down(){
            Schema::connection( env( 'DB_DATABASE_MODULE1' ) )->dropIfExists( 'objectives' );
        }
    }

I was expecting that when I ran my migrations, the module's tables would be created in their own database (module1database) but it didn't work:

Migrating: 2020_11_10_134237_create_objectives_table

    InvalidArgumentException

    Database connection [module1] not configured. 

at \path\to\my\site\vendor\laravel\framework\src\Illuminate\Database\DatabaseManager.php:152
     148▕         // If the configuration doesn't exist, we'll throw an exception and bail.
     149▕         $connections = $this->app['config']['database.connections'];
     150▕
     151▕         if (is_null($config = Arr::get($connections, $name))) {
  ➜ 152▕             throw new InvalidArgumentException("Database connection [{$name}] not configured.");
     153▕         }
     154▕
     155▕         return (new ConfigurationUrlParser)
     156▕                     ->parseConfiguration($config);

  1   \path\to\my\site\vendor\laravel\framework\src\Illuminate\Database\DatabaseManager.php:115
      Illuminate\Database\DatabaseManager::configuration("module1")

  2   \path\to\my\site\vendor\laravel\framework\src\Illuminate\Database\DatabaseManager.php:86
      Illuminate\Database\DatabaseManager::makeConnection("module1")

I guess, I still have to do something to read from Modules\Module1\Config\database.php, any help would be appreciated. I would also like to be able to have my module's enviromentals inside the module (probably something like \Modules\Module1\.env), that would also be much appreciated.

1 Answers

inside registerConfig method in module service provider add this (V6 & higher)

$this->mergeConfigFrom(
      module_path($this->moduleName, 'Config/database.php'),
     'database.connections.module1'
);

for older versions

$this->mergeConfigFrom(
     __DIR__.'/../Config/database.php',
    'database.connections.module1'
);

and edit your Config/database.php file to be like this

return [
            'driver' => 'mysql',
            'url' => env( 'DATABASE_URL' ),
            'host' => env( 'DB_MODULE1_HOST', '127.0.0.1' ),
            'port' => env( 'DB_MODULE1_PORT', '3306' ),
            'database' => env('DB_MODULE1_DATABASE', 'forge'),
            'username' => env( 'DB_MODULE1_USERNAME', 'forge' ),
            'password' => env( 'DB_MODULE1_PASSWORD', '' ),
            'unix_socket' => env( 'DB_MODULE1_SOCKET', '' ),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded( 'pdo_mysql' ) ?
                array_filter( [ PDO::MYSQL_ATTR_SSL_CA => env( 'MYSQL_ATTR_SSL_CA' ), ] ) : [],
];
Related