Completed
Push — master ( fc55b8...468cb3 )
by PROSPER
02:13
created

OauthController::checkIfUserNeedsUpdating()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 21
rs 9.3142
cc 2
eloc 14
nc 2
nop 2
1
<?php
2
3
namespace App\Http\Controllers;
4
5
use Illuminate\Http\Request;
6
7
use App\User;
8
use App\Http\Requests;
9
use Illuminate\Contracts\Auth\Guard;
10
use App\Http\Controllers\Controller;
11
use Laravel\Socialite\Contracts\Factory as Socialite;
12
13
14
class OauthController extends Controller
15
{
16
    protected $socialite;
17
    protected $auth;
18
19
    public function __construct(Socialite $socialite, Guard $auth)
20
    {
21
        $this->socialite = $socialite;
22
        $this->auth = $auth;
23
    }
24
25
    public function authenticate(Request $request, $provider)
26
    {
27
        return $this->execute(($request->has('code') || $request->has('oauth_token')), $provider);
28
    }
29
30
    public function execute($request, $provider)
31
    {
32
        if (! $request) {
33
            return $this->getAuthorizationFirst($provider);
34
        }
35
36
        $user = $this->findByProviderIdOrCreate($this->getSocialUser($provider), $provider);
37
        $this->auth->loginUsingId($user->id);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Illuminate\Contracts\Auth\Guard as the method loginUsingId() does only exist in the following implementations of said interface: Illuminate\Auth\SessionGuard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
38
39
        return redirect('/api');
40
    }
41
42
    /**
43
     * Find a user by username or create a new user
44
     * @param
45
     * @return
46
     */
47
    public function findByProviderIdOrCreate($userData, $provider)
48
    {
49
        $user = User::where('provider_id', '=', $userData->id)->first();
50
51
        $email = $this->isEmailExists($userData->getEmail()) ? null : $userData->getEmail();
52
53
        $username = $this->isUsernameExists($userData->getNickName()) ? null : $userData->getNickName();
54
55
        if (empty($user))  {
56
            $user = User::create([
57
                'fullname'      => $userData->getName(),
58
                'username'      => $username,
59
                'provider_id'   => $userData->getId(),
60
                'avatar'        => $userData->getAvatar(),
61
                'email'         => $email,
62
                'provider'      => $provider,
63
            ]);
64
        }
65
66
        return $user;
67
    }
68
69
    private function isUsernameExists($username = null)
70
    {
71
        $username = User::whereUsername($username)->first()['username'];
72
73
        return (! is_null($username)) ? true : false;
74
    }
75
76
    private function isEmailExists($email = null)
77
    {
78
        $email = User::whereEmail($email)->first()['email'];
79
80
        return (! is_null($email)) ? true : false;
81
    }
82
83
    /**
84
     * Check if the user's info needs updating
85
     * @param
86
     * @return
87
     */
88
    public function checkIfUserNeedsUpdating($userData, $user)
89
    {
90
        $socialData = [
91
            'avatar' => $userData->getAvatar(),
92
            'fullname' => $userData->getName(),
93
            'username' => $userData->getNickName(),
94
        ];
95
96
        $dbData = [
97
            'avatar' => $user->avatar,
98
            'fullname' => $user->fullname,
99
            'username' => $user->username,
100
        ];
101
102
        if (! empty(array_diff($dbData, $socialData))) {
103
            $user->avatar = $userData->getAvatar();
104
            $user->fullname = $userData->getName();
105
            $user->username = $userData->getNickName();
106
            $user->save();
107
        }
108
    }
109
110
    /**
111
     * Redirect the user to the Social Media Account authentication page
112
     * @param $provider
113
     * @return \Symfony\Component\HttpFoundation\RedirectResponse
114
     */
115
    private function getAuthorizationFirst($provider)
116
    {
117
        return $this->socialite->driver($provider)->redirect();
118
    }
119
120
    /**
121
     * Get Data from Social Media Account
122
     * @param  string $provider
123
     * @return collection
124
     */
125
    private function getSocialUser($provider)
126
    {
127
        return $this->socialite->driver($provider)->user();
128
    }
129
130
}
131
132