ResourceAbstract   B
last analyzed

Complexity

Total Complexity 45

Size/Duplication

Total Lines 194
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 0%

Importance

Changes 11
Bugs 5 Features 3
Metric Value
wmc 45
c 11
b 5
f 3
lcom 1
cbo 5
dl 0
loc 194
ccs 0
cts 98
cp 0
rs 8.3673

6 Methods

Rating   Name   Duplication   Size   Complexity  
D validate_arguments() 0 46 25
A __construct() 0 10 2
C call() 0 65 15
A getClient() 0 3 1
A getResourceName() 0 3 1
A getMethods() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like ResourceAbstract often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ResourceAbstract, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Redbox\Twitch\Resource;
3
use Redbox\Twitch\Exception;
4
use Redbox\Twitch\Transport\HttpRequest;
5
use Redbox\Twitch;
6
7
class ResourceAbstract
8
{
9
    /**
10
     * @var array
11
     */
12
    private $methods;
13
14
    /**
15
     * @var Twitch\Client
16
     */
17
    private $client;
18
19
    /**
20
     * @var string
21
     */
22
    private $resource_name;
23
24
    /**
25
     * @var array
26
     */
27
    private $url_parts = array();
28
29
30
    /**
31
     * ResourceAbstract constructor.
32
     *
33
     * @param Twitch\Client $client
34
     * @param string $resource_name
35
     * @param array $declaration
36
     */
37
    public function __construct(Twitch\Client $client, $resource_name = "", $declaration = [])
38
    {
39
        $this->client        = $client;
40
        $this->resource_name = $resource_name;
41
        $this->methods       = isset($declaration['methods']) ? $declaration['methods'] : [];
42
43
        // If this line gives errros .. Comment it out because somewhere in the resource it self is an error.
44
      //  $client->registerResource($this->resource_name, $this);
45
        // Todo validate resources
46
    }
47
48
    /**
49
     * Validate arguments given for a 'virtual' method.
50
     *
51
     * @param string $method_name
52
     * @param array $args
53
     * @return bool
54
     * @throws Exception\RuntimeException
55
     */
56
    private function validate_arguments($method_name = '', $args = array())
57
    {
58
        if (isset($this->methods[$method_name]) === true) {
59
            $method = $this->methods[$method_name];
60
            if (isset($method['parameters']) === true and is_array($method['parameters']) === true) {
61
                $parameters = $method['parameters'];
62
                foreach ($parameters as $name => $options) {
63
                    switch ($options['type']) {
64
                        case 'integer':
65
                            // todo implment default value as seen in team
66
67
                            // Required
68
                            if (isset($options['required']) === true and $options['required'] === true and isset($args[$name]) === false)
69
                                throw new Exception\RuntimeException($this->resource_name.' requires parameter '.$name.' to be given for method '.$method_name);
70
71
                            // Min
72
                            if (isset($options['min']) === true and (isset($args[$name]) === true and $args[$name] < $options['min']))
73
                                throw new Exception\RuntimeException($this->resource_name . ' requires parameter ' . $name . ' to have a minimum value of ' . $options['min'] . ' for method ' . $method_name);
74
75
                            // Min
76
                            if (isset($options['max']) === true and (isset($args[$name]) === true and $args[$name] > $options['max']))
77
                                throw new Exception\RuntimeException($this->resource_name . ' requires parameter ' . $name . ' to have a maximum value of ' . $options['min'] . ' for method ' . $method_name);
78
79
80
                            break;
81
                        case 'string':
82
83
                            // Required
84
                            if (isset($options['required']) === true and $options['required'] === true and isset($args[$name]) === false)
85
                                throw new Exception\RuntimeException($this->resource_name . ' requires parameter ' . $name . ' to be given for method ' . $method_name);
86
87
                            // todo add validator for restricted_value
88
89
                            // Url Part
90
                            if (isset($options['url_part']) === true and $options['url_part'] === true and isset($args[$name]) === false) {
91
                                throw new Exception\RuntimeException($this->resource_name . ' requires parameter ' . $name . ' to be given for method ' . $method_name);
92
                            } else if (isset($options['url_part']) === true and $options['url_part'] == true and isset($args[$name]) === true) {
93
                                $this->url_parts[$method_name][':' . $name] = array('name' => $name, 'value' => $args[$name]);
94
                            }
95
                            break;
96
                    }
97
                }
98
            }
99
        }
100
        return true;
101
    }
102
103
    /**
104
     * Call and process the 'virtual' method as defined in Client.php
105
     *
106
     * @param string $method
107
     * @param array $arguments
108
     * @param array $body
109
     * @return mixed
110
     * @throws Exception\AuthorizationRequiredException
111
     * @throws Exception\RuntimeException
112
     */
113
    public function call($method, $arguments = array(), $body = array())
114
    {
115
        if ($this->validate_arguments($method, $arguments) === true)
116
        {
117
118
            $headers = array();
119
            $headers['Accept']    = 'application/vnd.twitchtv.v3+json';
120
            $headers['Client-ID'] = $this->client->getClientId();
121
122
            if (isset($this->methods[$method]['requiresAuth']) === true) {
123
                if ($this->methods[$method]['requiresAuth'] === true && !$this->client->getAccessToken()) {
124
                    throw new Exception\AuthorizationRequiredException('Method: '.$method.' requires authorization. Did you forget to use setAccessToken() ?');
125
                }
126
            }
127
128
            if (isset($this->methods[$method]['requireScope']) == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
129
                /* Should the be an auth exception ? */
130
                throw new Exception\AuthorizationRequiredException('Method: '.$method.' did not set define any scope.');
131
            } else {
132
                $client_scope = $this->getClient()->getScope();
133
                $required_scope = $this->methods[$method]['requireScope'];
134
                foreach($required_scope as $scope) {
135
                    if (in_array($scope, $client_scope) == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
136
                        throw new Exception\AuthorizationRequiredException('Method: '.$method.' requires scope: '.$scope.' to be set.');
137
                    }
138
                }
139
140
            }
141
142
            if ($this->client->getAccessToken())
143
                $headers['Authorization'] = 'OAuth ' . $this->client->getAccessToken();
144
145
146
            if (isset($this->url_parts[$method]) === true and is_array($this->url_parts[$method]) === true) {
147
                if (count($this->url_parts[$method]) > 0) {
148
                    foreach ($this->url_parts[$method] as $key => $url_part) {
149
                        $this->methods[$method]['path'] = str_replace($key, $url_part['value'], $this->methods[$method]['path']);
150
                        unset($arguments[$url_part['name']]);
151
                    }
152
                }
153
            }
154
155
            $url = '/'.$this->methods[$method]['path'];
156
157
            $count = 0;
158
            while ($value = current($arguments)) {
159
                $url .= (($count > 0) ? '&' : '?').key($arguments).'='.urlencode($value);
160
                next($arguments);
161
                $count++;
162
            }
163
164
            $request = new HttpRequest(
165
                $url,
166
                $this->methods[$method]['httpMethod'],
167
                $headers,
168
                $body
169
            );
170
171
            $response = $this->client->getTransport()->sendRequest(
172
                $request
173
            );
174
175
            return $response;
176
        }
177
    }
178
179
    /**
180
     * @return Client
181
     */
182
    public function getClient() {
183
        return $this->client;
184
    }
185
186
    /**
187
     * @return string
188
     */
189
    public function getResourceName() {
190
        return $this->resource_name;
191
    }
192
193
    /**
194
     * @return array
195
     */
196
    public function getMethods() {
197
        return $this->methods;
198
    }
199
200
}