lorisleiva / laravel-actions

⚡️ Laravel components that take care of one specific task
https://laravelactions.com
MIT License
2.49k stars 121 forks source link

Error when registering commands in the service provider of a package #197

Open Patabugen opened 2 years ago

Patabugen commented 2 years ago

I'm developing a Laravel package which uses Actions to be used AsClass and AsCommand.

When I try to register the commands in my service provider I get an error: because the commands method wants a Symphony Command and obviously my Action is not. one of those.

I looked into the CommandDecorator but I don't think that would work either.

Is this a bug/problem to solve, or is there already a way to register an Action as a command with Laravel Actions?

use Courier\Console\Commands\InstallCommand;
use Courier\Console\Commands\NetworkCommand;

/**
 * Bootstrap any package services.
 *
 * @return void
 */
public function boot()
{
    if ($this->app->runningInConsole()) {
        $this->commands([
            InstallCommand::class,
            NetworkCommand::class,
        ]);
    }
}
1) Patabugen\MssqlChanges\Tests\ListTablesTest::test_we_can_list_tables_from_artisan
TypeError: Illuminate\Console\Application::add(): Argument #1 ($command) must be of type Symfony\Component\Console\Command\Command, Patabugen\MssqlChanges\Actions\ListTableChanges given, called in /home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Console/Application.php on line 280

/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Console/Application.php:242
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Console/Application.php:280
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Console/Application.php:294
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Support/ServiceProvider.php:404
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Console/Application.php:161
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Console/Application.php:82
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php:395
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php:328
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:338
/home/sami/laravel-mssql-changes/tests/ListTablesTest.php:39
leandrodiogenes commented 2 years ago

Hi @Patabugen. You have to register the commands using this on your service provider.

Actions::registerCommands();

Take a time to read this session on docs https://laravelactions.com/2.x/execute-as-commands.html#command-signature-and-options

Patabugen commented 2 years ago

Ah sorry, I should have included that step!

I did a bunch of fiddling and source diving earlier to see why that wasn't working, and I wasn't sure if it might have an issue running in TestBench, perhaps?

When I use registerCommands() I get this:

$ vendor/bin/phpunit --filter=test_we_can_list_tables_from_artisan
PHPUnit 9.5.25 #StandWithUkraine

Runtime:       PHP 8.0.23
Configuration: /home/sami/laravel-mssql-changes/phpunit.xml
Random Seed:   1664459647
Warning:       No code coverage driver available

E                                                                   1 / 1 (100%)

Time: 00:00.086, Memory: 18.00 MB

There was 1 error:

1) Patabugen\MssqlChanges\Tests\ListTablesTest::test_we_can_list_tables_from_artisan
LogicException: You must call one of in() or append() methods before iterating over a Finder.

/home/sami/laravel-mssql-changes/vendor/symfony/finder/Finder.php:611
/home/sami/laravel-mssql-changes/vendor/lorisleiva/lody/src/LodyManager.php:49
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php:729
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php:413
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php:1506
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php:413
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php:1506
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php:413
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php:1506
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php:413
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Collections/Traits/EnumeratesValues.php:261
/home/sami/laravel-mssql-changes/vendor/lorisleiva/laravel-actions/src/ActionManager.php:130
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:338
/home/sami/laravel-mssql-changes/src/MssqlChangesServiceProvider.php:20
/home/sami/laravel-mssql-changes/vendor/spatie/laravel-package-tools/src/PackageServiceProvider.php:26
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:689
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php:75
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:666
/home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/RegisterProviders.php:17
/home/sami/laravel-mssql-changes/vendor/orchestra/testbench-core/src/Concerns/CreatesApplication.php:324
/home/sami/laravel-mssql-changes/vendor/orchestra/testbench-core/src/Concerns/CreatesApplication.php:222
/home/sami/laravel-mssql-changes/vendor/orchestra/testbench-core/src/TestCase.php:80
/home/sami/laravel-mssql-changes/vendor/orchestra/testbench-core/src/Concerns/Testing.php:82
/home/sami/laravel-mssql-changes/vendor/orchestra/testbench-core/src/TestCase.php:48
/home/sami/laravel-mssql-changes/tests/TestCase.php:13

