When first implemented, a lot of logic had to be recreated from the symfony/console package because it expects the application to be a Symfony\Component\Console\Application object and we couldn't do that because the expectation in the Joomla ecosystem is all applications are a subclass of Joomla\Application\AbstractApplication, and PHP being what it is you can't have two parent classes. Thanks to https://github.com/joomla-framework/application/pull/83 though, we can use an interface for Joomla applications and therefore have our application subclass both extend the Symfony application and declare itself a Joomla application by implementing the interface. Now, all the extra code needed (which is legitimately 99% of this package) because we couldn't subclass the Symfony application is not needed, and we're refactored to the minimum implementation needed.
Two other challenges present themselves in this approach, one of which has been addressed and the other needing an upstream solution in joomla/application.
First, the Symfony application typehints Symfony\Component\EventDispatcher\EventDispatcherInterface for the event dispatcher and uses Symfony\Component\EventDispatcher\Event as the root for its event classes. This is not compatible with Joomla\Event\DispatcherInterface and Joomla\Event\EventInterface. To address this issue, a new event dispatcher bridge package is created which allows the Symfony dispatcher to dispatch events to the Joomla API and vice-versa (maybe one day PSR-14 makes this a little easier to pull off).
Second, there is a naming conflict between Symfony\Component\Console\Application::get($name) and Joomla\Application\ConfigurationAwareApplicationInterface::get($name, $default). The Symfony method is used to get a Command class object while the Joomla method is used to read a value from the injected configuration Registry. That one isn't addressed yet and before a tag on the joomla/application repository can be made with the interfaces we need to figure something out here, so for now our console application can't be made configuration aware.
As far as using the event dispatcher bridge goes, see the below example. The rest is left to the bridge's internals.
require __DIR__ . '/vendor/autoload.php';
$decoratedDispatcher = new \Joomla\Event\Dispatcher;
$dispatcher = new \Joomla\SymfonyEventDispatcherBridge\Joomla\Dispatcher($decoratedDispatcher);
$dispatcher->addListener(\Symfony\Component\Console\ConsoleEvents::COMMAND, function (\Symfony\Component\EventDispatcher\Event $event) {
/*
* $event is an instance of `Joomla\SymfonyEventDispatcherBridge\Symfony\Event` decorating `Symfony\Component\Console\Event\ConsoleCommandEvent`
*/
/** @var \Symfony\Component\Console\Output\OutputInterface $output */
$output = $event->getOutput();
$output->writeln('<comment>Before command execute event triggered.</comment>');
});
$dispatcher->addListener(\Symfony\Component\Console\ConsoleEvents::ERROR, function (\Symfony\Component\EventDispatcher\Event $event) {
/*
* $event is an instance of `Joomla\SymfonyEventDispatcherBridge\Symfony\Event` decorating `Symfony\Component\Console\Event\ConsoleErrorEvent`
*/
/** @var \Symfony\Component\Console\Output\OutputInterface $output */
$output = $event->getOutput();
$event->getOutput()->writeln('<comment>Error event triggered.</comment>');
});
$dispatcher->addListener(\Symfony\Component\Console\ConsoleEvents::TERMINATE, function (\Symfony\Component\EventDispatcher\Event $event) {
/*
* $event is an instance of `Joomla\SymfonyEventDispatcherBridge\Symfony\Event` decorating `Symfony\Component\Console\Event\ConsoleTerminateEvent`
*/
/** @var \Symfony\Component\Console\Output\OutputInterface $output */
$output = $event->getOutput();
$event->getOutput()->writeln('<comment>Terminate event triggered.</comment>');
});
$app = new \Joomla\Console\Application;
$app->setName('Console Tester');
$app->setDispatcher($dispatcher);
/*
* Undocumented in the method signature, but this method call supports the same arguments as `Symfony\Component\Console\Application::run()`
*/
$app->execute();
When first implemented, a lot of logic had to be recreated from the
symfony/console
package because it expects the application to be aSymfony\Component\Console\Application
object and we couldn't do that because the expectation in the Joomla ecosystem is all applications are a subclass ofJoomla\Application\AbstractApplication
, and PHP being what it is you can't have two parent classes. Thanks to https://github.com/joomla-framework/application/pull/83 though, we can use an interface for Joomla applications and therefore have our application subclass both extend the Symfony application and declare itself a Joomla application by implementing the interface. Now, all the extra code needed (which is legitimately 99% of this package) because we couldn't subclass the Symfony application is not needed, and we're refactored to the minimum implementation needed.Two other challenges present themselves in this approach, one of which has been addressed and the other needing an upstream solution in
joomla/application
.First, the Symfony application typehints
Symfony\Component\EventDispatcher\EventDispatcherInterface
for the event dispatcher and usesSymfony\Component\EventDispatcher\Event
as the root for its event classes. This is not compatible withJoomla\Event\DispatcherInterface
andJoomla\Event\EventInterface
. To address this issue, a new event dispatcher bridge package is created which allows the Symfony dispatcher to dispatch events to the Joomla API and vice-versa (maybe one day PSR-14 makes this a little easier to pull off).Second, there is a naming conflict between
Symfony\Component\Console\Application::get($name)
andJoomla\Application\ConfigurationAwareApplicationInterface::get($name, $default)
. The Symfony method is used to get a Command class object while the Joomla method is used to read a value from the injected configuration Registry. That one isn't addressed yet and before a tag on thejoomla/application
repository can be made with the interfaces we need to figure something out here, so for now our console application can't be made configuration aware.As far as using the event dispatcher bridge goes, see the below example. The rest is left to the bridge's internals.