Completed
Push — master ( 06c648...ccf5a4 )
by Sergii
02:16
created

RawEmailContext::parseHTML()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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