Completed
Push — master ( acbb74...fdb3a6 )
by PROSPER
03:54
created

OauthController::checkIfUserNeedsUpdating()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
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\Http\Requests;
8
use App\Http\Controllers\Controller;
9
use Illuminate\Contracts\Auth\Guard;
10
use Laravel\Socialite\Contracts\Factory as Socialite;
11
use App\User;
12
13
class OauthController extends Controller
14
{
15
    protected $socialite;
16
    protected $auth;
17
18
    public function __construct(Socialite $socialite, Guard $auth)
19
    {
20
        $this->socialite = $socialite;
21
        $this->auth = $auth;
22
    }
23
24
    public function authenticate(Request $request, $provider)
25
    {
26
        return $this->execute(($request->has('code') || $request->has('oauth_token')), $provider);
27
    }
28
29
    public function execute($request, $provider)
30
    {
31
        if (! $request) {
32
            return $this->getAuthorizationFirst($provider);
33
        }
34
35
        $user = $this->findByProviderIdOrCreate($this->getSocialUser($provider), $provider);
36
        $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...
37
38
        return redirect('/api');
39
    }
40
41
    /**
42
     * Find a user by username or create a new user
43
     * @param
44
     * @return
45
     */
46
    public function findByProviderIdOrCreate($userData, $provider)
47
    {
48
        $user = User::where('provider_id', '=', $userData->id)->first();
49
50
        if (empty($user))  {
51
            $user = User::create([
52
                'fullname'      => $userData->getName(),
53
                'username'      => $userData->getNickName(),
54
                'provider_id'   => $userData->getId(),
55
                'avatar'        => $userData->getAvatar(),
56
                'email'         => $userData->getEmail(),
57
                'provider'      => $provider,
58
            ]);
59
        }
60
61
        $this->checkIfUserNeedsUpdating($userData, $user);
62
63
        return $user;
64
    }
65
66
    /**
67
     * Check if the user's info needs updating
68
     * @param
69
     * @return
70
     */
71
    public function checkIfUserNeedsUpdating($userData, $user)
72
    {
73
        $socialData = [
74
            'avatar' => $userData->getAvatar(),
75
            'fullname' => $userData->getName(),
76
            'username' => $userData->getId(),
77
        ];
78
79
        $dbData = [
80
            'avatar' => $user->avatar,
81
            'fullname' => $user->fullname,
82
            'username' => $user->username,
83
        ];
84
85
        if (! empty(array_diff($dbData, $socialData))) {
86
            $user->avatar = $userData->getAvatar();
87
            $user->fullname = $userData->getName();
88
            $user->username = $userData->getId();
89
            $user->save();
90
        }
91
    }
92
93
    /**
94
     * Redirect the user to the Social Media Account authentication page
95
     * @param $provider
96
     * @return \Symfony\Component\HttpFoundation\RedirectResponse
97
     */
98
    private function getAuthorizationFirst($provider)
99
    {
100
        return $this->socialite->driver($provider)->redirect();
101
    }
102
103
    /**
104
     * Get Data from Social Media Account
105
     * @param  string $provider
106
     * @return collection
107
     */
108
    private function getSocialUser($provider)
109
    {
110
        return $this->socialite->driver($provider)->user();
111
    }
112
113
}
114
115