I also tried passing in the path (since the default "app/Actions" doesn't exist in my package) both as a relative path and an absolute one but both gave similar errors.

I didn't save those specific errors/investigations unfortunately, but it that should work with TestBench then I can run through them again.

nguyentrongthien commented 1 year ago

Hello, do we have any update on this issue? I ran into this exact problem when deploying my Laravel app. Artisan could not run because of registerCommands() in AppServiceProvider.php. It threw the exact same exception and stack trace that @Patabugen posted.

leandrodiogenes commented 1 year ago

Hi @nguyentrongthien, do you have any repo that i can see the error?

nguyentrongthien commented 1 year ago

Hi @leandrodiogenes , this is the Laravel app I am working on. On my dev environment which is Windows with Laragon, php 8.1.11 and Laravel 9.36.4 I have no issue at all. But when I deployed this to the Ubuntu remote server, which is Ubuntu 20.04.4 with php 8.1.13, running php composer install will throw the error when the script attempted to run php artisan optimize.

I am still wracking my brain as to why this could happen because the lock file should ensure that I have exact same dependencies in both environment and yet only my production environment encountered this error. The only workaround I found for now is to comment out registerCommands() and then run php composer install. In fact, this error appears whenever an Artisan command is run.

Here is one of my stack traces

[2023-01-16 10:25:24] production.ERROR: You must call one of in() or append() methods before iterating over a Finder. {"exception":"[object] (LogicException(code: 0): You must call one of in() or append() methods before iterating over a Finder. at /var/www/my-toolbox-backend/vendor/symfony/finder/Finder.php:611)
[stacktrace]
#0 /var/www/my-toolbox-backend/vendor/lorisleiva/lody/src/LodyManager.php(50): Symfony\\Component\\Finder\\Finder->getIterator()
#1 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php(729): Lorisleiva\\Lody\\LodyManager->Lorisleiva\\Lody\\{closure}()
#2 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php(413): Illuminate\\Support\\LazyCollection->Illuminate\\Support\\{closure}()
#3 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php(1506): Illuminate\\Support\\LazyCollection->Illuminate\\Support\\{closure}()
#4 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php(413): Illuminate\\Support\\LazyCollection->Illuminate\\Support\\{closure}()
#5 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php(1506): Illuminate\\Support\\LazyCollection->Illuminate\\Support\\{closure}()
#6 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php(413): Illuminate\\Support\\LazyCollection->Illuminate\\Support\\{closure}()
#7 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php(1506): Illuminate\\Support\\LazyCollection->Illuminate\\Support\\{closure}()
#8 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Collections/LazyCollection.php(413): Illuminate\\Support\\LazyCollection->Illuminate\\Support\\{closure}()
#9 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Collections/Traits/EnumeratesValues.php(261): Illuminate\\Support\\LazyCollection->Illuminate\\Support\\{closure}()
#10 /var/www/my-toolbox-backend/vendor/lorisleiva/laravel-actions/src/ActionManager.php(130): Illuminate\\Support\\LazyCollection->each()
#11 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php(338): Lorisleiva\\Actions\\ActionManager->registerCommands()
#12 /var/www/my-toolbox-backend/app/Providers/AppServiceProvider.php(28): Illuminate\\Support\\Facades\\Facade::__callStatic()
#13 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): App\\Providers\\AppServiceProvider->boot()
#14 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Container/Util.php(41): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()
#15 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(93): Illuminate\\Container\\Util::unwrapIfClosure()
#16 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(37): Illuminate\\Container\\BoundMethod::callBoundMethod()
#17 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Container/Container.php(651): Illuminate\\Container\\BoundMethod::call()
#18 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(933): Illuminate\\Container\\Container->call()
#19 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(914): Illuminate\\Foundation\\Application->bootProvider()
#20 [internal function]: Illuminate\\Foundation\\Application->Illuminate\\Foundation\\{closure}()
#21 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(915): array_walk()
#22 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Foundation/Bootstrap/BootProviders.php(17): Illuminate\\Foundation\\Application->boot()
#23 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(242): Illuminate\\Foundation\\Bootstrap\\BootProviders->bootstrap()
#24 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(383): Illuminate\\Foundation\\Application->bootstrapWith()
#25 /var/www/my-toolbox-backend/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(153): Illuminate\\Foundation\\Console\\Kernel->bootstrap()
#26 /var/www/my-toolbox-backend/artisan(37): Illuminate\\Foundation\\Console\\Kernel->handle()
#27 {main}
"}
leandrodiogenes commented 1 year ago

yeah, in fact I couldn't see the local error, I'll take a deeper look later but I believe it's something related to the domain structure you use in your project.

leandrodiogenes commented 1 year ago

@nguyentrongthien as your project has not a default folder structure, try to register all actions folders instead of only this

Actions::registerCommands('app\Domains');

try this

Actions::registerCommands('app\Domains\Checklist\Actions');
Actions::registerCommands('app\Domains\User\Actions');
...

or

Actions::registerCommands([
    'app\Domains\Checklist\Actions',
    'app\Domains\User\Actions',
]);

Let me know what happens

nguyentrongthien commented 1 year ago

@leandrodiogenes I tried both of the solutions you suggested but it threw the same error. I think it has something to do with the registerCommands() function itself, the arguments don't matter. Maybe it has something to do with https://github.com/lorisleiva/lody?

leandrodiogenes commented 1 year ago

yea @nguyentrongthien the bad part is that i cannot simulate the issue locally 😫

nguyentrongthien commented 1 year ago

yeah, this is what's making me pulling my hair out. My local works perfectly. Only my production that is having issues. I could work around by placing all my command-actions in App/Commands but that would defeat the purpose of my directory structure 😭

cnb-philip commented 1 year ago

We are getting this error all of the sudden, just from adding a new Action with a command signature. we also use a domain org, and have been using the default registerCommand() successfully up until now.

JHWelch commented 1 year ago

I seem to be having this problem as well. Also running TestBench. First got the

LogicException: You must call one of in() or append() methods before iterating over a Finder.

but once I got the path correct it is the

TypeError: Illuminate\Console\Application::add(): Argument #1 ($command) must be of type Symfony\Component\Console\Command\Command, Patabugen\MssqlChanges\Actions\ListTableChanges given, called in /home/sami/laravel-mssql-changes/vendor/laravel/framework/src/Illuminate/Console/Application.php on line 280

error.

ap1969 commented 1 year ago

Hi, I have made a bit of progress in this in my case. I had laravel-actions installed in the parent app and the package, with the "You must call one of in() or append() methods before iterating over a Finder.".

I was calling registerCommands with a number of paths, all with that error.

I uninstalled it from the parent app, and now I have no error as long as I used:

Actions::registerCommands('vendor/<your package path>/src/Actions')

However, I also have no Action files being set up as artisan commands, which I'm looking into

ap1969 commented 1 year ago

Think I've found the problem for me:

  1. Main app is in /var/www/html
  2. Various custom laravel packages are in /var/www/laravel-packages/xxx
  3. Composer in the main app is set up with a repository pointing to the laravel-packages folder.
  4. In LodyManager.php, resolveClassname() uses $file->getRealPath() which points to /var/www/laravel-packages/xxx
  5. But $psr4Resolver->findPrefixes() calls getPsr4Dictionary() which lists those folders as /var/www/html/xxx

Not an easy one to fix without hacking Lody.