Completed
Push — master ( 55f4d0...97c563 )
by PROSPER
03:11
created

OauthController::findByProviderIdOrCreate()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 1 Features 2
Metric Value
c 5
b 1
f 2
dl 0
loc 30
rs 8.439
cc 5
eloc 18
nc 16
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
use Session;
13
14
15
class OauthController extends Controller
16
{
17
    protected $socialite;
18
    protected $auth;
19
20
    public function __construct(Socialite $socialite, Guard $auth)
21
    {
22
        $this->socialite = $socialite;
23
        $this->auth = $auth;
24
    }
25
26
    public function authenticate(Request $request, $provider)
27
    {
28
        return $this->execute(($request->has('code') || $request->has('oauth_token')), $provider);
29
    }
30
31
    public function execute($request, $provider)
32
    {
33
        if (! $request) {
34
            return $this->getAuthorizationFirst($provider);
35
        }
36
37
        $user = $this->findByProviderIdOrCreate($this->getSocialUser($provider), $provider);
38
        $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...
39
40
        return redirect('/api');
41
    }
42
43
    /**
44
     * Find a user by username or create a new user
45
     * @param
46
     * @return
47
     */
48
    public function findByProviderIdOrCreate($userData, $provider)
49
    {
50
        $user = User::where('provider_id', '=', $userData->id)->first();
51
52
        Session::put('provider', $provider);
53
54
        $email = $this->isEmailExists($userData->getEmail()) ? null : $userData->getEmail();
55
56
        $username = $this->isUsernameExists($userData->getNickName()) ? null : $userData->getNickName();
57
58
        $tokenSecret = property_exists($userData, "tokenSecret") ? $userData->tokenSecret : null;
59
60
        if (empty($user))  {
61
62
            $user = User::create([
63
                'fullname'      => $userData->getName(),
64
                'username'      => $username,
65
                'provider_id'   => $userData->getId(),
66
                'avatar'        => $userData->getAvatar(),
67
                'email'         => $email,
68
                'provider'      => $provider,
69
                'oauth_token'   => $userData->token,
70
                'oauth_token_secret'   => $tokenSecret
71
            ]);
72
73
            Session::put('provider', $provider);
74
        }
75
76
        return $user;
77
    }
78
79
    private function isUsernameExists($username = null)
80
    {
81
        $username = User::whereUsername($username)->first()['username'];
82
83
        return (! is_null($username)) ? true : false;
84
    }
85
86
    private function isEmailExists($email = null)
87
    {
88
        $email = User::whereEmail($email)->first()['email'];
89
90
        return (! is_null($email)) ? true : false;
91
    }
92
93
    /**
94
     * Check if the user's info needs updating
95
     * @param
96
     * @return
97
     */
98
    public function checkIfUserNeedsUpdating($userData, $user)
99
    {
100
        $socialData = [
101
            'avatar' => $userData->getAvatar(),
102
            'fullname' => $userData->getName(),
103
            'username' => $userData->getNickName(),
104
        ];
105
106
        $dbData = [
107
            'avatar' => $user->avatar,
108
            'fullname' => $user->fullname,
109
            'username' => $user->username,
110
        ];
111
112
        if (! empty(array_diff($dbData, $socialData))) {
113
            $user->avatar = $userData->getAvatar();
114
            $user->fullname = $userData->getName();
115
            $user->username = $userData->getNickName();
116
            $user->save();
117
        }
118
    }
119
120
    /**
121
     * Redirect the user to the Social Media Account authentication page
122
     * @param $provider
123
     * @return \Symfony\Component\HttpFoundation\RedirectResponse
124
     */
125
    private function getAuthorizationFirst($provider)
126
    {
127
        return $this->socialite->driver($provider)->redirect();
128
    }
129
130
    /**
131
     * Get Data from Social Media Account
132
     * @param  string $provider
133
     * @return collection
134
     */
135
    private function getSocialUser($provider)
136
    {
137
        return $this->socialite->driver($provider)->user();
138
    }
139
140
}
141
142