You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a follow-up of #401, #406 and #407 as all of them are symptoms of the very same issue.
Description
Commands which aren not intended to be visible (such as the TestCommand and commands in the commands.hidden setting) are visible in the production environment.
Furthermore, lazy loaded commands aren't scheduled by laravel-zero as pointed out in #406.
Steps to reproduce
Create a laravel-zero/laravel-zero with laravel/frameworkv9.1.1 in it.
Make sure that the hidden-setting in config/commands.php contains at least one command
Build the application php ./application app:build
Run the application php ./builds/application
Take note that all commands - even the hidden ones and the TestCommand - are listed
Also - take note, that some commands aren't scheduled
Actual Behavior
Test- and Development commands are visible even when executing the command in production environment.
Commands should be scheduled.
Expected Behavior
Commands which are supposed to be used for testing and development should not be visible.
Some commands aren't scheduled.
Workaround
Add a customized kernel class which inherits LaravelZero\Framework\Kernel with the following content: ./app/Framework/MyKernel.php:
<?phpnamespaceApp\Framework;
useIlluminate\Console\Application;
useIlluminate\Support\Collection;
useLaravelZero\Framework\Commands\CommandasLaravelZeroCommand;
useLaravelZero\Framework\Kernel;
useNunoMaduro\Collision\Adapters\Laravel\Commands\TestCommand;
useReflectionClass;
useSymfony\Component\Console\ApplicationasSymfonyApplication;
useSymfony\Component\Console\Command\Command;
useSymfony\Component\Console\Input\InputOption;
{
/** * Provides the functionality to handle the execution of a command line interface. */classMyKernelextendsKernel
{
/** * {@inheritdoc} */publicfunctiongetArtisan(): Application
{
if (is_null($this->artisan))
{
$artisan = newApplication($this->app, $this->events, $this->app->version());
$artisan->resolveCommands($this->commands);
$commandsProperty = (newReflectionClass(SymfonyApplication::class))->getProperty('commands');
$commandMapProperty = (newReflectionClass(Application::class))->getProperty('commandMap');
/** @var Collection<string, string> */$commandMap = collect($commandMapProperty->getValue($artisan));
/** @var string[] */$commands = $commandsProperty->getValue($artisan);
$toRemove = collect($commandMap)->filter(function (string$commandClass)
{
return$commandClass == TestCommand::class || in_array($commandClass, config('commands.remove'));
});
$availableCommands = $commandMap->diff($toRemove);
$property->setAccessible(true); // Not necessary in PHP >= 8.1$commandMapProperty->setValue($artisan, $availableCommands->toArray());
$property->setAccessible(false); // Not necessary in PHP >= 8.1$artisan->setContainerCommandLoader();
collect($artisan->all())->each(function (Command$command) use ($commands)
{
if (in_array($command::class, config('commands.hidden', []), true))
{
$command->setHidden(true);
}
if (
$command instanceof LaravelZeroCommand &&
!in_array($command::class, $commands)
)
{
$this->app->call([$command, 'schedule']);
}
});
$this->artisan = $artisan;
}
returnparent::getArtisan();
}
}
}
Next, replace laravel-zeros Kernel with your newly created custom kernel by editing the Kernel singleton in your ./bootstrap/app.php file:
Create a new Artisan instance
Don't get confused, the class is called Application in this code snippet
Add all commands from the Kernel::$commands array
This array has been filtered by laravel-zeros Kernel class, so there are no unwanted commands in this array for sure.
Remove unwanted commands which are queued for a lazy load in the commandMap
Enable lazy loading (using the setContainerCommandLoader() method)
Hide commands which are marked for hiding
This will work now as $artisan->all() returns all commands (even the ones queued for lazy-loading) after enabling lazy loading.
Schedule commands which haven't been scheduled before
Only commands which are present in the Artisan::$commands array are scheduled by laravel-zero. Thus, scheduling all commands which aren't in the array should fix this issue.
What's more, as lazy loaded commands aren't even stored in Artisan::$commands but rather in Artisan::$commandMap, lines 192-197 in particular won't work in this point of view at all.
As pointed out in issue #406, scheduling doesn't work either cause of this issue (see line 222-224 in previously linked snippet).
A Few Last Words
I just wanted to point out that this is not some sort of a rant at all. I've been looking for some neat way to create PHP CLIs as I want to clean up an existing php project and I'm amazed about this great piece of work!
Thanks for your great work! I deeply hope my research will help to improve this project even further 😄
Edit: Added info & workaround for command scheduling
The text was updated successfully, but these errors were encountered:
This is a follow-up of #401, #406 and #407 as all of them are symptoms of the very same issue.
Description
Commands which aren not intended to be visible (such as the
TestCommand
and commands in thecommands.hidden
setting) are visible in theproduction
environment.Furthermore, lazy loaded commands aren't scheduled by
laravel-zero
as pointed out in #406.Steps to reproduce
laravel-zero/laravel-zero
withlaravel/framework
v9.1.1
in it.hidden
-setting inconfig/commands.php
contains at least one commandphp ./application app:build
php ./builds/application
TestCommand
- are listedActual Behavior
Test- and Development commands are visible even when executing the command in production environment.
Commands should be scheduled.
Expected Behavior
Commands which are supposed to be used for testing and development should not be visible.
Some commands aren't scheduled.
Workaround
Add a customized kernel class which inherits
LaravelZero\Framework\Kernel
with the following content:./app/Framework/MyKernel.php:
Next, replace
laravel-zero
sKernel
with your newly created custom kernel by editing theKernel
singleton in your ./bootstrap/app.php file:After editing the ./bootstrap/app.php file, the
Kernel
singleton should look like this:Here's what it does:
Artisan
instanceDon't get confused, the class is called
Application
in this code snippetKernel::$commands
arrayThis array has been filtered by
laravel-zero
sKernel
class, so there are no unwanted commands in this array for sure.commandMap
setContainerCommandLoader()
method)This will work now as
$artisan->all()
returns all commands (even the ones queued for lazy-loading) after enabling lazy loading.Only commands which are present in the
Artisan::$commands
array are scheduled bylaravel-zero
. Thus, scheduling all commands which aren't in the array should fix this issue.My workaround is based on @owenvoke's recommendation pointed out in #401 which can be seen in his repository:
https://github.com/owenvoke/rugby-schedule/blob/bbb78284980294f4dc288ff4da48d44c07c4e3d6/app/Providers/AppServiceProvider.php#L18-L22
More Context
As seen in the
laravel/framework
-repository, commands aren't added to theArtisan::$commands
-array directly but rather are queued in theArtisan::$commandMap
for a lazy load:https://github.com/laravel/framework/blob/6463e1c90d73faf58b57d98f27eb5c3f5264138e/src/Illuminate/Console/Application.php#L270-L274
Then again, in
laravel-zero/foundation
, theArtisan::starting
-bootstrapers are called first (through theArtisan
-constructor call, line 330) and the lazy command loader is injected only afterwards (setContainerCommandLoader()
at line 332):https://github.com/laravel-zero/foundation/blob/88f6f9e828294949b6c56f07e9046c8e98eb62c9/src/Illuminate/Foundation/Console/Kernel.php#L329-L333
With the lazy command loader not injected, filtering commands as seen in
laravel-zero/framework
is not possible:https://github.com/laravel-zero/framework/blob/e9bdb5e1338c4c874be9cb6c902c5fbc5a58e02e/src/Kernel.php#L183-L197
What's more, as lazy loaded commands aren't even stored in
Artisan::$commands
but rather inArtisan::$commandMap
, lines 192-197 in particular won't work in this point of view at all.Furthermore, hiding commands as seen in the
Kernel
class oflaravel-zero/framework
doesn't work either, as$artisan->all()
only contains all commands once the lazy command loader has been injected usingsetContainerCommandLoader()
:https://github.com/laravel-zero/framework/blob/e9bdb5e1338c4c874be9cb6c902c5fbc5a58e02e/src/Kernel.php#L214-L226
As pointed out in issue #406, scheduling doesn't work either cause of this issue (see line 222-224 in previously linked snippet).
A Few Last Words
I just wanted to point out that this is not some sort of a rant at all. I've been looking for some neat way to create PHP CLIs as I want to clean up an existing php project and I'm amazed about this great piece of work!
Thanks for your great work! I deeply hope my research will help to improve this project even further 😄
The text was updated successfully, but these errors were encountered: