OauthController::authenticate()   A
last analyzed

Complexity

Conditions 2
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace App\Http\Controllers;
4
5
use Illuminate\Http\Request;
6
use App\User;
7
use App\Http\Requests;
8
use Illuminate\Contracts\Auth\Guard;
9
use Laravel\Socialite\Contracts\Factory as Socialite;
10
use Session;
11
12
class OauthController extends Controller
13
{
14
    protected $socialite;
15
    protected $auth;
16
17
    public function __construct(Socialite $socialite, Guard $auth)
18
    {
19
        $this->socialite = $socialite;
20
        $this->auth = $auth;
21
    }
22
23
    public function authenticate(Request $request, $provider)
24
    {
25
        return $this->execute(($request->has('code') || $request->has('oauth_token')), $provider);
26
    }
27
28
    public function execute($request, $provider)
29
    {
30
        if (! $request) {
31
            return $this->getAuthorizationFirst($provider);
32
        }
33
34
        $user = $this->findByProviderIdOrCreate($this->getSocialUser($provider), $provider);
35
        $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...
Documentation introduced by
The property id does not exist on object<App\User>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
36
37
        return redirect('/api');
38
    }
39
40
    /**
41
     * Find a user by username or create a new user
42
     *
43
     * @param $userData
44
     * @param $provider
45
     *
46
     * @return \App\User
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 $userData
96
     * @param $user
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