Completed
Pull Request — master (#16)
by Sergii
03:45
created

RawUserContext   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 219
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 26
lcom 1
cbo 10
dl 0
loc 219
ccs 0
cts 97
cp 0
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A entityType() 0 4 1
A getCurrentId() 0 4 2
A getIdByArguments() 0 6 1
A createUserWithRoles() 0 11 2
A loginUser() 0 13 2
B fillLoginForm() 0 23 4
B isLoggedIn() 0 25 5
A logoutUser() 0 7 2
B createTestUser() 0 60 7
1
<?php
2
/**
3
 * @author Sergii Bondarenko, <[email protected]>
4
 */
5
namespace Drupal\TqExtension\Context\User;
6
7
// Contexts.
8
use Drupal\TqExtension\Context\RawTqContext;
9
// Utils.
10
use Drupal\TqExtension\Utils\BaseEntity;
11
use Drupal\TqExtension\Utils\Database\FetchField;
12
use Drupal\TqExtension\Utils\EntityDrupalWrapper;
13
14
class RawUserContext extends RawTqContext
15
{
16
    use BaseEntity;
17
18
    /**
19
     * {@inheritdoc}
20
     */
21
    protected function entityType()
22
    {
23
        return 'user';
24
    }
25
26
    /**
27
     * {@inheritdoc}
28
     */
29
    public function getCurrentId()
30
    {
31
        return empty($this->user->uid) ? 0 : $this->user->uid;
32
    }
33
34
    /**
35
     * @param string $column
36
     *   Column of a "users" table.
37
     * @param string $value
38
     *   Expected value in column.
39
     *
40
     * @return int
41
     */
42
    public function getIdByArguments($column, $value)
43
    {
44
        return (new FetchField('users', 'uid'))
45
            ->condition($column, $value)
46
            ->execute();
47
    }
48
49
    /**
50
     * @param string $roles
51
     *   Necessary user roles separated by comma.
52
     * @param array $fields
53
     *
54
     * @return \stdClass
55
     */
56
    public function createUserWithRoles($roles, array $fields = [])
57
    {
58
        $user = $this->createTestUser($fields);
59
        $driver = $this->getDriver();
60
61
        foreach (array_map('trim', explode(',', $roles)) as $role) {
62
            $driver->userAddRole($user, $role);
63
        }
64
65
        return $user;
66
    }
67
68
    /**
69
     * @throws \Exception
70
     */
71
    public function loginUser()
72
    {
73
        $this->logoutUser();
74
75
        if (empty($this->user)) {
76
            throw new \Exception('Tried to login without a user.');
77
        }
78
79
        $this->fillLoginForm([
80
            'username' => $this->user->name,
81
            'password' => $this->user->pass,
82
        ]);
83
    }
84
85
    /**
86
     * @param array $props
87
     *   An array with two keys: "username" and "password". Both of them are required.
88
     * @param string $message
89
     *   An error message, that will be thrown when user cannot be authenticated.
90
     *
91
     * @throws \Behat\Mink\Exception\ElementNotFoundException
92
     *   When one of a fields cannot be not found.
93
     * @throws \Exception
94
     *   When login process failed.
95
     * @throws \WebDriver\Exception\NoSuchElement
96
     *   When log in button cannot be found.
97
     */
98
    public function fillLoginForm(array $props, $message = '')
99
    {
100
        $this->visitPath('/user/login');
101
        $formContext = $this->getFormContext();
102
103
        foreach (['username', 'password'] as $prop) {
104
            $formContext->fillField($this->getDrupalText($prop . '_field'), $props[$prop]);
105
        }
106
107
        $this->getWorkingElement()->pressButton($this->getDrupalText('log_in'));
108
109
        if (!$this->isLoggedIn()) {
110
            throw new \Exception($message ?: sprintf(
111
                'Failed to login as a user "%s" with password "%s".',
112
                $props['username'],
113
                $props['password']
114
            ));
115
        }
116
117
        $this->user = user_load_by_name($props['username']);
118
119
        \DrupalKernelPlaceholder::setCurrentUser($this->user);
120
    }
121
122
    /**
123
     * Cookies are set when at least one page of the site has been visited. This
124
     * action done in "beforeScenario" hook of TqContext.
125
     *
126
     * @see TqContext::beforeScenario()
127
     *
128
     * @return bool
129
     */
130
    public function isLoggedIn()
131
    {
132
        $cookieName = session_name();
133
        $baseUrl = parse_url($this->locatePath());
134
135
        // When "base_url" has "https" scheme, then secure cookie (SSESS) will be set to
136
        // mark authentication. "session_name()" will return unsecure name (SESS) since it
137
        // run programmatically. Correct a cookie name if Behat configured for using secure
138
        // URL and name is not "secure".
139
        // "scheme" may not exist in case if, for instance, "127.0.0.1:1234" used as base URL.
140
        if (strpos($cookieName, 'SS') !== 0 && isset($baseUrl['scheme']) && 'https' === $baseUrl['scheme']) {
141
            $cookieName = "S$cookieName";
142
        }
143
144
        $cookie = $this->getSession()->getCookie($cookieName);
145
146
        if (null !== $cookie) {
147
            // "goutte" session using for checking HTTP status codes.
148
            $this->getSession('goutte')->setCookie($cookieName, $cookie);
149
150
            return true;
151
        }
152
153
        return false;
154
    }
155
156
    public function logoutUser()
157
    {
158
        if ($this->isLoggedIn()) {
159
            $this->logout();
160
            $this->user = false;
161
        }
162
    }
163
164
    /**
165
     * @param array $fields
166
     *   Additional data for user account.
167
     *
168
     * @throws \Exception
169
     *
170
     * @return \stdClass
171
     */
172
    public function createTestUser(array $fields = [])
173
    {
174
        $random = $this->getRandom();
175
        $username = $random->name(8);
176
        $user = [
177
            // 'uid' => 0,
178
            'name' => $username,
179
            'pass' => $random->name(16),
180
            'mail' => "[email protected]",
181
            'roles' => [
182
                DRUPAL_AUTHENTICATED_RID => 'authenticated user',
183
            ],
184
        ];
185
186
        if (!empty($fields)) {
187
            $entity = new EntityDrupalWrapper('user');
188
            // Remove fields such as "name", "pass", "mail" if they are required.
189
            $required = array_diff_key($entity->getRequiredFields(), $user);
190
191
            // Fill fields. Field can be found by name or label.
192
            foreach ($fields as $fieldName => $value) {
193
                $fieldName = $entity->getFieldNameByLocator($fieldName);
194
195
                $user[$fieldName] = $value;
196
                // Remove field from $required if it was there and filled.
197
                unset($required[$fieldName]);
198
            }
199
200
            // Throw an exception when one of required fields was not filled.
201
            if (!empty($required)) {
202
                throw new \Exception(sprintf(
203
                    'The following fields "%s" are required and has not filled.',
204
                    implode('", "', $required)
205
                ));
206
            }
207
        }
208
209
        $user = (object) $user;
210
        $userId = \DrupalKernelPlaceholder::getUidByName($user->name);
211
212
        // User is already exists, remove it to create again.
213
        if ($userId > 0) {
214
            \DrupalKernelPlaceholder::deleteUser($userId);
215
        }
216
217
        // $this->user always exist but when no user created it has "false" as a value.
218
        // Variable stored to another because RawDrupalContext::userCreate() will modify
219
        // it and this will affect for future actions.
220
        if (!empty($this->user)) {
221
            $tmp = $this->user;
222
        }
223
224
        $this->userCreate($user);
225
226
        if (isset($tmp)) {
227
            $this->user = $tmp;
228
        }
229
230
        return $user;
231
    }
232
}
233