From 87719ef15c4ef87017d0dc7474c086d159beeace Mon Sep 17 00:00:00 2001 From: Marco Bellido Date: Mon, 20 Apr 2020 13:33:59 +0200 Subject: [PATCH 1/4] feature: consumer with sqs driver --- .gitattributes | 8 ++ .gitignore | 5 + LICENSE.md | 21 +++ README.md | 128 +++++++++++++++++- composer.json | 58 ++++++++ config/domain_events_messaging.php | 45 ++++++ phpunit.xml.dist | 22 +++ src/Consumer/Console/ConsumeCommand.php | 50 +++++++ src/Consumer/Consumer.php | 92 +++++++++++++ src/Consumer/ConsumerManager.php | 26 ++++ src/Consumer/Contracts/ConsumerContract.php | 16 +++ src/Consumer/Drivers/ConsumerNullDriver.php | 15 ++ src/Consumer/Drivers/ConsumerSqsDriver.php | 79 +++++++++++ src/DomainEventsMessagingServiceProvider.php | 41 ++++++ .../DomainEventsMessagingException.php | 9 ++ src/Facades/DomainEventsMessagingConsumer.php | 13 ++ src/Messages/DomainEventsMessage.php | 28 ++++ tests/Consumer/Console/ConsumeCommandTest.php | 68 ++++++++++ tests/Consumer/ConsumerTest.php | 80 +++++++++++ .../Drivers/ConsumerSqsDriverTest.php | 51 +++++++ tests/Stubs/FakeEvent.php | 18 +++ tests/Stubs/FakeJob.php | 22 +++ tests/Stubs/FakeNotDispatchableEvent.php | 7 + tests/TestCase.php | 16 +++ 24 files changed, 917 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE.md create mode 100644 composer.json create mode 100644 config/domain_events_messaging.php create mode 100644 phpunit.xml.dist create mode 100644 src/Consumer/Console/ConsumeCommand.php create mode 100644 src/Consumer/Consumer.php create mode 100644 src/Consumer/ConsumerManager.php create mode 100644 src/Consumer/Contracts/ConsumerContract.php create mode 100644 src/Consumer/Drivers/ConsumerNullDriver.php create mode 100644 src/Consumer/Drivers/ConsumerSqsDriver.php create mode 100644 src/DomainEventsMessagingServiceProvider.php create mode 100644 src/Exceptions/DomainEventsMessagingException.php create mode 100644 src/Facades/DomainEventsMessagingConsumer.php create mode 100644 src/Messages/DomainEventsMessage.php create mode 100644 tests/Consumer/Console/ConsumeCommandTest.php create mode 100644 tests/Consumer/ConsumerTest.php create mode 100644 tests/Consumer/Drivers/ConsumerSqsDriverTest.php create mode 100644 tests/Stubs/FakeEvent.php create mode 100644 tests/Stubs/FakeJob.php create mode 100644 tests/Stubs/FakeNotDispatchableEvent.php create mode 100644 tests/TestCase.php diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b035b6c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +# Path-based git attributes +# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html + +# Ignore all test and documentation with "export-ignore". +/.gitattributes export-ignore +/.gitignore export-ignore +/phpunit.xml.dist export-ignore +/tests export-ignore \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..56d7960 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/.idea +/vendor +composer.lock +/phpunit.xml +.phpunit.result.cache \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..3e52990 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) GOI + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 6e4afca..ce5882b 100644 --- a/README.md +++ b/README.md @@ -1 +1,127 @@ -# Laravel Domain Events Messaging \ No newline at end of file +# Laravel Domain Events Messaging + +This package allows to send/consume domain message events from your laravel app. This can be used to communicate between services or in the same application via queues. + +It's divided in two main elements: + +- **Publisher**: To publish messages on queue. +- **Consumer**: Read messages from queue and execute jobs/events. + +## Requirements + +- PHP >= 7.2 +- Laravel >= 6.0 + +## Instalation + +- Require package with composer: + +```bash +composer require letsgoi/laravel-domain-events-messaging +``` + +- Publish configuration: + +```bash +php artisan vendor:publish --provider="Letsgoi\DomainEventsMessaging\DomainEventsMessagingServiceProvider" --tag="config" +``` + +Service Provider will be automatically registered, however if you want to add it manually, you must add this to your `config/app.php` file: + +```php +'providers' => [ + // ... + Letsgoi\DomainEventsMessaging\DomainEventsMessagingServiceProvider::class, +]; +``` + +## Usage + +### Publisher + +Work in Progress + +### Consumer + +Domain Events Consumer will consume messages from the queue driver defined on config file (on `DOMAIN_EVENTS_CONSUMER_CONNECTION` env variable) and launch jobs/events setted on config file (`config/domain_events_messaging.php`) by message subject. + +#### Defining events: + +On config file you must set the messages to be consumed and the job/event to be dispatched when this message will be consumed: + +```php +'consumer' => [ + // ... + + 'events' => [ + 'message.subject' => Event::class, + 'message.other' => Job::class, + // ... + ] +] +``` + +When consumer read some message with subject defined on this config, the job/event will be launch with the `array $payload` setted on his constructor. + +#### Jobs/Events + +The class defined on config file to be dispatched on message, could be: + +- Laravel Job: It must use the `Illuminate\Foundation\Bus\Dispatchable` trait. +- Laravel Event: It must use the `Illuminate\Foundation\Events\Dispatchable` trait. + +Both will be receive on his constructor message as string: + +```php +public function __construct(string $message) +``` + +You can queue the jobs as a normal job on Laravel. + +#### Running consumer: + +To run the consumer as a daemon you must execute: + +```bash +php artisan domain-events:consume +``` + +This task should be monitored with some like supervisor to be running on fails. + +## Drivers + +### AWS SNS-SQS + +To use AWS SNS or AWS SQS driver, you must follow this instructions: + +- Add (and fill) this variables on your .env file: + +``` +# AWS IAM +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION= + +# SNS +AWS_SNS_DOMAIN_EVENTS_TOPIC_ARN= + +# SQS +AWS_SQS_DOMAIN_EVENTS_URL= +``` + +## Testing + +Run tests: + + +```bash +composer test +``` + +## Contributing +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. + +Please make sure to update tests as appropriate. + +## License +[MIT](./LICENSE.md) diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..f5ecb57 --- /dev/null +++ b/composer.json @@ -0,0 +1,58 @@ +{ + "name": "letsgoi/laravel-domain-events", + "description": "Package to publish/consume domain events messages from Laravel apps", + "keywords": [ + "goi", + "letsgoi", + "laravel", + "domain", + "events", + "messages", + "queue", + "communication" + ], + "homepage": "https://github.com/letsgoi/laravel-domain-events", + "license": "MIT", + "authors": [ + { + "name": "GOI", + "email": "tech@letsgoi.com" + } + ], + "require": { + "php": ">=7.2", + "illuminate/console": "^6.0|^7.0", + "illuminate/support": "^6.0|^7.0", + "ext-json": "*", + "aws/aws-sdk-php": "^3.134" + }, + "require-dev": { + "phpunit/phpunit": "^8.0", + "orchestra/testbench": "^5.1" + }, + "autoload": { + "psr-4": { + "Letsgoi\\DomainEventsMessaging\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Letsgoi\\DomainEventsMessaging\\Tests\\": "tests" + } + }, + "extra": { + "laravel": { + "providers": [ + "Letsgoi\\DomainEventsMessaging\\DomainEventsMessagingServiceProvider" + ], + "aliases": { + "DomainEventsMessagingConsumer": "Letsgoi\\DomainEventsMessaging\\Facades\\DomainEventsMessagingConsumer" + } + } + }, + "scripts": { + "test": "phpunit" + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/config/domain_events_messaging.php b/config/domain_events_messaging.php new file mode 100644 index 0000000..74a11b2 --- /dev/null +++ b/config/domain_events_messaging.php @@ -0,0 +1,45 @@ + [ + /* + |-------------------------------------------------------------------------- + | Default Domain Event Consumer Connection Name (sqs|null) + |-------------------------------------------------------------------------- + | + */ + + 'default' => env('DOMAIN_EVENTS_CONSUMER_CONNECTION', 'null'), + + /* + |-------------------------------------------------------------------------- + | Domain Event Consumer Connections + |-------------------------------------------------------------------------- + | + */ + + 'connections' => [ + 'sqs' => [ + 'queue_url' => env('AWS_DOMAIN_EVENTS_SQS_URL'), + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'queue' => env('AWS_SQS_URL'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + ], + ], + + + /* + |-------------------------------------------------------------------------- + | Domain Event Consumer Events + | + | Set events/jobs to receive messages on events. + |-------------------------------------------------------------------------- + | + */ + + 'events' => [ +// 'application.event.subject' => EventJob::class, + ], + ], +]; diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..3509b21 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,22 @@ + + + + + tests + + + + + src/ + + + \ No newline at end of file diff --git a/src/Consumer/Console/ConsumeCommand.php b/src/Consumer/Console/ConsumeCommand.php new file mode 100644 index 0000000..f7947d6 --- /dev/null +++ b/src/Consumer/Console/ConsumeCommand.php @@ -0,0 +1,50 @@ +domainEventConsumer = $domainEventConsumer; + } + + public function handle(): void + { + if ($this->downForMaintenance()) { + $this->error('The application is in maintenance mode'); + return; + } + + if ($this->option('once')) { + $this->domainEventConsumer->consume(); + $this->info('Event consumer runned!'); + return; + } + + $this->info('Running event consumer...'); + $this->domainEventConsumer->daemon($this->option('sleep')); + } + + private function downForMaintenance(): bool + { + return $this->option('force') ? false : $this->laravel->isDownForMaintenance(); + } +} diff --git a/src/Consumer/Consumer.php b/src/Consumer/Consumer.php new file mode 100644 index 0000000..ee9b55d --- /dev/null +++ b/src/Consumer/Consumer.php @@ -0,0 +1,92 @@ +busDispatcher = $busDispatcher; + $this->eventDispatcher = $eventDispatcher; + } + + public function daemon(int $sleepSeconds = 3): void + { + while (true) { + $event = $this->consume(); + + if ($event === null) { + sleep($sleepSeconds); + } + } + } + + public function consume(): ?DomainEventsMessage + { + $event = DomainEventsMessagingConsumer::consume(); + + if ($event !== null) { + $this->processDomainEvent($event); + } + + return $event; + } + + private function processDomainEvent(DomainEventsMessage $event): void + { + $domainEvents = Config::get('domain_events_messaging.consumer.events'); + + if (array_key_exists($event->getEvent(), $domainEvents)) { + $this->dispatch($domainEvents[$event->getEvent()], $event); + } + } + + private function dispatch(string $class, DomainEventsMessage $domainEvent): void + { + if (!$this->isDispatchable($class)) { + throw new DomainEventsMessagingException("{$class} is not a job or event"); + } + + $dispatchable = new $class($domainEvent->getMessage()); + + if ($this->isJob($class)) { + $this->busDispatcher->dispatch($dispatchable); + } + + if ($this->isEvent($class)) { + $this->eventDispatcher->dispatch($dispatchable); + } + } + + private function isDispatchable(string $class): bool + { + return $this->isJob($class) || $this->isEvent($class); + } + + private function isJob(string $class): bool + { + return in_array(JobDispatchable::class, class_uses($class)); + } + + private function isEvent(string $class): bool + { + return in_array(EventDispatchable::class, class_uses($class)); + } +} diff --git a/src/Consumer/ConsumerManager.php b/src/Consumer/ConsumerManager.php new file mode 100644 index 0000000..7856e6d --- /dev/null +++ b/src/Consumer/ConsumerManager.php @@ -0,0 +1,26 @@ +container['config']['domain_events_messaging.consumer.default'] ?? 'null'; + } +} diff --git a/src/Consumer/Contracts/ConsumerContract.php b/src/Consumer/Contracts/ConsumerContract.php new file mode 100644 index 0000000..63850ae --- /dev/null +++ b/src/Consumer/Contracts/ConsumerContract.php @@ -0,0 +1,16 @@ +awsSqsClient = $awsSqsClient ?: $this->getAwsSqsClient(); + $this->queueUrl = Config::get('domain_events_messaging.consumer.connections.sqs.queue_url'); + } + + public function consume(): ?DomainEventsMessage + { + $message = $this->receiveMessage(); + + if ($message === null) { + return null; + } + + $this->deleteMessage($message['ReceiptHandle']); + + $messageBody = json_decode($message['Body'], true); + + return new DomainEventsMessage($messageBody['Subject'], $messageBody['Message']); + } + + private function getAwsSqsClient(): SqsClient + { + $config = array_merge( + Config::get('domain_events_messaging.consumer.connections.sqs'), + [ + 'version' => 'latest', + 'http' => [ + 'timeout' => 60, + 'connect_timeout' => 60, + ], + ] + ); + + return (new Sdk($config))->createClient('sqs'); + } + + private function receiveMessage(): ?array + { + $response = $this->awsSqsClient->receiveMessage([ + 'QueueUrl' => $this->queueUrl, + 'MaxNumberOfMessages' => self::MAX_NUMBER_OF_MESSAGES, + ]); + + if (!is_array($response['Messages']) || count($response['Messages']) === 0) { + return null; + } + + return $response['Messages'][0]; + } + + private function deleteMessage(string $receiptHandle): void + { + $this->awsSqsClient->deleteMessage([ + 'QueueUrl' => $this->queueUrl, + 'ReceiptHandle' => $receiptHandle, + ]); + } +} diff --git a/src/DomainEventsMessagingServiceProvider.php b/src/DomainEventsMessagingServiceProvider.php new file mode 100644 index 0000000..b801395 --- /dev/null +++ b/src/DomainEventsMessagingServiceProvider.php @@ -0,0 +1,41 @@ +registerPublishes(); + } + + public function register(): void + { + $this->registerCommands(); + + $this->app->bind('domain-events-messaging-consumer', function () { + return new ConsumerManager($this->app); + }); + + $this->mergeConfigFrom(__DIR__ . '/../config/domain_events_messaging.php', 'domain-events-messaging'); + } + + private function registerPublishes(): void + { + $this->publishes([ + __DIR__ . '/../config/domain_events_messaging.php' => config_path('domain_events_messaging.php'), + ], 'config'); + } + + private function registerCommands(): void + { + $this->commands([ + ConsumeCommand::class, + ]); + } +} diff --git a/src/Exceptions/DomainEventsMessagingException.php b/src/Exceptions/DomainEventsMessagingException.php new file mode 100644 index 0000000..0286010 --- /dev/null +++ b/src/Exceptions/DomainEventsMessagingException.php @@ -0,0 +1,9 @@ +event = $event; + $this->message = $message; + } + + public function getEvent(): string + { + return $this->event; + } + + public function getMessage(): string + { + return $this->message; + } +} diff --git a/tests/Consumer/Console/ConsumeCommandTest.php b/tests/Consumer/Console/ConsumeCommandTest.php new file mode 100644 index 0000000..65240b7 --- /dev/null +++ b/tests/Consumer/Console/ConsumeCommandTest.php @@ -0,0 +1,68 @@ +mock(Consumer::class, static function (MockInterface $mock) { + $mock->shouldReceive('daemon') + ->once(); + }); + + $this->artisan('domain-events-messaging:consume'); + } + + /** @test */ + public function it_should_launch_consumer_as_a_daemon_with_sleep_seconds_on_consume_command_with_sleep_parameter() + { + $this->mock(Consumer::class, static function (MockInterface $mock) { + $mock->shouldReceive('daemon') + ->with(5) + ->once(); + }); + + $this->artisan('domain-events-messaging:consume', ['--sleep' => 5]); + } + + /** @test */ + public function it_should_launch_consumer_once_on_consume_command_with_once_parameter() + { + $this->mock(Consumer::class, static function (MockInterface $mock) { + $mock->shouldReceive('consume') + ->once(); + }); + + $this->artisan('domain-events-messaging:consume', ['--once' => true]); + } + + /** @test */ + public function it_should_not_launch_consumer_when_app_is_in_maintenance_on_consume_command() + { + $this->mock(Consumer::class, static function (MockInterface $mock) { + $mock->shouldReceive('daemon') + ->never(); + }); + + $this->artisan('down'); + $this->artisan('domain-events-messaging:consume'); + $this->artisan('up'); + } + + /** @test */ + public function it_should_launch_consumer_when_app_is_in_maintenance_on_consume_command_with_force_parameter() + { + $this->mock(Consumer::class, static function (MockInterface $mock) { + $mock->shouldReceive('daemon') + ->once(); + }); + + $this->artisan('domain-events-messaging:consume', ['--force' => true]); + } +} diff --git a/tests/Consumer/ConsumerTest.php b/tests/Consumer/ConsumerTest.php new file mode 100644 index 0000000..db40012 --- /dev/null +++ b/tests/Consumer/ConsumerTest.php @@ -0,0 +1,80 @@ + FakeEvent::class, + ]); + + DomainEventsMessagingConsumer::shouldReceive('consume') + ->once() + ->andReturn($domainEventMessage); + + $consumer = app(Consumer::class); + $this->assertSame($domainEventMessage, $consumer->consume()); + + Event::assertDispatched(FakeEvent::class, static function (FakeEvent $event) { + return $event->payload === 'domain-message'; + }); + } + + /** @test */ + public function it_should_dispatch_job_on_consume_domain_event_message() + { + Bus::fake(); + + $domainEventMessage = new DomainEventsMessage('message.subject', 'domain-message'); + Config::set('domain_events_messaging.consumer.events', [ + 'message.subject' => FakeJob::class, + ]); + + DomainEventsMessagingConsumer::shouldReceive('consume') + ->once() + ->andReturn($domainEventMessage); + + $consumer = app(Consumer::class); + $this->assertSame($domainEventMessage, $consumer->consume()); + + Bus::assertDispatched(FakeJob::class, static function (FakeJob $job) { + return $job->payload === 'domain-message'; + }); + } + + /** @test */ + public function it_should_throw_exception_on_consume_domain_event_message_with_not_dispatchable_event_associated() + { + $domainEventMessage = new DomainEventsMessage('message.subject', 'domain-message'); + Config::set('domain_events_messaging.consumer.events', [ + 'message.subject' => FakeNotDispatchableEvent::class, + ]); + + DomainEventsMessagingConsumer::shouldReceive('consume') + ->once() + ->andReturn($domainEventMessage); + + $this->expectException(DomainEventsMessagingException::class); + + $consumer = app(Consumer::class); + $this->assertSame($domainEventMessage, $consumer->consume()); + } +} diff --git a/tests/Consumer/Drivers/ConsumerSqsDriverTest.php b/tests/Consumer/Drivers/ConsumerSqsDriverTest.php new file mode 100644 index 0000000..1182a33 --- /dev/null +++ b/tests/Consumer/Drivers/ConsumerSqsDriverTest.php @@ -0,0 +1,51 @@ +mock(SqsClient::class, static function (MockInterface $mock) { + $mock->shouldReceive('receiveMessage') + ->withArgs([[ + 'QueueUrl' => 'queue_url', + 'MaxNumberOfMessages' => 1, + ]]) + ->once() + ->andReturn([ + 'Messages' => [ + [ + 'ReceiptHandle' => 'message-id', + 'Body' => json_encode([ + 'Subject' => 'message.subject', + 'Message' => 'domain-message' + ]), + ], + ], + ]); + + $mock->shouldReceive('deleteMessage') + ->withArgs([[ + 'QueueUrl' => 'queue_url', + 'ReceiptHandle' => 'message-id', + ]]) + ->once(); + }); + + $consumerSqsDriver = new ConsumerSqsDriver($sqsClient); + $domainEventMessage = $consumerSqsDriver->consume(); + + $this->assertSame('message.subject', $domainEventMessage->getEvent()); + $this->assertSame('domain-message', $domainEventMessage->getMessage()); + } +} diff --git a/tests/Stubs/FakeEvent.php b/tests/Stubs/FakeEvent.php new file mode 100644 index 0000000..12624b7 --- /dev/null +++ b/tests/Stubs/FakeEvent.php @@ -0,0 +1,18 @@ +payload = $payload; + } +} diff --git a/tests/Stubs/FakeJob.php b/tests/Stubs/FakeJob.php new file mode 100644 index 0000000..c6ee4b9 --- /dev/null +++ b/tests/Stubs/FakeJob.php @@ -0,0 +1,22 @@ +payload = $payload; + } + + public function handle(): void + { + } +} diff --git a/tests/Stubs/FakeNotDispatchableEvent.php b/tests/Stubs/FakeNotDispatchableEvent.php new file mode 100644 index 0000000..e193636 --- /dev/null +++ b/tests/Stubs/FakeNotDispatchableEvent.php @@ -0,0 +1,7 @@ + Date: Tue, 21 Apr 2020 09:12:43 +0200 Subject: [PATCH 2/4] update: added php code style --- .gitattributes | 2 +- .gitignore | 2 +- composer.json | 6 ++++-- phpcs.xml.dist | 7 +++++++ phpunit.xml.dist | 2 +- src/Consumer/Contracts/ConsumerContract.php | 1 - src/Consumer/Drivers/ConsumerNullDriver.php | 1 - src/DomainEventsMessagingServiceProvider.php | 1 - src/Facades/DomainEventsMessagingConsumer.php | 4 ++-- tests/Consumer/Drivers/ConsumerSqsDriverTest.php | 2 +- 10 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 phpcs.xml.dist diff --git a/.gitattributes b/.gitattributes index b035b6c..a0db9b4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,4 +5,4 @@ /.gitattributes export-ignore /.gitignore export-ignore /phpunit.xml.dist export-ignore -/tests export-ignore \ No newline at end of file +/tests export-ignore diff --git a/.gitignore b/.gitignore index 56d7960..73bf252 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ /vendor composer.lock /phpunit.xml -.phpunit.result.cache \ No newline at end of file +.phpunit.result.cache diff --git a/composer.json b/composer.json index f5ecb57..b63357f 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,8 @@ }, "require-dev": { "phpunit/phpunit": "^8.0", - "orchestra/testbench": "^5.1" + "orchestra/testbench": "^5.1", + "letsgoi/php-code-style": "^0.1.1" }, "autoload": { "psr-4": { @@ -51,7 +52,8 @@ } }, "scripts": { - "test": "phpunit" + "test": "phpunit", + "syntax": "phpcs" }, "minimum-stability": "dev", "prefer-stable": true diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..233ae29 --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,7 @@ + + + + + + src/ + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 3509b21..edb3d77 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -19,4 +19,4 @@ src/ - \ No newline at end of file + diff --git a/src/Consumer/Contracts/ConsumerContract.php b/src/Consumer/Contracts/ConsumerContract.php index 63850ae..efcda06 100644 --- a/src/Consumer/Contracts/ConsumerContract.php +++ b/src/Consumer/Contracts/ConsumerContract.php @@ -2,7 +2,6 @@ namespace Letsgoi\DomainEventsMessaging\Consumer\Contracts; - use Letsgoi\DomainEventsMessaging\Messages\DomainEventsMessage; interface ConsumerContract diff --git a/src/Consumer/Drivers/ConsumerNullDriver.php b/src/Consumer/Drivers/ConsumerNullDriver.php index d7971f3..a15601e 100644 --- a/src/Consumer/Drivers/ConsumerNullDriver.php +++ b/src/Consumer/Drivers/ConsumerNullDriver.php @@ -2,7 +2,6 @@ namespace Letsgoi\DomainEventsMessaging\Consumer\Drivers; - use Letsgoi\DomainEventsMessaging\Consumer\Contracts\ConsumerContract; use Letsgoi\DomainEventsMessaging\Messages\DomainEventsMessage; diff --git a/src/DomainEventsMessagingServiceProvider.php b/src/DomainEventsMessagingServiceProvider.php index b801395..6dce760 100644 --- a/src/DomainEventsMessagingServiceProvider.php +++ b/src/DomainEventsMessagingServiceProvider.php @@ -2,7 +2,6 @@ namespace Letsgoi\DomainEventsMessaging; -use Illuminate\Foundation\Application; use Illuminate\Support\ServiceProvider; use Letsgoi\DomainEventsMessaging\Consumer\Console\ConsumeCommand; use Letsgoi\DomainEventsMessaging\Consumer\ConsumerManager; diff --git a/src/Facades/DomainEventsMessagingConsumer.php b/src/Facades/DomainEventsMessagingConsumer.php index c99cf32..a4066b9 100644 --- a/src/Facades/DomainEventsMessagingConsumer.php +++ b/src/Facades/DomainEventsMessagingConsumer.php @@ -4,10 +4,10 @@ use Illuminate\Support\Facades\Facade; -class DomainEventsMessagingConsumer extends Facade +class DomainEventsMessagingConsumer extends Facade { protected static function getFacadeAccessor(): string { return 'domain-events-messaging-consumer'; } -} \ No newline at end of file +} diff --git a/tests/Consumer/Drivers/ConsumerSqsDriverTest.php b/tests/Consumer/Drivers/ConsumerSqsDriverTest.php index 1182a33..e7ba8ec 100644 --- a/tests/Consumer/Drivers/ConsumerSqsDriverTest.php +++ b/tests/Consumer/Drivers/ConsumerSqsDriverTest.php @@ -28,7 +28,7 @@ public function it_should_receive_message_and_delete_it_from_sqs_on_consume() 'ReceiptHandle' => 'message-id', 'Body' => json_encode([ 'Subject' => 'message.subject', - 'Message' => 'domain-message' + 'Message' => 'domain-message', ]), ], ], From 82038e34d555e2f564dd7027451b76f61a4bc4b2 Mon Sep 17 00:00:00 2001 From: Marco Bellido Date: Fri, 24 Apr 2020 09:24:47 +0200 Subject: [PATCH 3/4] update: added github actions --- .github/workflows/main.yml | 28 +++++++++++++++++++++ src/Consumer/Contracts/ConsumerContract.php | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..8d46beb --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,28 @@ +name: Continuous Integration + +on: [push] + +jobs: + syntax: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install dependencies + run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist + + - name: Check syntax + run: composer syntax + + test: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install dependencies + run: composer install -q --no-ansi --no-interaction --no-scripts --no-suggest --no-progress --prefer-dist + + - name: Execute tests + run: composer test diff --git a/src/Consumer/Contracts/ConsumerContract.php b/src/Consumer/Contracts/ConsumerContract.php index efcda06..23df531 100644 --- a/src/Consumer/Contracts/ConsumerContract.php +++ b/src/Consumer/Contracts/ConsumerContract.php @@ -9,7 +9,7 @@ interface ConsumerContract /** * Consume message from domain event exchange * - * @return DomainEventsMessage|null ?DomainEventsMessage + * @return DomainEventsMessage|null DomainEventsMessage */ public function consume(): ?DomainEventsMessage; } From 99daae86dee7eb7965dc4e2fd1024eb47af454ca Mon Sep 17 00:00:00 2001 From: Marco Bellido Date: Mon, 27 Apr 2020 11:14:14 +0200 Subject: [PATCH 4/4] update: syntax style --- src/Consumer/Console/ConsumeCommand.php | 3 +++ src/Consumer/Consumer.php | 6 ++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Consumer/Console/ConsumeCommand.php b/src/Consumer/Console/ConsumeCommand.php index f7947d6..242736e 100644 --- a/src/Consumer/Console/ConsumeCommand.php +++ b/src/Consumer/Console/ConsumeCommand.php @@ -30,12 +30,15 @@ public function handle(): void { if ($this->downForMaintenance()) { $this->error('The application is in maintenance mode'); + return; } if ($this->option('once')) { $this->domainEventConsumer->consume(); + $this->info('Event consumer runned!'); + return; } diff --git a/src/Consumer/Consumer.php b/src/Consumer/Consumer.php index ee9b55d..8533f67 100644 --- a/src/Consumer/Consumer.php +++ b/src/Consumer/Consumer.php @@ -19,10 +19,8 @@ class Consumer /** @var EventDispatcher */ private $eventDispatcher; - public function __construct( - BusDispatcher $busDispatcher, - EventDispatcher $eventDispatcher - ) { + public function __construct(BusDispatcher $busDispatcher, EventDispatcher $eventDispatcher) + { $this->busDispatcher = $busDispatcher; $this->eventDispatcher = $eventDispatcher; }