* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Notifier; use Psr\Container\ContainerInterface; use Symfony\Component\Notifier\Channel\ChannelInterface; use Symfony\Component\Notifier\Channel\ChannelPolicy; use Symfony\Component\Notifier\Channel\ChannelPolicyInterface; use Symfony\Component\Notifier\Channel\SmsChannel; use Symfony\Component\Notifier\Exception\LogicException; use Symfony\Component\Notifier\Notification\Notification; use Symfony\Component\Notifier\Recipient\NoRecipient; use Symfony\Component\Notifier\Recipient\RecipientInterface; /** * @author Fabien Potencier */ final class Notifier implements NotifierInterface { private array $adminRecipients = []; /** * @param ChannelInterface[]|ContainerInterface $channels */ public function __construct( private array|ContainerInterface $channels, private ?ChannelPolicyInterface $policy = null, ) { } public function send(Notification $notification, RecipientInterface ...$recipients): void { if (!$recipients) { $recipients = [new NoRecipient()]; } foreach ($recipients as $recipient) { foreach ($this->getChannels($notification, $recipient) as $channel => $transportName) { $channel->notify($notification, $recipient, $transportName); } } } public function addAdminRecipient(RecipientInterface $recipient): void { $this->adminRecipients[] = $recipient; } /** * @return RecipientInterface[] */ public function getAdminRecipients(): array { return $this->adminRecipients; } /** * @return iterable */ private function getChannels(Notification $notification, RecipientInterface $recipient): iterable { $channels = $notification->getChannels($recipient); if (!$channels) { $errorPrefix = sprintf('Unable to determine which channels to use to send the "%s" notification', $notification::class); $error = 'you should either pass channels in the constructor, override its "getChannels()" method'; if (null === $this->policy) { throw new LogicException(sprintf('%s; %s, or configure a "%s".', $errorPrefix, $error, ChannelPolicy::class)); } if (!$channels = $this->policy->getChannels($notification->getImportance())) { throw new LogicException(sprintf('%s; the "%s" returns no channels for importance "%s"; %s.', $errorPrefix, ChannelPolicy::class, $notification->getImportance(), $error)); } } foreach ($channels as $channelName) { $transportName = null; if (false !== $pos = strpos($channelName, '/')) { $transportName = substr($channelName, $pos + 1); $channelName = substr($channelName, 0, $pos); } if (null === $channel = $this->getChannel($channelName)) { throw new LogicException(sprintf('The "%s" channel does not exist.', $channelName)); } if ($channel instanceof SmsChannel && $recipient instanceof NoRecipient) { throw new LogicException(sprintf('The "%s" channel needs a Recipient.', $channelName)); } if (!$channel->supports($notification, $recipient)) { throw new LogicException(sprintf('The "%s" channel is not supported.', $channelName)); } yield $channel => $transportName; } } private function getChannel(string $name): ?ChannelInterface { if ($this->channels instanceof ContainerInterface) { return $this->channels->has($name) ? $this->channels->get($name) : null; } return $this->channels[$name] ?? null; } }