Test Failed
Push — master ( 4cd501...1b9ce5 )
by Stiofan
07:38
created

GDGoogleAnalyticsStats::getMetrics()   C

Complexity

Conditions 7
Paths 48

Size

Total Lines 48
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 27
nc 48
nop 8
dl 0
loc 48
rs 6.7272
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
4
/**
5
 * Handles interactions with Google Analytics' Stat API
6
 *
7
 **/
8
class GDGoogleAnalyticsStats
9
{
10
11
	var $client = false;
12
	var $accountId;
13
	var $baseFeed = 'https://www.googleapis.com/analytics/v3';
14
	var $token = false;
15
16
17
	/**
18
	 * Constructor
19
	 *
20
	 * @param token - a one-time use token to be exchanged for a real token
21
	 **/
22
	public function __construct()
23
	{
24
25
			# Include SimplePie if it doesn't exist
26
			if ( !class_exists('SimplePie') ) {
27
				require_once (ABSPATH . WPINC . '/class-feed.php');
28
			}
29
			
30
			if ( !class_exists('Google_Client') ) {
31
				require_once 'google-api-php-client/src/Google_Client.php';
32
			}
33
			if ( !class_exists('Google_AnalyticsService') ) {
34
				require_once 'google-api-php-client/src/contrib/Google_AnalyticsService.php';
35
			}
36
37
            $this->client = new Google_Client();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Google_Client() of type object<Google_Client> is incompatible with the declared type boolean of property $client.

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...
38
            $this->client->setApprovalPrompt("force");
39
            $this->client->setAccessType('offline');
40
            $this->client->setClientId(GEODIR_GA_CLIENTID);
41
            $this->client->setClientSecret(GEODIR_GA_CLIENTSECRET);
42
            $this->client->setRedirectUri(GEODIR_GA_REDIRECT);
43
			
44
            $this->client->setScopes(array("https://www.googleapis.com/auth/analytics"));
45
46
            // Magic. Returns objects from the Analytics Service instead of associative arrays.
47
            $this->client->setUseObjects(true);
48
49
            try {
50
                    $this->analytics = new Google_AnalyticsService($this->client);
0 ignored issues
show
Bug introduced by
The property analytics does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
51
                }
52
            catch (Google_ServiceException $e)
53
                {
54
                    print '(cas:48) There was an Analytics API service error ' . $e->getCode() . ':' . $e->getMessage();
55
					return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
56
                }
57
	}
58
59
	function checkLogin()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
60
	{
61
            $ga_google_authtoken = get_option('geodir_ga_auth_token');
62
63
            if (!empty($ga_google_authtoken))
64
            {
65
				try
66
                {
67
                    $this->client->setAccessToken($ga_google_authtoken);
0 ignored issues
show
Bug introduced by
The method setAccessToken cannot be called on $this->client (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
68
				}
69
				catch( Google_AuthException $e )
70
                {
71
                    print '(cas:72) GeoDirectory was unable to authenticate you with
72
                            Google using the Auth Token you pasted into the input box on the previous step. <br><br>
73
                            This could mean either you pasted the token wrong, or the time/date on your server is wrong,
74
                            or an SSL issue preventing Google from Authenticating. <br><br>
75
                            <br><br><strong>Tech Info </strong> ' . $e->getCode() . ':' . $e->getMessage();
76
77
                    return false;
78
                }
79
            }
80
            else
81
            {
82
                $authCode = get_option('geodir_ga_auth_code');
83
84
                if (empty($authCode)) return false;
85
86
                try
87
                {
88
                    $accessToken = $this->client->authenticate($authCode);
0 ignored issues
show
Bug introduced by
The method authenticate cannot be called on $this->client (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
89
                }
90
                catch( Exception $e )
91
                {
92
                    print '(cas:72) GeoDirectory was unable to authenticate you with
93
                            Google using the Auth Token you pasted into the input box on the previous step. <br><br>
94
                            This could mean either you pasted the token wrong, or the time/date on your server is wrong,
95
                            or an SSL issue preventing Google from Authenticating. <br><br>
96
                            <br><br><strong>Tech Info </strong> ' . $e->getCode() . ':' . $e->getMessage();
97
98
                    return false;
99
                }
100
101
                if($accessToken)
102
                {
103
                    $this->client->setAccessToken($accessToken);
0 ignored issues
show
Bug introduced by
The method setAccessToken cannot be called on $this->client (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
104
                    update_option('geodir_ga_auth_token', $accessToken);
105
                }
106
                else
107
                {
108
                    return false;
109
                }
110
            }
111
112
            $this->token =  $this->client->getAccessToken();
0 ignored issues
show
Bug introduced by
The method getAccessToken cannot be called on $this->client (of type boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
113
            return true;
114
	}
115
116
	function deauthorize()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
117
	{
118
            update_option('geodir_ga_auth_code', '');
119
            update_option('geodir_ga_auth_token', '');
120
	}
121
122
	function getSingleProfile()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
123
	{
124
            $webproperty_id = get_option('geodir_ga_account_id');
125
            list($pre, $account_id, $post) = explode('-',$webproperty_id);
0 ignored issues
show
Unused Code introduced by
The assignment to $pre is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
Unused Code introduced by
The assignment to $post is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
126
127
            if (empty($webproperty_id)) return false;
128
129
            try {
130
                $profiles = $this->analytics->management_profiles->listManagementProfiles($account_id, $webproperty_id);
131
            }
132
            catch (Google_ServiceException $e)
133
            {
134
                print 'There was an Analytics API service error ' . $e->getCode() . ': ' . $e->getMessage();
135
                return false;
136
            }
137
138
            $profile_id = $profiles->items[0]->id;
139
            if (empty($profile_id)) return false;
140
141
            $account_array = array();
142
            array_push($account_array, array('id'=>$profile_id, 'ga:webPropertyId'=>$webproperty_id));
143
            return $account_array;
144
	}
145
146
        function getAllProfiles()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
147
        {
148
            $profile_array = array();
149
            
150
            try {
151
                    $profiles = $this->analytics->management_webproperties->listManagementWebproperties('~all');
152
                }
153
                catch (Google_ServiceException $e)
154
                {
155
                    print 'There was an Analytics API service error ' . $e->getCode() . ': ' . $e->getMessage();
156
                }
157
158
159
            if( !empty( $profiles->items ) )
160
            {
161
                foreach( $profiles->items as $profile )
162
                {
163
                    $profile_array[ $profile->id ] = str_replace('http://','',$profile->name );
164
                }
165
            }
166
167
            return $profile_array;
168
        }
169
170
	function getAnalyticsAccounts()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
171
	{
172
		$analytics = new Google_AnalyticsService($this->client);
0 ignored issues
show
Documentation introduced by
$this->client is of type boolean, but the function expects a object<Google_Client>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
173
		$accounts = $analytics->management_accounts->listManagementAccounts();
174
		$account_array = array();
175
176
		$items = $accounts->getItems();
177
178
		if (count($items) > 0) {
179
			foreach ($items as $key => $item)
180
			{
181
				$account_id = $item->getId();
182
183
				$webproperties = $analytics->management_webproperties->listManagementWebproperties($account_id);
184
185
				if (!empty($webproperties))
186
				{
187
					foreach ($webproperties->getItems() as $webp_key => $webp_item) {
188
						$profiles = $analytics->management_profiles->listManagementProfiles($account_id, $webp_item->id);
189
190
						$profile_id = $profiles->items[0]->id;
191
						array_push($account_array, array('id'=>$profile_id, 'ga:webPropertyId'=>$webp_item->id));
192
					}
193
				}
194
			}
195
196
			return $account_array;
197
		}
198
		return false;
199
200
	}
201
202
203
204
	/**
205
	 * Sets the account id to use for queries
206
	 *
207
	 * @param id - the account id
208
	 **/
209
	function setAccount($id)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
210
	{
211
		$this->accountId = $id;
212
	}
213
214
215
	/**
216
	 * Get a specific data metrics
217
	 *
218
	 * @param metrics - the metrics to get
219
	 * @param startDate - the start date to get
220
	 * @param endDate - the end date to get
221
	 * @param dimensions - the dimensions to grab
222
	 * @param sort - the properties to sort on
223
	 * @param filter - the property to filter on
224
	 * @param limit - the number of items to get
225
	 * @param realtime - if the realtime api should be used
226
	 * @return the specific metrics in array form
227
	 **/
228
	function getMetrics($metric, $startDate, $endDate, $dimensions = false, $sort = false, $filter = false, $limit = false, $realtime = false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
229
	{
230
		$analytics = new Google_AnalyticsService($this->client);
0 ignored issues
show
Documentation introduced by
$this->client is of type boolean, but the function expects a object<Google_Client>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
231
232
		$params = array();
233
234
		if ($dimensions)
235
		{
236
			$params['dimensions'] = $dimensions;
237
		}
238
		if ($sort)
239
		{
240
			$params['sort'] = $sort;
241
		}
242
		if ($filter)
243
		{
244
			$params['filters'] = $filter;
245
		}
246
		if ($limit)
247
		{
248
			$params['max-results'] = $limit;
249
		}
250
           
251
           // Just incase, the ga: is still used in the account id, strip it out to prevent it breaking
252
           $filtered_id = str_replace( 'ga:', '', $this->accountId );
253
           
254
           if(!$filtered_id){
255
                echo 'Error - Account ID is blank';
256
                return false;
257
           }
258
259
		if($realtime){
260
			return $analytics->data_realtime->get(
261
				'ga:'.$filtered_id,
262
				$metric,
263
				$params
264
			);
265
		}else{
266
			return $analytics->data_ga->get(
267
				'ga:'.$filtered_id,
268
				$startDate,
269
				$endDate,
270
				$metric,
271
				$params
272
			);
273
		}
274
275
	}
276
277
278
279
280
281
	/**
282
	 * Checks the date against Jan. 1 2005 because GA API only works until that date
283
	 *
284
	 * @param date - the date to compare
285
	 * @return the correct date
286
	 **/
287
	function verifyStartDate($date)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
288
	{
289
		if ( strtotime($date) > strtotime('2005-01-01') )
290
			return $date;
291
		else
292
			return '2005-01-01';
0 ignored issues
show
Bug Best Practice introduced by
The return type of return '2005-01-01'; (string) is incompatible with the return type documented by GDGoogleAnalyticsStats::verifyStartDate of type the.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
293
	}
294
295
} // END class