Provider::setAutenticateAndReferer()   B
last analyzed

Complexity

Conditions 6
Paths 10

Size

Total Lines 47
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 3 Features 0
Metric Value
eloc 28
c 6
b 3
f 0
dl 0
loc 47
rs 8.8497
cc 6
nc 10
nop 3
1
<?php
2
/**
3
 * Copyright © 2019 O2TI. All rights reserved.
4
 * See LICENSE.txt for license details.
5
 */
6
7
namespace O2TI\SocialLogin\Provider;
8
9
use Exception;
10
use Hybridauth\HybridauthFactory;
0 ignored issues
show
Bug introduced by
The type Hybridauth\HybridauthFactory was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
11
use Hybridauth\User\Profile as SocialProfile;
12
use Magento\Customer\Api\AccountManagementInterface;
13
use Magento\Customer\Api\CustomerRepositoryInterface;
14
use Magento\Customer\Api\Data\CustomerInterfaceFactory;
0 ignored issues
show
Bug introduced by
The type Magento\Customer\Api\Data\CustomerInterfaceFactory was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
15
use Magento\Customer\Model\Account\Redirect as AccountRedirect;
16
use Magento\Customer\Model\Customer;
17
use Magento\Customer\Model\CustomerFactory;
0 ignored issues
show
Bug introduced by
The type Magento\Customer\Model\CustomerFactory was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use Magento\Customer\Model\ResourceModel\Customer as CustomerResource;
19
use Magento\Customer\Model\Session as CustomerSession;
20
use Magento\Customer\Model\Url as CustomerUrl;
21
use Magento\Framework\App\Config\ScopeConfigInterface;
22
use Magento\Framework\App\ObjectManager;
23
use Magento\Framework\Exception\LocalizedException;
24
use Magento\Framework\Message\ManagerInterface;
25
use Magento\Framework\Session\SessionManagerInterface;
26
use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory;
27
use Magento\Framework\Stdlib\CookieManagerInterface;
28
use Magento\Framework\UrlInterface;
29
use Magento\Store\Model\ScopeInterface;
30
use Magento\Store\Model\StoreManagerInterface;
31
32
/**
33
 * Provider section.
34
 *
35
 * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
36
 */
