Completed
Pull Request — master (#16)
by Sergii
07:37
created

RawUserContext::isLoggedIn()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 25
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

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