diff --git a/README.md b/README.md index e01f584..1895b36 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ An Elegant wrapper around Symfony's Process component. - [Output to Array](#output-to-array) - [Output Stream (Recommended)](#output-stream) - [Output Lines](#output-lines) + - [Output via Laravel Artisan Command](#output-via-laravel-artisan-command) + - [Output via Symfony Console Command](#output-via-symfony-console-command) - [Throwing Exceptions](#throwing-exceptions) - [Data](#data) - [Working Directory](#working-directory) @@ -104,6 +106,30 @@ Alternatively, you may use the `content` method to get the contents of the line: $line->content(); ``` +### Output via Laravel Artisan Command + +If you run Terminal from the Laravel's Artisan command, you may send the output to the console by +passing an instance of the Command to the `output` method: + +```php +public function handle() +{ + Terminal::output($this)->run('echo Hello, World'); +} +``` + +### Output via Symfony Console Command + +If you run Terminal from the Symfony's Console command, you may send the output to the console by +passing an instance of the OutputInterface to the `output` method: + +```php +protected function execute(InputInterface $input, OutputInterface $output) +{ + Terminal::output($output)->run('echo Hello, World'); +} +``` + ### Throwing Exceptions If you would like to throw an exception when the command is not successful, you may use the `throw` method: diff --git a/src/Builder.php b/src/Builder.php index b668f29..77fa836 100644 --- a/src/Builder.php +++ b/src/Builder.php @@ -158,16 +158,56 @@ public function withEnvironmentVariables(array $environmentVariables) /** * Set output handler. * - * @param callable $output + * @param mixed $output * @return $this */ - public function output(callable $output) + public function output($output) { - $this->output = $output; + $this->output = $this->parseOutput($output); return $this; } + /** + * Parse a given output. + * + * @param mixed $output + * @return callable + */ + protected function parseOutput($output) + { + if (is_callable($output)) { + return $output; + } + + if ($output instanceof \Symfony\Component\Console\Output\OutputInterface) { + return $this->wrapOutput([$output, 'write']); + } + + if ($output instanceof \Illuminate\Console\Command) { + return $this->wrapOutput([$output->getOutput(), 'write']); + } + + throw new InvalidArgumentException(sprintf( + 'Terminal output must be a %s, an instance of "%s" or an instance of "%s" but "%s" was given.', + 'callable', 'Symfony\Component\Console\Output\OutputInterface', 'Illuminate\Console\Command', + ($type = gettype($output)) === 'object' ? get_class($output) : $type + )); + } + + /** + * Wrap output callback. + * + * @param callable $callback + * @return callable + */ + protected function wrapOutput(callable $callback): callable + { + return function ($type, $data) use ($callback) { + return call_user_func($callback, $data); + }; + } + /** * Set input. * diff --git a/tests/BuilderTest.php b/tests/BuilderTest.php index da3a37d..6b5d671 100644 --- a/tests/BuilderTest.php +++ b/tests/BuilderTest.php @@ -289,6 +289,65 @@ public function testToString() ); } + /** + * Test that termina can handle Symfony' OutputInterface. + * + * @return void + */ + public function testOutputAsSymfonyOutputInterface() + { + $output = Mockery::mock('Symfony\Component\Console\Output\OutputInterface', function ($mock) { + $mock->shouldReceive('write') + ->once() + ->with("Hello\n") + ->andReturn(null); + }); + + (new Builder)->output($output)->run('echo Hello'); + } + + /** + * Test that termina can handle Symfony' OutputInterface. + * + * @return void + */ + public function testOutputAsLaravelCommad() + { + $output = Mockery::mock('Illuminate\Console\Command', function ($mock) { + $mock->shouldReceive('getOutput->write') + ->once() + ->with("Hello\n") + ->andReturn(null); + }); + + (new Builder)->output($output)->run('echo Hello'); + } + + /** + * Get invalid outputs. + * + * @return array + */ + public function invalidOutputs(): array + { + return [ + [123], + ['string'], + [new \stdClass], + ]; + } + + /** + * Test Terminal output validation. + * + * @dataProvider invalidOutputs + */ + public function testOutputValidation($output) + { + $this->expectException('InvalidArgumentException'); + (new Builder)->output($value)->run('echo Hello'); + } + /** * Create a new builder instance with a mocked process instance. *