Completed
Push — master ( 43ecd9...9c45ab )
by Brian
10:48
created

SocialiteWasCalled::extendSocialite()   B

Complexity

Conditions 4
Paths 2

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 11
cts 11
cp 1
rs 8.7972
c 0
b 0
f 0
cc 4
eloc 13
nc 2
nop 3
crap 4
1
<?php
2
3
namespace SocialiteProviders\Manager;
4
5
use Illuminate\Container\Container as Application;
6
use Laravel\Socialite\SocialiteManager;
7
use SocialiteProviders\Manager\Contracts\Helpers\ConfigRetrieverInterface;
8
use SocialiteProviders\Manager\Exception\InvalidArgumentException;
9
use SocialiteProviders\Manager\Exception\MissingConfigException;
10
11
class SocialiteWasCalled
12
{
13
    const SERVICE_CONTAINER_PREFIX = 'SocialiteProviders.config.';
14
15
    /**
16
     * @var LaravelApp
17
     */
18
    protected $app;
19
20
    /**
21
     * @var ConfigRetrieverInterface
22
     */
23
    private $configRetriever;
24
25
    /**
26
     * @var bool
27
     */
28
    public static $spoofedConfig = false;
29 10
30
    /**
31 10
     * @param LaravelApp               $app
32 10
     * @param ConfigRetrieverInterface $configRetriever
33 10
     */
34
    public function __construct(Application $app, ConfigRetrieverInterface $configRetriever)
35
    {
36
        $this->app = $app;
0 ignored issues
show
Documentation Bug introduced by
It seems like $app of type object<Illuminate\Container\Container> is incompatible with the declared type object<SocialiteProviders\Manager\LaravelApp> of property $app.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
37
        $this->configRetriever = $configRetriever;
38
    }
39
40
    /**
41
     * @param string $providerName  'meetup'
42
     * @param string $providerClass 'Your\Name\Space\ClassNameProvider' must extend
43
     *                              either Laravel\Socialite\Two\AbstractProvider or
44 10
     *                              Laravel\Socialite\One\AbstractProvider
45
     * @param string $oauth1Server  'Your\Name\Space\ClassNameServer' must extend League\OAuth1\Client\Server\Server
46
     *
47 10
     * @throws InvalidArgumentException
48 10
     */
49 4
    public function extendSocialite($providerName, $providerClass, $oauth1Server = null)
50 4
    {
51 4
        /** @var SocialiteManager $socialite */
52 4
        $socialite = $this->app->make(\Laravel\Socialite\Contracts\Factory::class);
53
54 4
        $this->classExists($providerClass);
55 4
        if ($this->isOAuth1($oauth1Server)) {
56
            $this->classExists($oauth1Server);
57
            $this->classExtends($providerClass, \Laravel\Socialite\One\AbstractProvider::class);
58
        }
59
60
        $socialite->extend(
61
            $providerName,
62
            function () use ($socialite, $providerName, $providerClass, $oauth1Server) {
63
                $provider = $this->buildProvider($socialite, $providerName, $providerClass, $oauth1Server);
64
                if (defined('SOCIALITEPROVIDERS_STATELESS') && SOCIALITEPROVIDERS_STATELESS) {
65 10
                    return $provider->stateless();
0 ignored issues
show
Bug introduced by
The method stateless does only exist in Laravel\Socialite\Two\AbstractProvider, but not in Laravel\Socialite\One\AbstractProvider.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
66
                }
67 10
68
                return $provider;
69 7
            }
70 3
        );
71 2
    }
72 2
73
    /**
74
     * @param SocialiteManager $socialite
75 4
     * @param                  $providerName
76 3
     * @param string           $providerClass
77
     * @param null|string      $oauth1Server
78
     *
79
     * @return \Laravel\Socialite\One\AbstractProvider|\Laravel\Socialite\Two\AbstractProvider
80
     */
81
    protected function buildProvider(SocialiteManager $socialite, $providerName, $providerClass, $oauth1Server)
82
    {
83
        if ($this->isOAuth1($oauth1Server)) {
84
            return $this->buildOAuth1Provider($socialite, $providerClass, $providerName, $oauth1Server);
85
        }
86
87
        return $this->buildOAuth2Provider($socialite, $providerClass, $providerName);
88 2
    }
89
90 2
    /**
91 1
     * Build an OAuth 1 provider instance.
92
     *
93 1
     * @param string $providerClass must extend Laravel\Socialite\One\AbstractProvider
94 1
     * @param string $oauth1Server  must extend League\OAuth1\Client\Server\Server
95 1
     * @param array  $config
0 ignored issues
show
Bug introduced by
There is no parameter named $config. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
96
     *
97
     * @return \Laravel\Socialite\One\AbstractProvider
98
     */
99
    protected function buildOAuth1Provider(SocialiteManager $socialite, $providerClass, $providerName, $oauth1Server)
100
    {
101
        $this->classExtends($oauth1Server, \League\OAuth1\Client\Server\Server::class);
102
103
        $config = $this->getConfig($providerClass, $providerName);
104
105
        $configServer = $socialite->formatConfig($config->get());
106
107 3
        $provider = new $providerClass(
108
            $this->app->offsetGet('request'), new $oauth1Server($configServer)
109 3
        );
110
111 3
        $provider->setConfig($config);
112
113
        return $provider;
114
    }
115
116
    /**
117
     * Build an OAuth 2 provider instance.
118
     *
119
     * @param SocialiteManager $socialite
120
     * @param string           $providerClass must extend Laravel\Socialite\Two\AbstractProvider
121 6
     * @param array            $config
0 ignored issues
show
Bug introduced by
There is no parameter named $config. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
122
     *
123 6
     * @return \Laravel\Socialite\Two\AbstractProvider
124 6
     */
125 6
    protected function buildOAuth2Provider(SocialiteManager $socialite, $providerClass, $providerName)
126
    {
127 6
        $this->classExtends($providerClass, \Laravel\Socialite\Two\AbstractProvider::class);
128 4
129 2
        $config = $this->getConfig($providerClass, $providerName);
130 2
131
        $provider = $socialite->buildProvider($providerClass, $config->get());
132
133 2
        $provider->setConfig($config);
134
135 2
        return $provider;
136 1
    }
137 1
138 1
    /**
139
     * @param string $providerClass
140
     * @param string $providerName
141 1
     *
142
     * @throws MissingConfigException
143
     *
144
     * @return array
145
     */
146
    protected function getConfig($providerClass, $providerName)
147
    {
148
        $config = null;
149
        $additionalConfigKeys = $providerClass::additionalConfigKeys();
150
        $exceptionMessages = [];
151 7
        try {
152
            $config = $this->configRetriever->fromEnv($providerClass::IDENTIFIER, $additionalConfigKeys);
153 7
154
            // We will use the $spoofedConfig variable for now as a way to find out if there was no
155
            // configuration in the .env file which means we should not return anything and jump
156
            // to the service config check to check if something can be found there.
157
            if (!static::$spoofedConfig) {
158
                return $config;
159
            }
160
        } catch (MissingConfigException $e) {
161
            $exceptionMessages[] = $e->getMessage();
162 5
        }
163
164 5
        $config = null;
165 1
        try {
166 1
            $config = $this->configRetriever->fromServices($providerName, $additionalConfigKeys);
167
168 4
            // Here we don't need to check for the $spoofedConfig variable because this will be
169
            // the end of checking for config and should contain either the proper data or an
170 10
            // array containing spoofed values.
171
            return $config;
172 10
        } catch (MissingConfigException $e) {
173 4
            $exceptionMessages[] = $e->getMessage();
174
        }
175 7
176
        throw new MissingConfigException(implode(PHP_EOL, $exceptionMessages));
177
    }
178
179
    /**
180
     * Check if a server is given, which indicates that OAuth1 is used.
181
     *
182
     * @param string $oauth1Server
183
     *
184
     * @return bool
185
     */
186
    private function isOAuth1($oauth1Server)
187
    {
188
        return !empty($oauth1Server);
189
    }
190
191
    /**
192
     * @param string $class
193
     * @param string $baseClass
194
     *
195
     * @throws InvalidArgumentException
196
     */
197
    private function classExtends($class, $baseClass)
198
    {
199
        if (false === is_subclass_of($class, $baseClass)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if $baseClass can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
200
            $message = $class.' does not extend '.$baseClass;
201
            throw new InvalidArgumentException($message);
202
        }
203
    }
204
205
    private function classExists($providerClass)
206
    {
207
        if (!class_exists($providerClass)) {
208
            throw new InvalidArgumentException("$providerClass doesn't exist");
209
        }
210
    }
211
}
212