Completed
Push — master ( 8a1851...b55ba8 )
by Alexander
13:15
created

Template::compose()   B

Complexity

Conditions 8
Paths 40

Size

Total Lines 32
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 8

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 20
c 1
b 0
f 0
nc 40
nop 2
dl 0
loc 32
ccs 20
cts 20
cp 1
crap 8
rs 8.4444
1
<?php
2
namespace Yiisoft\Mailer;
3
4
use Yiisoft\View\ViewContextInterface;
5
use Yiisoft\View\View;
6
7
/**
8
 * Template composes the message from view templates, ensuring isolated view rendering. It allows
9
 * changing of the rendering options such as layout during composing of the particular message without
10
 * affecting other messages.
11
 *
12
 * An instance of this class serves as a view context during the mail template rendering and is available
13
 * inside a view template file via [[\yii\base\View::context]].
14
 *
15
 * @see BaseMailer::compose()
16
 */
17
class Template implements ViewContextInterface
18
{
19
    /**
20
     * @var MessageInterface related mail message instance.
21
     */
22
    private $message;
23
24
    /**
25
     * @var View view instance used for rendering.
26
     */
27
    private $view;
28
29
    /**
30
     * @var string path to the directory containing view files.
31
     */
32
    private $viewPath;
33
34
    /**
35
     * @var string|array name of the view to use as a template. The value could be:
36
     *
37
     * - a string that contains either a view name for rendering HTML body of the email.
38
     *   The text body in this case is generated by applying `strip_tags()` to the HTML body.
39
     * - an array with 'html' and/or 'text' elements. The 'html' element refers to a view name
40
     *   for rendering the HTML body, while 'text' element is for rendering the text body. For example,
41
     *   `['html' => 'contact-html', 'text' => 'contact-text']`.
42
     */
43
    private $viewName;
44
45
    /**
46
     * @param View $view
47
     * @param string $viewPath
48
     * @param string|array $viewName
49
     */
50 10
    public function __construct(View $view, string $viewPath, $viewName)
51
    {
52 10
        $this->view = $view;
53 10
        $this->viewPath = $viewPath;
54 10
        $this->viewName = $viewName;
55
    }
56
57
    /**
58
     * @var string HTML layout view name. It is the layout used to render HTML mail body.
59
     * The property can take the following values:
60
     *
61
     * - a relative view name: a view file relative to [[viewPath]], e.g., 'layouts/html'.
62
     * - an empty string: the layout is disabled.
63
     */
64
    private $htmlLayout = '';
65
66
    /**
67
     * Sets html layout.
68
     * @param string $layout
69
     */
70 6
    public function setHtmlLayout(string $layout): void
71
    {
72 6
        $this->htmlLayout = $layout;
73
    }
74
75
    /**
76
     * @var string text layout view name. This is the layout used to render TEXT mail body.
77
     * Please refer to [[htmlLayout]] for possible values that this property can take.
78
     */
79
    private $textLayout = '';
80
81
    /**
82
     * Sets text layout.
83
     * @param string $layout
84
     */
85 6
    public function setTextLayout(string $layout): void
86
    {
87 6
        $this->textLayout = $layout;
88
    }
89
90 7
    public function getViewPath(): string
91
    {
92 7
        return $this->viewPath;
93
    }
94
95
    /**
96
     * Composes the given mail message according to this template.
97
     * @param MessageInterface $message the message to be composed.
98
     * @param array $parameters the parameters (name-value pairs) that will be extracted and made available in the view file.
99
     */
100 4
    public function compose(MessageInterface $message, $parameters = []): void
101
    {
102 4
        $this->message = $message;
103
104 4
        if (is_array($this->viewName)) {
105 2
            if (isset($this->viewName['html'])) {
106 2
                $html = $this->render($this->viewName['html'], $parameters, $this->htmlLayout);
107
            }
108 2
            if (isset($this->viewName['text'])) {
109 2
                $text = $this->render($this->viewName['text'], $parameters, $this->textLayout);
110
            }
111
        } else {
112 4
            $html = $this->render($this->viewName, $parameters, $this->htmlLayout);
113
        }
114
115 4
        if (isset($html)) {
116 4
            $this->message->setHtmlBody($html);
117
        }
118 4
        if (isset($text)) {
119 2
            $this->message->setTextBody($text);
120 4
        } elseif (isset($html)) {
121 4
            if (preg_match('~<body[^>]*>(.*?)</body>~is', $html, $match)) {
122 1
                $html = $match[1];
123
            }
124
            // remove style and script
125 4
            $html = preg_replace('~<((style|script))[^>]*>(.*?)</\1>~is', '', $html);
126
            // strip all HTML tags and decode HTML entities
127 4
            $text = html_entity_decode(strip_tags($html), ENT_QUOTES | ENT_HTML5);
128
            // improve whitespace
129 4
            $text = preg_replace("~^[ \t]+~m", '', trim($text));
130 4
            $text = preg_replace('~\R\R+~mu', "\n\n", $text);
131 4
            $this->message->setTextBody($text);
132
        }
133
    }
134
135
    /**
136
     * Renders the view specified with optional parameters and layout.
137
     * The view will be rendered using the [[view]] component.
138
     * @param string $view a view name of the view file.
139
     * @param array $parameters the parameters (name-value pairs) that will be extracted and made available in the view file.
140
     * @param string $layout layout view name. If the value is empty, no layout will be applied.
141
     * @return string the rendering result.
142
     */
143 6
    public function render(string $view, array $parameters = [], string $layout = ''): string
144
    {
145 6
        $output = $this->view->render($view, $parameters, $this);
146 6
        if ($layout === '') {
147 5
            return $output;
148
        }
149 1
        return $this->view->render($layout, ['content' => $output], $this);
150
    }
151
}
152