Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Mailer
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 5
380
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 setMessage
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 convertAddress
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 buildSubject
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 send
0.00% covered (danger)
0.00%
0 / 48
0.00% covered (danger)
0.00%
0 / 1
156
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\Core\Mail;
6
7use PHPMailer\PHPMailer\PHPMailer;
8use PeServer\Core\Mail\Attachment;
9use PeServer\Core\Mail\EmailAddress;
10use PeServer\Core\Mail\EmailMessage;
11use PeServer\Core\Mail\IMailSetting;
12use PeServer\Core\Mail\SmtpSetting;
13use PeServer\Core\Text;
14use PeServer\Core\Throws\ArgumentException;
15use PeServer\Core\Throws\ArgumentNullException;
16use PeServer\Core\Throws\InvalidOperationException;
17use PeServer\Core\Throws\NotImplementedException;
18
19class Mailer
20{
21    #region define
22
23    protected const ADDRESS_KIND_FROM = 1;
24    protected const ADDRESS_KIND_TO = 2;
25    protected const ADDRESS_KIND_CC = 3;
26    protected const ADDRESS_KIND_BCC = 4;
27
28    public const DEFAULT_ENCODING = '8bit';
29    public const DEFAULT_CHARACTER_SET = 'utf-8';
30
31    #endregion
32
33    #region variable
34
35    /**
36     */
37    private readonly IMailSetting $setting;
38
39    public string $encoding  = self::DEFAULT_ENCODING;
40    public string $characterSet = self::DEFAULT_CHARACTER_SET;
41
42    /**
43     * Return-Path:
44     */
45    public string $returnPath = Text::EMPTY;
46    /**
47     * FROM:
48     */
49    public EmailAddress $fromAddress;
50    /**
51     * TO:
52     *
53     * @var EmailAddress[]
54     */
55    public array $toAddresses = [];
56    /**
57     * CC:
58     *
59     * @var EmailAddress[]
60     */
61    public array $ccAddresses = [];
62    /**
63     * BCC:
64     *
65     * @var EmailAddress[]
66     */
67    public array $bccAddresses = [];
68
69    /**
70     * 件名。
71     */
72    public string $subject = Text::EMPTY;
73
74    /**
75     * メッセージ。
76     */
77    private EmailMessage $message;
78
79    /**
80     * 添付ファイル。
81     *
82     * @var Attachment[]
83     */
84    public array $attachments = [];
85
86    #endregion
87
88    /**
89     * 生成。
90     *
91     * @param IMailSetting $setting
92     */
93    public function __construct(IMailSetting $setting)
94    {
95        $this->fromAddress = new EmailAddress(Text::EMPTY, Text::EMPTY);
96        $this->message = new EmailMessage();
97        $this->setting = $setting;
98    }
99
100    #region function
101
102    /**
103     * 本文設定。
104     *
105     * @param EmailMessage $message
106     * @return void
107     * @throws ArgumentException HTMLとプレーンテキスト未設定。
108     */
109    public function setMessage(EmailMessage $message)
110    {
111        if (!$message->hasText() && !$message->hasHtml()) {
112            throw new ArgumentException();
113        }
114
115        $this->message = $message;
116    }
117
118    /**
119     * アドレスを設定可能形式に変換。
120     *
121     * サービス側でトラップせずにこいつを拡張して開発中は知らんところに飛ばないように調整する。
122     *
123     * @param int $kind 種別
124     * @phpstan-param self::ADDRESS_KIND_* $kind 種別
125     * @param EmailAddress $data
126     * @return EmailAddress
127     * @throws ArgumentException そもそものアドレスが未設定
128     */
129    protected function convertAddress(int $kind, EmailAddress $data): EmailAddress
130    {
131        if (Text::isNullOrWhiteSpace($data->address)) {
132            throw new ArgumentException('$data->address');
133        }
134
135        return $data;
136    }
137
138    /**
139     * 件名を調整。
140     *
141     * @param string $subject 元になる件名。
142     * @return string
143     */
144    protected function buildSubject(string $subject): string
145    {
146        return $subject;
147    }
148
149    /**
150     * 送信。
151     *
152     * @return void
153     */
154    public function send(): void
155    {
156        $client = new PHPMailer(true);
157
158        $lang = mb_language();
159        if (is_string($lang)) {
160            $client->setLanguage($lang, __DIR__ . '/../Libs/PHPMailer/language');
161        }
162
163        $client->CharSet = $this->characterSet;
164        $client->Encoding = $this->encoding;
165
166        $client->Sender = $this->returnPath;
167        $fromAddress = $this->convertAddress(self::ADDRESS_KIND_FROM, $this->fromAddress);
168        $client->setFrom($fromAddress->address, $fromAddress->name);
169        if (Text::isNullOrWhiteSpace($client->Sender)) {
170            $client->Sender = $client->$this->fromAddress['address'];
171        }
172
173
174        $client->clearAddresses();
175        foreach ($this->toAddresses as $address) {
176            $toAddress = $this->convertAddress(self::ADDRESS_KIND_TO, $address);
177            $client->addAddress($toAddress->address, $toAddress->name);
178        }
179
180        $client->clearCCs();
181        foreach ($this->ccAddresses as $address) {
182            $ccAddress = $this->convertAddress(self::ADDRESS_KIND_CC, $address);
183            $client->addCC($ccAddress->address, $ccAddress->name);
184        }
185
186        $client->clearBCCs();
187        foreach ($this->bccAddresses as $address) {
188            $bccAddress = $this->convertAddress(self::ADDRESS_KIND_BCC, $address);
189            $client->addBCC($bccAddress->address, $bccAddress->name);
190        }
191
192
193        $isHtml = false;
194        $client->Subject = $this->buildSubject($this->subject);
195        if ($this->message->hasHtml()) {
196            $client->isHTML(true);
197            $client->Body = $this->message->getHtml();
198            $isHtml = true;
199        }
200        if ($this->message->hasText()) {
201            if ($isHtml) {
202                $client->AltBody = $this->message->getText();
203            } else {
204                $client->Body = $this->message->getText();
205            }
206        } elseif (!$isHtml) {
207            throw new InvalidOperationException();
208        }
209
210        $client->clearAttachments();
211        foreach ($this->attachments as $attachment) {
212            $client->addStringAttachment($attachment->data->raw, $attachment->name, PHPMailer::ENCODING_BASE64, $attachment->mime);
213        }
214
215        if ($this->setting instanceof SmtpSetting) {
216            $smtp = $this->setting;
217            $client->isSMTP();
218            $client->Host = $smtp->host;
219            $client->Port = $smtp->port;
220            $client->SMTPSecure = $smtp->secure;
221            $client->SMTPAuth = $smtp->authentication;
222            $client->Username = $smtp->userName;
223            $client->Password = $smtp->password;
224        }
225
226        $client->send();
227    }
228
229    #endregion
230}