AbstractMail::__construct()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 10
cts 10
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 9
nc 2
nop 1
crap 3
1
<?php
2
/**
3
 * BrightNucleus ChainMail Component.
4
 *
5
 * @package   BrightNucleus/ChainMail
6
 * @author    Alain Schlesser <[email protected]>
7
 * @license   MIT
8
 * @link      http://www.brightnucleus.com/
9
 * @copyright 2016 Alain Schlesser, Bright Nucleus
10
 */
11
12
namespace BrightNucleus\ChainMail\Mail;
13
14
use BrightNucleus\ChainMail\Exception\InvalidTemplate;
15
use BrightNucleus\ChainMail\Mail;
16
use BrightNucleus\ChainMail\Recipients;
17
use BrightNucleus\ChainMail\Support\EmailAddress;
18
use BrightNucleus\ChainMail\Support\Factory;
19
use BrightNucleus\ChainMail\Template;
20
use BrightNucleus\Config\ConfigInterface;
21
use BrightNucleus\Config\Exception\FailedToProcessConfigException;
22
use BrightNucleus\View;
23
use BrightNucleus\View\Location\FilesystemLocation;
24
use BrightNucleus\View\ViewBuilder;
25
use Exception;
26
use RuntimeException;
27
28
/**
29
 * Abstract Class AbstractMail.
30
 *
31
 * @since   1.0.0
32
 *
33
 * @package BrightNucleus\ChainMail
34
 * @author  Alain Schlesser <[email protected]>
35
 */
