1<?php declare(strict_types=1);
2
3/*
4 * This file is part of the Monolog package.
5 *
6 * (c) Jordi Boggiano <j.boggiano@seld.be>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Monolog\Handler;
13
14use Monolog\Logger;
15use Monolog\Utils;
16use Monolog\Formatter\FormatterInterface;
17use Monolog\Formatter\LineFormatter;
18use Swift_Message;
19use Swift;
20
21/**
22 * SwiftMailerHandler uses Swift_Mailer to send the emails
23 *
24 * @author Gyula Sallai
25 *
26 * @phpstan-import-type Record from \Monolog\Logger
27 */
28class SwiftMailerHandler extends MailHandler
29{
30    /** @var \Swift_Mailer */
31    protected $mailer;
32    /** @var Swift_Message|callable(string, Record[]): Swift_Message */
33    private $messageTemplate;
34
35    /**
36     * @psalm-param Swift_Message|callable(string, Record[]): Swift_Message $message
37     *
38     * @param \Swift_Mailer          $mailer  The mailer to use
39     * @param callable|Swift_Message $message An example message for real messages, only the body will be replaced
40     */
41    public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, bool $bubble = true)
42    {
43        parent::__construct($level, $bubble);
44
45        $this->mailer = $mailer;
46        $this->messageTemplate = $message;
47    }
48
49    /**
50     * {@inheritDoc}
51     */
52    protected function send(string $content, array $records): void
53    {
54        $this->mailer->send($this->buildMessage($content, $records));
55    }
56
57    /**
58     * Gets the formatter for the Swift_Message subject.
59     *
60     * @param string|null $format The format of the subject
61     */
62    protected function getSubjectFormatter(?string $format): FormatterInterface
63    {
64        return new LineFormatter($format);
65    }
66
67    /**
68     * Creates instance of Swift_Message to be sent
69     *
70     * @param  string        $content formatted email body to be sent
71     * @param  array         $records Log records that formed the content
72     * @return Swift_Message
73     *
74     * @phpstan-param Record[] $records
75     */
76    protected function buildMessage(string $content, array $records): Swift_Message
77    {
78        $message = null;
79        if ($this->messageTemplate instanceof Swift_Message) {
80            $message = clone $this->messageTemplate;
81            $message->generateId();
82        } elseif (is_callable($this->messageTemplate)) {
83            $message = ($this->messageTemplate)($content, $records);
84        }
85
86        if (!$message instanceof Swift_Message) {
87            $record = reset($records);
88            throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it' . ($record ? Utils::getRecordMessageForException($record) : ''));
89        }
90
91        if ($records) {
92            $subjectFormatter = $this->getSubjectFormatter($message->getSubject());
93            $message->setSubject($subjectFormatter->format($this->getHighestRecord($records)));
94        }
95
96        $mime = 'text/plain';
97        if ($this->isHtmlBody($content)) {
98            $mime = 'text/html';
99        }
100
101        $message->setBody($content, $mime);
102        /** @phpstan-ignore-next-line */
103        if (version_compare(Swift::VERSION, '6.0.0', '>=')) {
104            $message->setDate(new \DateTimeImmutable());
105        } else {
106            /** @phpstan-ignore-next-line */
107            $message->setDate(time());
108        }
109
110        return $message;
111    }
112}
113