Skip to content

Commit

Permalink
Merge 79f2372 into 21d36bf
Browse files Browse the repository at this point in the history
  • Loading branch information
weierophinney committed Jan 20, 2021
2 parents 21d36bf + 79f2372 commit 15f2277
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 8 deletions.
51 changes: 51 additions & 0 deletions docs/book/events.md
@@ -0,0 +1,51 @@
# Events

The [symfony/console component](https://symfony.com/doc/current/components/console.html) allows attaching an event dispatcher instance to a console application.
During the lifetime of a console command, the application will trigger a number of events, to which you may subscribe listeners.
Internally, laminas/laminas-cli itself adds a listener on the `Symfony\Component\Console\ConsoleEvents::TERMINATE` event in order to provide [command chains](command-chains.md).

If you wish to subscribe to any of the various symfony/console events, you will need to provide an alternate event dispatcher instance.
You may do so by defining a `Laminas\Cli\SymfonyEventDispatcher` service in your container that resolves to a `Symfony\Component\EventDispatcher\EventDispatcherInterface` instance. (We use this instead of the more generic `Symfony\Contracts\EventDispatcher\EventDispatcherInterface` so that we can use its `addListener()` method to subscribe our own listener.)

As an example, your container configuration file might look like the following for laminas-mvc applications.
Create a configuration file named `config/autoload/console.global.php` if it does not already exist, and ensure the following contents are present:

```php
return [
'service_manager' => [
'factories' => [
'Laminas\Cli\SymfonyEventDispatcher' => \Your\Custom\DispatcherFactory::class,
// ...
],
'delegators' => [
'Laminas\Cli\SymfonyEventDispatcher' => [
// [OPTIONAL] Delegator factories for adding listeners and/or subscribers
],
// ...
],
// ...
],
// ...
];
```

If you are in a Mezzio application, again, create a configuration file named `config/autoload/console.global.php` if it does not already exist, and ensure the following contents are present:

```php
return [
'dependencies' => [
'factories' => [
'Laminas\Cli\SymfonyEventDispatcher' => \Your\Custom\DispatcherFactory::class,
// ...
],
'delegators' => [
'Laminas\Cli\SymfonyEventDispatcher' => [
// [OPTIONAL] Delegator factories for adding listeners and/or subscribers
],
// ...
],
// ...
],
// ...
];
```
1 change: 1 addition & 0 deletions mkdocs.yml
Expand Up @@ -6,6 +6,7 @@ nav:
- Command Chains: command-chains.md
- Command Params: command-params.md
- Autocompletion: autocompletion.md
- Events: events.md
site_name: laminas-cli
site_description: 'Command-line interface for Laminas projects'
repo_url: 'https://github.com/laminas/laminas-cli'
Expand Down
8 changes: 7 additions & 1 deletion src/ApplicationFactory.php
Expand Up @@ -16,6 +16,7 @@
use Symfony\Component\Console\Application;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Webmozart\Assert\Assert;

use function strstr;
Expand All @@ -40,7 +41,12 @@ public function __invoke(ContainerInterface $container): Application
Assert::isMap($commands);
Assert::allString($commands);

$dispatcher = new EventDispatcher();
$eventDispatcherServiceName = __NAMESPACE__ . '\SymfonyEventDispatcher';
$dispatcher = $container->has($eventDispatcherServiceName)
? $container->get($eventDispatcherServiceName)
: new EventDispatcher();
Assert::isInstanceOf($dispatcher, EventDispatcherInterface::class);

$dispatcher->addListener(ConsoleEvents::TERMINATE, new TerminateListener($config));

$application = new Application('laminas', $version);
Expand Down
60 changes: 60 additions & 0 deletions test/ApplicationFactoryTest.php
@@ -0,0 +1,60 @@
<?php

/**
* @see https://github.com/laminas/laminas-cli for the canonical source repository
* @copyright https://github.com/laminas/laminas-cli/blob/master/COPYRIGHT.md
* @license https://github.com/laminas/laminas-cli/blob/master/LICENSE.md New BSD License
*/

declare(strict_types=1);

namespace LaminasTest\Cli;

use Laminas\Cli\ApplicationFactory;
use Laminas\Cli\Listener\TerminateListener;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

/** @psalm-suppress PropertyNotSetInConstructor */
class ApplicationFactoryTest extends TestCase
{
public function testPullsEventDispatcherFromContainerWhenPresent(): void
{
$config = [
'laminas-cli' => [],
];

$dispatcher = $this->createMock(EventDispatcherInterface::class);
$dispatcher
->expects($this->once())
->method('addListener')
->with(
ConsoleEvents::TERMINATE,
$this->isInstanceOf(TerminateListener::class)
);

$container = $this->createMock(ContainerInterface::class);
$container
->expects($this->once())
->method('has')
->with('Laminas\Cli\SymfonyEventDispatcher')
->willReturn(true);
$container
->expects($this->exactly(2))
->method('get')
->withConsecutive(
['config'],
['Laminas\Cli\SymfonyEventDispatcher']
)
->willReturnOnConsecutiveCalls(
$config,
$dispatcher
);

/** @psalm-suppress InternalClass */
$this->assertInstanceOf(Application::class, (new ApplicationFactory())($container));
}
}
24 changes: 17 additions & 7 deletions test/ApplicationTest.php
Expand Up @@ -475,7 +475,13 @@ public function testParamInput(): void
public function testParamInputNonInteractiveMissingParameter(): void
{
$container = $this->createMock(ContainerInterface::class);
$container->method('has')->with(ParamCommand::class)->willReturn(true);
$container
->expects($this->atLeast(2))
->method('has')
->willReturnMap([
['Laminas\Cli\SymfonyEventDispatcher', false],
[ParamCommand::class, true],
]);
$container->method('get')->willReturnMap([
[
'config',
Expand Down Expand Up @@ -528,10 +534,12 @@ public function testListIncludesCommandWithDependencies(): void
/** @psalm-var ContainerInterface&\PHPUnit\Framework\MockObject\MockObject $container */
$container = $this->createMock(ContainerInterface::class);
$container
->expects($this->atLeastOnce())
->expects($this->atLeast(2))
->method('has')
->with($this->equalTo(ExampleCommandWithDependencies::class))
->willReturn(true);
->willReturnMap([
['Laminas\Cli\SymfonyEventDispatcher', false],
[ExampleCommandWithDependencies::class, true],
]);

$container
->method('get')
Expand Down Expand Up @@ -587,10 +595,12 @@ public function testHelpDisplaysInformationForCommandWithDependencies(): void
$container = $this->createMock(ContainerInterface::class);

$container
->expects($this->atLeastOnce())
->expects($this->atLeast(2))
->method('has')
->with($this->equalTo(ExampleCommandWithDependencies::class))
->willReturn(true);
->willReturnMap([
['Laminas\Cli\SymfonyEventDispatcher', false],
[ExampleCommandWithDependencies::class, true],
]);

$container
->method('get')
Expand Down

0 comments on commit 15f2277

Please sign in to comment.