├── Attribute └── AsRemoteEventConsumer.php ├── CHANGELOG.md ├── Consumer └── ConsumerInterface.php ├── Event ├── Mailer │ ├── AbstractMailerEvent.php │ ├── MailerDeliveryEvent.php │ └── MailerEngagementEvent.php └── Sms │ └── SmsEvent.php ├── Exception ├── ExceptionInterface.php ├── InvalidArgumentException.php ├── LogicException.php ├── ParseException.php └── RuntimeException.php ├── LICENSE ├── Messenger ├── ConsumeRemoteEventHandler.php └── ConsumeRemoteEventMessage.php ├── PayloadConverterInterface.php ├── README.md ├── RemoteEvent.php └── composer.json /Attribute/AsRemoteEventConsumer.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent\Attribute; 13 | 14 | /** 15 | * @author Fabien Potencier 16 | */ 17 | #[\Attribute(\Attribute::TARGET_CLASS)] 18 | class AsRemoteEventConsumer 19 | { 20 | /** 21 | * @param string $name The name of the remote event consumer, used to identify it when defining remote events 22 | */ 23 | public function __construct( 24 | public string $name, 25 | ) { 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | ========= 3 | 4 | 6.4 5 | --- 6 | 7 | * Mark the component as non experimental 8 | 9 | 6.3 10 | --- 11 | 12 | * Add the component (experimental) 13 | -------------------------------------------------------------------------------- /Consumer/ConsumerInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent\Consumer; 13 | 14 | use Symfony\Component\RemoteEvent\RemoteEvent; 15 | 16 | /** 17 | * @author Fabien Potencier 18 | */ 19 | interface ConsumerInterface 20 | { 21 | public function consume(RemoteEvent $event): void; 22 | } 23 | -------------------------------------------------------------------------------- /Event/Mailer/AbstractMailerEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent\Event\Mailer; 13 | 14 | use Symfony\Component\RemoteEvent\RemoteEvent; 15 | 16 | /** 17 | * @author Fabien Potencier 18 | */ 19 | abstract class AbstractMailerEvent extends RemoteEvent 20 | { 21 | private \DateTimeImmutable $date; 22 | private string $email = ''; 23 | private array $metadata = []; 24 | private array $tags = []; 25 | 26 | public function setDate(\DateTimeImmutable $date): void 27 | { 28 | $this->date = $date; 29 | } 30 | 31 | public function getDate(): \DateTimeImmutable 32 | { 33 | return $this->date; 34 | } 35 | 36 | public function setRecipientEmail(string $email): void 37 | { 38 | $this->email = $email; 39 | } 40 | 41 | public function getRecipientEmail(): string 42 | { 43 | return $this->email; 44 | } 45 | 46 | public function setMetadata(array $metadata): void 47 | { 48 | $this->metadata = $metadata; 49 | } 50 | 51 | public function getMetadata(): array 52 | { 53 | return $this->metadata; 54 | } 55 | 56 | public function setTags(array $tags): void 57 | { 58 | $this->tags = $tags; 59 | } 60 | 61 | public function getTags(): array 62 | { 63 | return $this->tags; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Event/Mailer/MailerDeliveryEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent\Event\Mailer; 13 | 14 | /** 15 | * @author Fabien Potencier 16 | */ 17 | final class MailerDeliveryEvent extends AbstractMailerEvent 18 | { 19 | public const RECEIVED = 'received'; 20 | public const DROPPED = 'dropped'; 21 | public const DELIVERED = 'delivered'; 22 | public const DEFERRED = 'deferred'; 23 | public const BOUNCE = 'bounce'; 24 | 25 | private string $reason = ''; 26 | 27 | public function setReason(string $reason): void 28 | { 29 | $this->reason = $reason; 30 | } 31 | 32 | public function getReason(): string 33 | { 34 | return $this->reason; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Event/Mailer/MailerEngagementEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent\Event\Mailer; 13 | 14 | /** 15 | * @author Fabien Potencier 16 | */ 17 | final class MailerEngagementEvent extends AbstractMailerEvent 18 | { 19 | public const OPEN = 'open'; 20 | public const CLICK = 'click'; 21 | public const SPAM = 'spam'; 22 | public const UNSUBSCRIBE = 'unsubscribe'; 23 | } 24 | -------------------------------------------------------------------------------- /Event/Sms/SmsEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent\Event\Sms; 13 | 14 | use Symfony\Component\RemoteEvent\RemoteEvent; 15 | 16 | /** 17 | * @author Fabien Potencier 18 | */ 19 | final class SmsEvent extends RemoteEvent 20 | { 21 | public const FAILED = 'failed'; 22 | public const DELIVERED = 'delivered'; 23 | 24 | private string $phone = ''; 25 | 26 | public function setRecipientPhone(string $phone): void 27 | { 28 | $this->phone = $phone; 29 | } 30 | 31 | public function getRecipientPhone(): string 32 | { 33 | return $this->phone; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Exception/ExceptionInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent\Exception; 13 | 14 | /** 15 | * @author Fabien Potencier 16 | */ 17 | interface ExceptionInterface extends \Throwable 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /Exception/InvalidArgumentException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent\Exception; 13 | 14 | /** 15 | * @author Fabien Potencier 16 | */ 17 | class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /Exception/LogicException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent\Exception; 13 | 14 | /** 15 | * @author Fabien Potencier 16 | */ 17 | class LogicException extends \LogicException implements ExceptionInterface 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /Exception/ParseException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent\Exception; 13 | 14 | /** 15 | * @author Fabien Potencier 16 | */ 17 | class ParseException extends InvalidArgumentException 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /Exception/RuntimeException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent\Exception; 13 | 14 | /** 15 | * @author Fabien Potencier 16 | */ 17 | class RuntimeException extends \RuntimeException implements ExceptionInterface 18 | { 19 | } 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2022-present Fabien Potencier 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Messenger/ConsumeRemoteEventHandler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent\Messenger; 13 | 14 | use Psr\Container\ContainerInterface; 15 | use Symfony\Component\RemoteEvent\Consumer\ConsumerInterface; 16 | use Symfony\Component\RemoteEvent\Exception\LogicException; 17 | 18 | /** 19 | * @author Fabien Potencier 20 | */ 21 | class ConsumeRemoteEventHandler 22 | { 23 | public function __construct( 24 | private readonly ContainerInterface $consumers, 25 | ) { 26 | } 27 | 28 | public function __invoke(ConsumeRemoteEventMessage $message): void 29 | { 30 | if (!$this->consumers->has($message->getType())) { 31 | throw new LogicException(\sprintf('Unable to find a consumer for message of type "%s".', $message->getType())); 32 | } 33 | $consumer = $this->consumers->get($message->getType()); 34 | 35 | if (!$consumer instanceof ConsumerInterface) { 36 | throw new LogicException(\sprintf('The consumer "%s" for message of type "%s" must implement "%s".', get_debug_type($consumer), $message->getType(), ConsumerInterface::class)); 37 | } 38 | 39 | $consumer->consume($message->getEvent()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Messenger/ConsumeRemoteEventMessage.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent\Messenger; 13 | 14 | use Symfony\Component\RemoteEvent\RemoteEvent; 15 | 16 | /** 17 | * @author Fabien Potencier 18 | */ 19 | class ConsumeRemoteEventMessage 20 | { 21 | public function __construct( 22 | private readonly string $type, 23 | private readonly RemoteEvent $event, 24 | ) { 25 | } 26 | 27 | public function getType(): string 28 | { 29 | return $this->type; 30 | } 31 | 32 | public function getEvent(): RemoteEvent 33 | { 34 | return $this->event; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /PayloadConverterInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent; 13 | 14 | use Symfony\Component\RemoteEvent\Exception\ParseException; 15 | 16 | interface PayloadConverterInterface 17 | { 18 | /** 19 | * @throws ParseException when the payload is not valid 20 | */ 21 | public function convert(array $payload): RemoteEvent; 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RemoteEvent Component 2 | ===================== 3 | 4 | Symfony RemoteEvent eases handling remote events. 5 | 6 | Resources 7 | --------- 8 | 9 | * [Documentation](https://symfony.com/doc/current/remote-event.html) 10 | * [Contributing](https://symfony.com/doc/current/contributing/index.html) 11 | * [Report issues](https://github.com/symfony/symfony/issues) and 12 | [send Pull Requests](https://github.com/symfony/symfony/pulls) 13 | in the [main Symfony repository](https://github.com/symfony/symfony) 14 | -------------------------------------------------------------------------------- /RemoteEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Symfony\Component\RemoteEvent; 13 | 14 | /** 15 | * @author Fabien Potencier 16 | */ 17 | class RemoteEvent 18 | { 19 | public function __construct( 20 | private readonly string $name, 21 | private readonly string $id, 22 | private readonly array $payload, 23 | ) { 24 | } 25 | 26 | public function getName(): string 27 | { 28 | return $this->name; 29 | } 30 | 31 | public function getId(): string 32 | { 33 | return $this->id; 34 | } 35 | 36 | public function getPayload(): array 37 | { 38 | return $this->payload; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "symfony/remote-event", 3 | "type": "library", 4 | "description": "Eases handling remote events", 5 | "keywords": ["event"], 6 | "homepage": "https://symfony.com", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Fabien Potencier", 11 | "email": "fabien@symfony.com" 12 | }, 13 | { 14 | "name": "Symfony Community", 15 | "homepage": "https://symfony.com/contributors" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=8.2", 20 | "symfony/messenger": "^6.4|^7.0" 21 | }, 22 | "autoload": { 23 | "psr-4": { "Symfony\\Component\\RemoteEvent\\": "" }, 24 | "exclude-from-classmap": [ 25 | "/Tests/" 26 | ] 27 | }, 28 | "minimum-stability": "dev" 29 | } 30 | --------------------------------------------------------------------------------