[9.x] Make stronger assertion before caching commands #40626
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Hi there 👋
Context:
Last year, support for Lazy loading commands was added in Laravel 9 (See #34873).
This means, if the command we're trying to resolve is a valid class, we add it to a
commandMapusing thegetDefaultNamestatic method as a key. Otherwise, we fall back to the previous behaviour which resolves the command from the container.Problem:
The issue here is that the above code assumes
$commandwill always refer to the class name of a SymfonyCommand— i.e.Symfony\Component\Console\Command\Command.However, the previous behaviour allowed us to use
$commandas an abstract that would, later on, be resolved as a valid Symfony or LaravelCommandclass.The new behaviour prevents this by throwing an exception saying the
getDefaultNamestatic method does not exist on the abstract class provided.Concrete example:
The Laravel Actions package leverages the previous behaviour to allow any PHP class to be registered as a command. It is only after the provided abstract is resolved from the container that we get a Laravel
Commandthat decorates the provided PHP class.Solution:
Fortunately, continuing to support the previous behaviour is very simple. We just need a stronger assertion before caching the provided command.
Instead of checking that the class exists — using
class_exists— we can check that the provided class is a subclass of the SymfonyCommand— usingis_subclass_ofwhich also checks that the class exists.