Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to run migrations on database created when tenant is created ? #100

Closed
Adesin-fr opened this issue Jul 31, 2020 · 18 comments
Closed

How to run migrations on database created when tenant is created ? #100

Adesin-fr opened this issue Jul 31, 2020 · 18 comments

Comments

@Adesin-fr
Copy link

Hi

I'm struggling a bit with this !
I got my database created automatically when a tenant is created, with an Event listener on my Tenant model :

        static::created(function (UserTenant $model) {
            $model->createDatabase();
        });

       // ....
    public function createDatabase()
    {
      DB::connection()->statement("CREATE DATABASE " . $this->getDatabaseName() );

     Artisan::call('tenants:artisan "migrate --database=tenant" --tenant=' . $this->id);

and I tried to add some call to the Artisan command from this function, so the table are migrated, but I get an error :
'There are no commands defined in the "migrate" namespace.'

Thanks for your help !

@ArtisanTinkerer
Copy link

This is working for me:

Artisan::call("tenants:artisan \"migrate --database=tenant\" --tenant={$tenant->id}");

@Adesin-fr
Copy link
Author

Thanks for you reply,

That seems to be the same line than mine, except you used double quotes...
Where are you running this code in ?
I do in my Tenant Model, which is not based on Command class. Perhaps your is located in a command ?

@ArtisanTinkerer
Copy link

I think it is the quotes, try it like mine. If I use your line in my code, I get the same error.

@masterix21
Copy link
Collaborator

@LemarinelNet seems to be a parameters problem. Try with:

Artisan::call('tenants:artisan', [
    "artisanCommand" => "migrate --database=tenant",
    "--tenant" => $this->id,
]);

@Adesin-fr
Copy link
Author

Still the same error :
Symfony/Component/Console/Exception/NamespaceNotFoundException with message 'There are no commands defined in the "migrate" namespace.'

My full class is :

<?php

namespace App;

use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Spatie\Multitenancy\Models\Tenant;

class UserTenant extends Tenant
{
    protected $table = "tenants";

    public static function booted()
    {
        static::created(function (UserTenant $model) {
            $model->createDatabase();
        });
    }

    public function createDatabase()
    {
        $this->database = "tenantdb_" . uniqid();
        $this->save();

        $db = DB::connection();

        $charset = $db->getConfig('charset');
        $collation = $db->getConfig('collation');

        $db->statement('CREATE DATABASE ' . $this->getDatabaseName() . " CHARACTER SET `$charset` COLLATE `$collation`");

        Artisan::call('tenants:artisan', [
            "artisanCommand" => "migrate --database=tenant",
            "--tenant" => $this->id,
        ]);
    }

}

Could it be that the Artisan is searching a "migrate" command in the current namespace App, but it only exists in the App\Console\Commands namespace ?

@masterix21
Copy link
Collaborator

I don't know why it happens, but can you try to execute the following code before your migrations?

Application::starting(function ($artisan) { 
    $artisan->resolveCommands([ 
        \Illuminate\Database\Console\Migrations\MigrateCommand::class,
    ]);
});

@Adesin-fr
Copy link
Author

Hi,
This command doesn't fail, but doesn't resolve to anything and doesn't return anything ?
What should it do ?
Placing it before my migration command still doesn't resolve the error.

@masterix21
Copy link
Collaborator

masterix21 commented Aug 2, 2020

It says to your application how to resolve the migration command. I had a similar problem fixed using the suggested code.

I think that your problem isn't package-dependent, sorry.

@Adesin-fr
Copy link
Author

Finaly solved it !
My initial code was in fact working, but the issue was from Tinker, which doesn't allow migrate commands in the shell (see laravel/tinker#37).
Tinker has a white list of allowed commands to be run, and migrate is not among them !
So, it was working from the application (web user registration), but not from tinker !

I removed the "Application::starting" part that you suggested, since it was making my code failing, and just the Artisan::call did the trick !

Thanks for your help anyway ;)

@masterix21
Copy link
Collaborator

Great! Thanks for your share

@schiffty
Copy link

@LemarinelNet Thanks for the tip on the whitelist, that solved my problem too.

One question, when you added migrate:install to the whitelist, did you do it through TinkerCommand.php or through the tinker.php config file? I kept getting a resolution error when trying to do it the "right" way by adding the InstallCommand class to tinker.php, so I fell back to adding migrate:install directly to TinkerCommand.php to get it working and just want to confirm I'm not missing something obvious. Thanks.

@joselara
Copy link

joselara commented Sep 3, 2020

I'm having the same issue using Artisan call method inside the console. It looks like it has something todo with tinker itself.

Symfony/Component/Console/Exception/NamespaceNotFoundException with message 'There are no commands defined in the "migrate" namespace.'

 Artisan::call('tenants:artisan', [
     "artisanCommand" => 'migrate --path=database/migrations/tenant --database=tenant',
     "--tenant" => $this->id
])

@masterix21
Copy link
Collaborator

@joselara are you calling the migration from tinker or with a console command? Please post your code.

Thanks

@michaelhume
Copy link

Hi @schiffty, et. al.. - did you ever resolve your question? I've landed here having the same issue. I've tried to add

'commands' => [
        \Illuminate\Database\Console\Migrations\MigrateCommand::class,
        \Spatie\Multitenancy\Commands\TenantsArtisanCommand::class,
    ],

to tinker.php without any luck. I still get the 'There are no commands defined in the "migrate" namespace.' error when trying to run code that contains Artisan::call from within tinker.

@masterix21 - my code is inside a job that is being triggered within tinker when creating a new tenant.

@masterix21
Copy link
Collaborator

Hi @michaelhume, if you can, please share your code in a testable GitHub repository: I'll take a look asap.

@michaelhume
Copy link

Thanks @masterix21 - I'm digging into it a bit more and will certainly post either a solution or a testable repo.

@michaelhume
Copy link

I was able to sort it all out. There were a number of small configuration issues but ultimately attempting to use a database queue driver in a multitenant setup and dispatching jobs on new models that don't yet have a database gets a bit hairy.

Thanks!

@michaelhume
Copy link

michaelhume commented Nov 26, 2021

Hi @masterix21 - Just to add a bit to this as it is coming up again for me. I've posted a question over on laracasts as well, but wanted to mention here as I suspect this may be related to this issue.

TLDR - I believe 'There are no commands defined in the "migrate" namespace.' is a red herring and the issue is actually somehow with the Migrator database connection. I can toggle this error by manipulating app('migrator')->setConnection() and running migrate in tinker. By setting to the tenant connection, I always get the error, and can clear it be setting the landlord connection. This is regardless of having a current tenant, or fixing a tenant DB_DATABASE in config.

I don't think it's really a package issue because this works when not in tinker, but I'm just wondering if anyone else has run into this or has any insight into what might be happening here? I'd like to understand why the different behaviour inside tinker.

[edit] laravel/tinker#136

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants