RawEmailContext::getMessagesViaImap()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 14
ccs 0
cts 9
cp 0
rs 9.4285
cc 2
eloc 8
nc 2
nop 1
crap 6
1
<?php
2
/**
3
 * @author Sergii Bondarenko, <[email protected]>
4
 */
5
namespace Drupal\TqExtension\Context\Email;
6
7
// Contexts.
8
use Drupal\TqExtension\Context\RawTqContext;
9
// Utils.
10
use Behat\DebugExtension\Message;
11
use Drupal\TqExtension\Utils\Imap;
12
use Drupal\TqExtension\Utils\Database\FetchField;
13
14
class RawEmailContext extends RawTqContext
15
{
16
    use Imap;
17
18
    private $messages = [];
19
    private $email = '';
20
21
    /**
22
     * @param string $to
23
     *
24
     * @throws \RuntimeException
25
     *
26
     * @return array
27
     */
28
    public function getEmailMessages($to = '')
29
    {
30
        // Update address for checking.
31
        if (!empty($to) && $this->email !== $to) {
32
            $this->email = $to;
33
        }
34
35
        if (empty($this->messages[$this->email])) {
36
            $messages = self::hasTag('imap')
37
              ? $this->getMessagesViaImap($this->email)
38
              : $this->getMessagesFromDb();
39
40
            if (empty($messages)) {
41
                throw new \RuntimeException(sprintf('The message for "%s" was not sent.', $this->email));
42
            }
43
44
            foreach ($messages as &$message) {
45
                if ($message['to'] === $this->email) {
46
                    $message['links'] = $this->parseLinksText($message['body']);
47
                }
48
            }
49
50
            $this->messages[$this->email] = $messages;
51
        }
52
53
        // The debug messages may differ due to testing testing mode:
54
        // Drupal mail system collector or IMAP protocol.
55
        self::debug(['%s'], [var_export($this->messages[$this->email], true)]);
56
57
        return $this->messages[$this->email];
58
    }
59
60
    /**
61
     * @param string $email
62
     *
63
     * @throws \InvalidArgumentException
64
     *
65
     * @return array
66
     */
67
    public function getAccount($email)
68
    {
69
        $accounts = $this->getTqParameter('email_accounts');
70
71
        if (empty($accounts[$email])) {
72
            throw new \InvalidArgumentException(sprintf(
73
                'An account for "%s" email address is not defined. Available addresses: "%s".',
74
                $email,
75
                implode(', ', array_keys($accounts))
76
            ));
77
        }
78
79
        return $accounts[$email];
80
    }
81
82
    public function parseLinksText($string)
83
    {
84
        $links = [];
85
86
        /** @var \DOMElement $link */
87
        foreach ((new \DOMXPath(self::parseHTML($string)))->query('//a[@href]') as $link) {
88
            $links[$link->textContent] = $link->getAttribute('href');
89
        }
90
91
        if (empty($links)) {
92
            preg_match_all('/((?:http(?:s)?|www)[^\s]+)/i', $string, $matches);
93
94
            if (!empty($matches[1])) {
95
                $links = $matches[1];
96
            }
97
        }
98
99
        return $links;
100
    }
101
102
    private function getMessagesViaImap($email)
103
    {
104
        $account = $this->getAccount($email);
105
        $timeout = $this->getTqParameter('wait_for_email');
106
107
        $this->setConnection($email, $account['imap'], $account['username'], $account['password']);
108
109
        if ($timeout > 0) {
110
            new Message('comment', 4, ['Waiting %s seconds for letter...'], [$timeout]);
111
            sleep($timeout);
112
        }
113
114
        return $this->getMessages($email);
115
    }
116
117
    private function getMessagesFromDb()
118
    {
119
        // We can't use variable_get() because Behat has another bootstrapped
120
        // variable $conf that is not updated from cURL bootstrapped Drupal instance.
121
        $result = (new FetchField('variable', 'value'))
122
            ->condition('name', 'drupal_test_email_collector')
123
            ->execute();
124
125
        $result = empty($result) ? [] : unserialize($result);
126
127
        self::debug(['Emails from the database: %s'], [var_export($result, true)]);
128
129
        return $result;
130
    }
131
132
    private static function parseHTML($string)
133
    {
134
        $document = new \DOMDocument();
135
136
        // Handle errors/warnings and don't mess up output of your script.
137
        // @see http://stackoverflow.com/a/17559716
138
        $libxml_state = libxml_use_internal_errors(true);
139
        $document->loadHTML($string);
140
141
        libxml_clear_errors();
142
        libxml_use_internal_errors($libxml_state);
143
144
        return $document;
145
    }
146
}
147