115 lines
4.0 KiB
PHP
115 lines
4.0 KiB
PHP
|
<?php
|
||
|
|
||
|
/*
|
||
|
* This file is part of the Symfony package.
|
||
|
*
|
||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||
|
*
|
||
|
* 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 <fabien@symfony.com>
|
||
|
*/
|
||
|
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<ChannelInterface, string|null>
|
||
|
*/
|
||
|
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;
|
||
|
}
|
||
|
}
|