37
class Provider
38
{
39
    public const CONFIG_PATH_SOCIAL_LOGIN_ENABLED = 'social_login/general/enabled';
40
    public const CONFIG_PATH_SOCIAL_LOGIN_PROVIDER_ENABLED = 'social_login/general/%s/enabled';
41
    public const CONFIG_PATH_SOCIAL_LOGIN_PROVIDER_KEY = 'social_login/general/%s/api_key';
42
    public const CONFIG_PATH_SOCIAL_LOGIN_PROVIDER_SECRET = 'social_login/general/%s/api_secret';
43
    public const COOKIE_NAME = 'login_redirect';
44
45
    /**
46
     * The providers we currently support.
47
     */
48
    public const PROVIDERS = [
49
        'facebook',
50
        'google',
51
        'WindowsLive',
52
    ];
53
54
    /**
55
     * @var HybridauthFactory
56
     */
57
    private $hybridauthFactory;
58
59
    /**
60
     * @var UrlInterface
61
     */
62
    private $url;
63
64
    /**
65
     * @var AccountManagementInterface
66
     */
67
    protected $accountManagement;
68
69
    /**
70
     * @var CustomerUrl
71
     */
72
    protected $customerUrl;
73
74
    /**
75
     * @var CustomerInterfaceFactory
76
     */
77
    protected $customerDataFactory;
78
79
    /**
80
     * @var CustomerFactory
81
     */
82
    private $customerFactory;
83
84
    /**
85
     * @var CustomerResource
86
     */
87
    private $customerResource;
88
89
    /**
90
     * @var CustomerSession
91
     */
92
    private $customerSession;
93
94
    /**
95
     * @var StoreManagerInterface
96
     */
97
    private $storeManager;
98
99
    /**
100
     * @var ScopeConfigInterface
101
     */
102
    private $scopeConfig;
103
104
    /**
105
     * @var CookieManagerInterface
106
     */
107
    private $cookieManager;
108
109
    /**
110
     * @var CookieMetadataFactory
111
     */
112
    private $cookieMetadataFactory;
113
114
    /**
115
     * @var SessionManagerInterface
116
     */
117
    private $sessionManager;
118
119
    /**
120
     * @var CustomerRepositoryInterface
121
     */
122
    protected $customerRepository;
123
124
    /**
125
     * @var ManagerInterface
126
     */
127
    private $messageManager;
128
129
    /**
130
     * @var AccountRedirect
131
     */
132
    protected $accountRedirect;
133
134
    /**
135
     * @param HybridauthFactory           $hybridauthFactory
136
     * @param UrlInterface                $url
137
     * @param AccountManagementInterface  $accountManagement
138
     * @param CustomerUrl                 $customerUrl
139
     * @param CustomerInterfaceFactory    $customerDataFactory
140
     * @param CustomerFactory             $customerFactory
141
     * @param CustomerResource            $customerResource
142
     * @param CustomerSession|null        $customerSession
143
     * @param StoreManagerInterface       $storeManager
144
     * @param ScopeConfigInterface        $scopeConfig
145
     * @param CookieManagerInterface      $cookieManager
146
     * @param CookieMetadataFactory       $cookieMetadataFactory
147
     * @param SessionManagerInterface     $sessionManager
148
     * @param CustomerRepositoryInterface $customerRepository
149
     * @param ManagerInterface            $messageManager
150
     * @param AccountRedirect             $accountRedirect
151
     */
152
    public function __construct(
153
        HybridauthFactory $hybridauthFactory,
154
        UrlInterface $url,
155
        AccountManagementInterface $accountManagement,
156
        CustomerUrl $customerUrl,
157
        CustomerInterfaceFactory $customerDataFactory,
158
        CustomerFactory $customerFactory,
159
        CustomerResource $customerResource,
160
        ?CustomerSession $customerSession = null,
161
        StoreManagerInterface $storeManager,
162
        ScopeConfigInterface $scopeConfig,
163
        CookieManagerInterface $cookieManager = null,
164
        CookieMetadataFactory $cookieMetadataFactory = null,
165
        SessionManagerInterface $sessionManager,
166
        CustomerRepositoryInterface $customerRepository,
167
        ManagerInterface $messageManager,
168
        AccountRedirect $accountRedirect
169
    ) {
170
        $this->hybridauthFactory = $hybridauthFactory;
171
        $this->url = $url;
172
        $this->accountManagement = $accountManagement;
173
        $this->customerUrl = $customerUrl;
174
        $this->customerDataFactory = $customerDataFactory;
175
        $this->customerFactory = $customerFactory;
176
        $this->customerResource = $customerResource;
177
        $this->customerSession = $customerSession ?? ObjectManager::getInstance()->get(CustomerSession::class);
178
        $this->storeManager = $storeManager;
179
        $this->scopeConfig = $scopeConfig;
180
        $this->cookieManager = $cookieManager ?:
181
            ObjectManager::getInstance()->get(CookieManagerInterface::class);
182
        $this->cookieMetadataFactory = $cookieMetadataFactory ?:
183
            ObjectManager::getInstance()->get(CookieMetadataFactory::class);
184
        $this->sessionManager = $sessionManager;
185
        $this->customerRepository = $customerRepository;
186
        $this->messageManager = $messageManager;
187
        $this->accountRedirect = $accountRedirect ?: ObjectManager::getInstance()->get(AccountRedirect::class);
0 ignored issues
show
introduced by
$accountRedirect is of type Magento\Customer\Model\Account\Redirect, thus it always evaluated to true.
Loading history...
188
    }
189
190
    /**
191
     * Implements Config Module.
192
     *
193
     * @param string $provider
194
     *
195
     * @return array
196
     */
197
    private function getProvidersConfig(string $provider): array
198
    {
199
        $config = [];
200
        $config[$provider] = [
201
            'enabled' => (bool) $this->scopeConfig->getValue(
202
                sprintf(self::CONFIG_PATH_SOCIAL_LOGIN_PROVIDER_ENABLED, $provider),
203
                ScopeInterface::SCOPE_STORE
204
            ),
205
            'keys' => [
206
                'key' => $this->scopeConfig->getValue(
207
                    sprintf(self::CONFIG_PATH_SOCIAL_LOGIN_PROVIDER_KEY, $provider),
208
                    ScopeInterface::SCOPE_STORE
209
                ),
210
                'secret' => $this->scopeConfig->getValue(
211
                    sprintf(self::CONFIG_PATH_SOCIAL_LOGIN_PROVIDER_SECRET, $provider),
212
                    ScopeInterface::SCOPE_STORE
213
                ),
214
            ],
215
        ];
216
217
        return $config;
218
    }
219
220
    /**
221
     * Generate Url Endpoint.
222
     *
223
     * @param string $provider
224
     *
225
     * @return string
226
     */
227
    private function getEndpoint(string $provider): string
228
    {
229
        $params = [
230
            '_secure'  => true,
231
            'provider' => $provider,
232
        ];
233
234
        return $this->url->getUrl('sociallogin/endpoint/index', $params);
235
    }
236
237
    /**
238
     * Gets customer data for a hybrid auth profile.
239
     *
240
     * @param SocialProfile $profile
241
     *
242
     * @return CustomerFactory
243
     */
244
    private function getCustomerData(SocialProfile $profile)
245
    {
246
        $customerData = [];
247
        foreach (['firstName', 'lastName', 'email'] as $field) {
248
            $data = $profile->{$field};
249
            $customerData[strtolower($field)] = $data !== null ? $data : '-';
250
        }
251
252
        $customer = $this->customerDataFactory->create();
253
        $customer->setEmail($customerData['email']);
254
        $customer->setFirstname($customerData['firstname']);
255
        $customer->setLastname($customerData['lastname']);
256
        $storeId = $this->storeManager->getStore()->getId();
257
        $customer->setStoreId($storeId);
258
        $websiteId = $this->storeManager->getStore($customer->getStoreId())->getWebsiteId();
259
        $customer->setWebsiteId($websiteId);
260
261
        return $customer;
262
    }
263
264
    /**
265
     * Set Customer.
266
     *
267
     * @param SocialProfile $socialProfile
268
     *
269
     * @return CustomerFactory
270
     */
271
    private function setCustomerData(SocialProfile $socialProfile)
272
    {
273
        $websiteId = $this->storeManager->getWebsite()->getId();
274
        $customer = $this->customerFactory->create();
275
        $customer->setWebsiteId($websiteId);
276
        if ($socialProfile->email) {
277
            $customer->loadByEmail($socialProfile->email);
278
            if (!$customer->getId()) {
279
                $customer = $this->getCustomerData($socialProfile);
280
                $customer = $this->createNewAccount($customer);
281
            }
282
        }
283
284
        return $customer;
285
    }
286
287
    /**
288
     * Create New Account.
289
     *
290
     * @param CustomerFactory $customer
291
     *
292
     * @return CustomerFactory
293
     */
294
    public function createNewAccount($customer)
295
    {
296
        try {
297
            $customer = $this->accountManagement
298
                ->createAccount($customer);
299
300
            $confirmationStatus = $this->accountManagement->getConfirmationStatus($customer->getId());
301
            if ($confirmationStatus === AccountManagementInterface::ACCOUNT_CONFIRMATION_REQUIRED) {
302
                $this->messageManager->addComplexSuccessMessage(
303
                    'checkoutConfirmAccountSuccessMessage',
304
                    [
305
                        'url' => $this->customerUrl->getEmailConfirmationUrl($customer->getEmail()),
306
                    ]
307
                );
308
            } else {
309
                $this->customerSession->setCustomerDataAsLoggedIn($customer);
310
            }
311
            if ($this->cookieManager->getCookie('mage-cache-sessid')) {
312
                $metadata = $this->cookieMetadataFactory->createCookieMetadata();
313
                $metadata->setPath('/');
314
                $this->cookieManager->deleteCookie('mage-cache-sessid', $metadata);
315
            }
316
        } catch (\Exception $exc) {
317
            $this->messageManager->addError(__('Unable to create account.'));
0 ignored issues
show
Deprecated Code introduced by
The function Magento\Framework\Messag...erInterface::addError() has been deprecated: 100.1.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

317
            /** @scrutinizer ignore-deprecated */ $this->messageManager->addError(__('Unable to create account.'));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
318
            $this->messageManager->addError(__($exc->getMessage()));
0 ignored issues
show
Deprecated Code introduced by
The function Magento\Framework\Messag...erInterface::addError() has been deprecated: 100.1.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

318
            /** @scrutinizer ignore-deprecated */ $this->messageManager->addError(__($exc->getMessage()));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
319
        }
320
321
        return $customer;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $customer returns the type Magento\Customer\Api\Data\CustomerInterface which is incompatible with the documented return type Magento\Customer\Model\CustomerFactory.
Loading history...
322
    }
323
324
    /**
325
     * Login account.
326
     *
327
     * @param string $provider
328
     *
329
     * @throws LocalizedException
330
     *
331
     * @return void
332
     */
333
    public function login(string $provider): void
334
    {
335
        $hybridAuth = $this->hybridauthFactory->create([
336
            'config' => [
337
                'callback'  => $this->getEndpoint($provider),
338
                'providers' => $this->getProvidersConfig($provider),
339
            ],
340
        ]);
341
        $authenticate = $hybridAuth->authenticate($provider);
342
        if ($authenticate->isConnected()) {
343
            $socialProfile = $authenticate->getUserProfile();
344
            $customer = $this->setCustomerData($socialProfile);
345
            $this->customerSession->setCustomerDataAsLoggedIn($customer);
346
347
            if ($this->cookieManager->getCookie('mage-cache-sessid')) {
348
                $metadata = $this->cookieMetadataFactory->createCookieMetadata();
349
                $metadata->setPath('/');
350
                $this->cookieManager->deleteCookie('mage-cache-sessid', $metadata);
351
            }
352
        }
353
    }
354
355
    /**
356
     * Set Autenticate And Referer.
357
     *
358
     * @param string      $provider
359
     * @param int|null    $isSecure
360
     * @param string|null $referer
361
     *
362
     * @return array
363
     */
364
    public function setAutenticateAndReferer(string $provider, int $isSecure = 1, string $referer = null): array
0 ignored issues
show
Unused Code introduced by
The parameter $isSecure is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

364
    public function setAutenticateAndReferer(string $provider, /** @scrutinizer ignore-unused */ int $isSecure = 1, string $referer = null): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
365
    {
366
        if ($referer) {
367
            $this->accountRedirect->setRedirectCookie($referer);
0 ignored issues
show
Deprecated Code introduced by
The function Magento\Customer\Model\A...ct::setRedirectCookie() has been deprecated: 100.0.10 This is legacy method to pass login_redirect cookie ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

367
            /** @scrutinizer ignore-deprecated */ $this->accountRedirect->setRedirectCookie($referer);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
368
        }
369
370
        $redirect = $this->accountRedirect->getRedirectCookie();
0 ignored issues
show
Deprecated Code introduced by
The function Magento\Customer\Model\A...ct::getRedirectCookie() has been deprecated: 100.0.10 This is legacy method to pass login_redirect cookie ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

370
        $redirect = /** @scrutinizer ignore-deprecated */ $this->accountRedirect->getRedirectCookie();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
371
372
        $response['redirectUrl'] = $redirect;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$response was never initialized. Although not strictly required by PHP, it is generally a good practice to add $response = array(); before regardless.
Loading history...
373
374
        $hybridAuth = $this->hybridauthFactory->create([
375
            'config' => [
376
                'callback'  => $this->getEndpoint($provider),
377
                'providers' => $this->getProvidersConfig($provider),
378
            ],
379
        ]);
380
381
        try {
382
            $authenticate = $hybridAuth->authenticate($provider);
383
        } catch (Exception $e) {
384
            $this->messageManager->addError(__('Unable to login, try another way.'));
0 ignored issues
show
Deprecated Code introduced by
The function Magento\Framework\Messag...erInterface::addError() has been deprecated: 100.1.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

384
            /** @scrutinizer ignore-deprecated */ $this->messageManager->addError(__('Unable to login, try another way.'));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
385
386
            return $response;
387
        }
388
389
        if ($authenticate->isConnected()) {
390
            $socialProfile = $authenticate->getUserProfile();
391
            $customer = $this->setCustomerData($socialProfile);
392
            if ($customer->getId()) {
393
                $this->customerSession->getCustomerFormData(true);
394
                $customerId = $this->customerSession->getCustomerId();
0 ignored issues
show
Unused Code introduced by
The assignment to $customerId is dead and can be removed.
Loading history...
395
                $customerDataObject = $this->customerRepository->getById($customer->getId());
396
397
                $this->customerSession->setCustomerDataAsLoggedIn($customerDataObject);
398
399
                if ($this->cookieManager->getCookie('mage-cache-sessid')) {
400
                    $metadata = $this->cookieMetadataFactory->createCookieMetadata();
401
                    $metadata->setPath('/');
402
                    $this->cookieManager->deleteCookie('mage-cache-sessid', $metadata);
403
                }
404
405
                return $response;
406
            }
407
408
            $this->messageManager->addError(__('Unable to login, try another way.'));
0 ignored issues
show
Deprecated Code introduced by
The function Magento\Framework\Messag...erInterface::addError() has been deprecated: 100.1.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

408
            /** @scrutinizer ignore-deprecated */ $this->messageManager->addError(__('Unable to login, try another way.'));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
409
410
            return $response;
411
        }
0 ignored issues
show
Bug Best Practice introduced by
The function implicitly returns null when the if condition on line 389 is false. This is incompatible with the type-hinted return array. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
412
    }
413
}
414