36
abstract class AbstractMail implements Mail
37
{
38
39
    /**
40
     * Configuration Settings.
41
     *
42
     * @since 1.0.0
43
     *
44
     * @var ConfigInterface
45
     */
46
    protected $config;
47
48
    /**
49
     * Template that is used for the email.
50
     *
51
     * @since 1.0.0
52
     *
53
     * @var Template
54
     */
55
    protected $template;
56
57
    /**
58
     * Content for the different sections.
59
     *
60
     * @since 1.0.0
61
     *
62
     * @var array
63
     */
64
    protected $sectionContent = [];
65
66
    /**
67
     * Format of the mail.
68
     *
69
     * @since 1.0.0
70
     *
71
     * @var string
72
     */
73
    protected $format;
74
75
    /**
76
     * ViewBuilder to create template and section views.
77
     *
78
     * @since 1.0.0
79
     *
80
     * @var ViewBuilder
81
     */
82
    protected $viewBuilder;
83
84
    /**
85
     * Instantiate an AbstractMail object.
86
     *
87
     * @since 1.0.0
88
     *
89
     * @param ConfigInterface $config The Config to use.
90
     *
91
     * @throws FailedToProcessConfigException If the Config could not be processed.
92
     */
93 16
    public function __construct(ConfigInterface $config)
94
    {
95 16
        $this->config = $config;
96 16
        $this->setFormat();
97
98 16
        $this->viewBuilder = new ViewBuilder($config
99 16
            ? $config->getSubConfig('ViewBuilder')
100 16
            : null
101
        );
102
103 16
        foreach ($this->config->getKey('view_root_locations') as $folder) {
104 16
            $this->viewBuilder->addLocation(
105 16
                new FilesystemLocation($folder)
106
            );
107
        }
108 16
    }
109
110
    /**
111
     * Get the template to use for the renderer.
112
     *
113
     * @since 1.0.0
114
     *
115
     * @return Template Reference to the template that is used.
116
     * @throws RuntimeException
117
     */
118 16
    public function getTemplate()
119
    {
120
121 16
        if ( ! $this->template) {
122
            $this->setDefaultTemplate();
123
        }
124
125 16
        if (is_string($this->template)) {
126
            $this->template = $this->createTemplate($this->template);
127
        }
128
129 16
        return $this->template;
130
    }
131
132
    /**
133
     * Set the template to use for the renderer.
134
     *
135
     * @since 1.0.0
136
     *
137
     * @param string|Template $template          Template to use for the
138
     *                                           renderer.
139
     *
140
     * @return Mail
141
     * @throws InvalidTemplate If the template class could not be instantiated.
142
     * @throws InvalidTemplate If the template type is not recognized.
143
     */
144 16
    public function setTemplate($template)
145
    {
146
        try {
147 16
            if (is_string($template)) {
148 16
                $template = $this->createTemplate($template);
149
            }
150
        } catch (Exception $exception) {
151
            throw new InvalidTemplate(
152
                'Could not instantiate the template class "%1$s". Reason: "%2$s".',
153
                $template,
154
                $exception->getMessage()
155
            );
156
        }
157
158 16
        if ( ! $template instanceof Template) {
159
            throw new InvalidTemplate(
160
                'Could not set the template, invalid type.',
161
                (array)$template
162
            );
163
        }
164 16
        $this->template = $template;
165
166 16
        return $this;
167
    }
168
169
    /**
170
     * Add a section to the Mail.
171
     *
172
     * @since 1.0.0
173
     *
174
     * @param string $type    Type of section to add.
175
     * @param string $content Content of the section.
176
     *
177
     * @throws RuntimeException
178
     */
179 8
    public function addSection($type, $content)
180
    {
181 8
        $this->sectionContent[$type] = $content;
182 8
    }
183
184
    /**
185
     * Render the Mail for a given context.
186
     *
187
     * @since 1.0.0
188
     *
189
     * @param array $context The context in which to render the email.
190
     *
191
     * @return string Rendered output of the email
192
     */
193 8
    public function render(array $context)
194
    {
195 8
        $template = $this->getTemplate();
196
197 8
        $context['template'] = $template;
198
199 8
        $this->instantiateSections($template->getUsedSections(), $context);
200
201 8
        $context['format'] = $this->getFormat();
202
203 8
        $context = $this->setContext($context);
204
205 8
        return $template->render($context);
206
    }
207
208
    /**
209
     * Send the email to one or more recipients.
210
     *
211
     * @since 1.0.0
212
     *
213
     * @param Recipients|EmailAddress|array|string $recipients
214
     *
215
     * @return Mail
0 ignored issues
show
Documentation introduced by
Should the return type not be |null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
216
     */
217
    public function sendTo($recipients)
218
    {
219
        if ($recipients instanceof EmailAddress) {
220
            return $this->executeSend($recipients);
221
        }
222
223
        if (is_string($recipients)) {
224
            return $this->sendTo(new EmailAddress($recipients));
225
        }
226
227
        if ($recipients instanceof Recipients) {
228
            array_walk($recipients, [$this, 'sendTo']);
229
230
            return $this;
231
        }
232
    }
233
234
    /**
235
     * Execute the sending of one individual email.
236
     *
237
     * @since 1.0.0
238
     *
239
     * @param EmailAddress $recipient Recipient to send the email to.
240
     *
241
     * @return Mail
242
     */
243
    protected function executeSend(EmailAddress $recipient)
244
    {
245
        // Do the actual sending.
246
        echo "Sending email to ${recipient}...";
247
248
        return $this;
249
    }
250
251
    /**
252
     * Instantiate the requested sections for a template.
253
     *
254
     * @since 1.0.0
255
     *
256
     * @param array $sections Sections to instantiate.
257
     * @param array $context  The context in which to instantiate the sections.
258
     */
259
    protected function instantiateSections(array $sections, array &$context)
260
    {
261 8
        $sectionFactory = new Factory($this->config, 'sections');
262
263 8
        foreach ($sections as $section) {
264
265 8
            $content = null;
266
267 8
            if (array_key_exists($section, $this->sectionContent)) {
268 8
                $content = $this->sectionContent[$section];
269
            }
270
271 8
            $context['sections'][$section] = $sectionFactory->create(
272
                $section,
273 8
                [$section, $content, $this->viewBuilder]
274
            );
275
        }
276 8
    }
277
278
    /**
279
     * Set the format of the mail.
280
     *
281
     * @since 1.0.0
282
     *
283
     * @return string Format of the Mail.
284
     */
285
    protected function getFormat()
286
    {
287 8
        return $this->format;
288
    }
289
290
    /**
291
     * Set the format of the mail.
292
     *
293
     * @since 1.0.0
294
     *
295
     * @return void
296
     */
297
    abstract protected function setFormat();
298
299
    /**
300
     * Set the template to the default template defined in the configuration.
301
     *
302
     * @since 1.0.0
303
     *
304
     * @throws RuntimeException
305
     */
306
    protected function setDefaultTemplate()
307
    {
308
        $defaultTemplate = $this->config->getKey('default_template');
309
        $this->setTemplate($defaultTemplate);
310
    }
311
312
    /**
313
     * Create an instance of a template.
314
     *
315
     * @since 1.0.0
316
     *
317
     * @param string $template Template to instantiate.
318
     *
319
     * @return Template $template Newly created instance.
320
     * @throws RuntimeException
321
     */
322
    protected function createTemplate($template)
323
    {
324 16
        $templateFactory = new Factory($this->config, 'templates');
325
326 16
        return $templateFactory->create($template, [$template, $this->viewBuilder]);
327
    }
328
329
    /**
330
     * Set the context of the mail.
331
     *
332
     * @since 1.0.0
333
     *
334
     * @param array $context Context to set/modify.
335
     *
336
     * @return array Updated context.
337
     */
338
    abstract protected function setContext(array $context);
339
}
340