Notifier.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Notifier;
  11. use Psr\Container\ContainerInterface;
  12. use Symfony\Component\Notifier\Channel\ChannelInterface;
  13. use Symfony\Component\Notifier\Channel\ChannelPolicy;
  14. use Symfony\Component\Notifier\Channel\ChannelPolicyInterface;
  15. use Symfony\Component\Notifier\Exception\LogicException;
  16. use Symfony\Component\Notifier\Notification\Notification;
  17. use Symfony\Component\Notifier\Recipient\AdminRecipient;
  18. use Symfony\Component\Notifier\Recipient\NoRecipient;
  19. use Symfony\Component\Notifier\Recipient\Recipient;
  20. /**
  21. * @author Fabien Potencier <fabien@symfony.com>
  22. *
  23. * @experimental in 5.1
  24. */
  25. final class Notifier implements NotifierInterface
  26. {
  27. private $adminRecipients = [];
  28. private $channels;
  29. private $policy;
  30. /**
  31. * @param ChannelInterface[]|ContainerInterface $channels
  32. */
  33. public function __construct($channels, ChannelPolicyInterface $policy = null)
  34. {
  35. $this->channels = $channels;
  36. $this->policy = $policy;
  37. }
  38. public function send(Notification $notification, Recipient ...$recipients): void
  39. {
  40. if (!$recipients) {
  41. $recipients = [new NoRecipient()];
  42. }
  43. foreach ($recipients as $recipient) {
  44. foreach ($this->getChannels($notification, $recipient) as $channel => $transportName) {
  45. $channel->notify($notification, $recipient, $transportName);
  46. }
  47. }
  48. }
  49. public function addAdminRecipient(AdminRecipient $recipient): void
  50. {
  51. $this->adminRecipients[] = $recipient;
  52. }
  53. /**
  54. * @return AdminRecipient[]
  55. */
  56. public function getAdminRecipients(): array
  57. {
  58. return $this->adminRecipients;
  59. }
  60. private function getChannels(Notification $notification, Recipient $recipient): iterable
  61. {
  62. $channels = $notification->getChannels($recipient);
  63. if (!$channels) {
  64. $errorPrefix = sprintf('Unable to determine which channels to use to send the "%s" notification', \get_class($notification));
  65. $error = 'you should either pass channels in the constructor, override its "getChannels()" method';
  66. if (null === $this->policy) {
  67. throw new LogicException(sprintf('%s; %s, or configure a "%s".', $errorPrefix, $error, ChannelPolicy::class));
  68. }
  69. if (!$channels = $this->policy->getChannels($notification->getImportance())) {
  70. throw new LogicException(sprintf('%s; the "%s" returns no channels for importance "%s"; %s.', $errorPrefix, ChannelPolicy::class, $notification->getImportance(), $error));
  71. }
  72. }
  73. foreach ($channels as $channelName) {
  74. $transportName = null;
  75. if (false !== $pos = strpos($channelName, '/')) {
  76. $transportName = substr($channelName, $pos + 1);
  77. $channelName = substr($channelName, 0, $pos);
  78. }
  79. if (null === $channel = $this->getChannel($channelName)) {
  80. throw new LogicException(sprintf('The "%s" channel does not exist.', $channelName));
  81. }
  82. if (!$channel->supports($notification, $recipient)) {
  83. throw new LogicException(sprintf('The "%s" channel is not supported.', $channelName));
  84. }
  85. yield $channel => $transportName;
  86. }
  87. }
  88. private function getChannel(string $name): ?ChannelInterface
  89. {
  90. if ($this->channels instanceof ContainerInterface) {
  91. return $this->channels->has($name) ? $this->channels->get($name) : null;
  92. }
  93. return $this->channels[$name] ?? null;
  94. }
  95. }