ar_connect_twitter::friendlyDate()   D
last analyzed

Complexity

Conditions 18
Paths 192

Size

Total Lines 58

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 342

Importance

Changes 0
Metric Value
cc 18
nc 192
nop 3
dl 0
loc 58
rs 4.1
c 0
b 0
f 0
ccs 0
cts 56
cp 0
crap 342

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
ar_pinp::allow('ar_connect_twitter');
4
ar_pinp::allow('ar_connect_twitterClient');
5
6
class ar_connect_twitter extends arBase {
7
8
	public static function client( $httpClient = null ) {
9
		return new ar_connect_twitterClient( $httpClient );
10
	}
11
12
	public static function parse( $text, $parseTwitterLinks = true ) {
13
		// FIXME: allow normal links and mailto links to be specified like the user and argument links
14
		// link URLs
15
		$text = " ".preg_replace(
16
			"/(([[:alnum:]]+:\/\/)|www\.)([^[:space:]]*)([[:alnum:]#?\/&=])/i",
17
			"<a href=\"\\1\\3\\4\" target=\"_blank\">\\1\\3\\4</a>", $text);
18
19
		// link mailtos
20
		$text = preg_replace(
21
			"/(([a-z0-9_]|\\-|\\.)+@([^[:space:]]*)([[:alnum:]-]))/i",
22
			"<a href=\"mailto:\\1\">\\1</a>", $text);
23
24
		if ( $parseTwitterLinks ) {
25
			if ( is_array($parseTwitterLinks) ) {
26
				$userLink = $parseTwitterLinks['user'];
27
				$argumentLink = $parseTwitterLinks['argument'];
28
			} else {
29
				$userLink = true;
30
				$argumentLink = true;
31
			}
32
			if ( is_bool($userLink) && $userLink ) {
33
				$userLink = '<a href="http://twitter.com/{user}" target="_blank">@{user}</a>';
34
			}
35
			if ( is_bool($argumentLink) && $argumentLink ) {
36
				$argumentLink = '<a href="http://twitter.com/search?q=%23{argument}" target="_blank">#{argument}</a>';
37
			}
38 View Code Duplication
			if ($userLink) {
39
				//link twitter users
40
				$text = preg_replace_callback( '/([\b ])@([a-z0-9_]*)\b/i',
41
					function ( $matches ) use ( $userLink )  {
42
						return $matches[1].str_replace( "{user}", $matches[2], $userLink );
43
					},
44
					$text
45
				);
46
			}
47 View Code Duplication
			if ($argumentLink) {
48
				//link twitter arguments
49
				$text = preg_replace_callback( '/([\b ])#([a-z0-9_]*)\b/i',
50
					function ( $matches ) use ( $argumentLink )  {
51
						return $matches[1].str_replace( "{argument}", $matches[2], $argumentLink );
52
					},
53
					$text
54
				);
55
			}
56
		}
57
58
		return trim($text);
59
	}
60
61
	public static function friendlyDate( $date, $nls = null, $now = null ) {
62
		if (!$nls) {
63
			$nls = array(
64
				'lastyear'   => 'last year',
65
				'yearsago'   => '%d years ago',
66
				'lastmonth'  => 'last month',
67
				'monthsago'  => '%d months ago',
68
				'lastweek'   => 'last week',
69
				'weeksago'   => '%d weeks ago',
70
				'yesterday'  => 'yesterday',
71
				'daysago'    => '%d days ago',
72
				'hourago'    => '1 hour ago',
73
				'hoursago'   => '%d hours ago',
74
				'minuteago'  => '1 minute ago',
75
				'minutesago' => '%d minutes ago',
76
				'justnow'    => 'just now'
77
			);
78
		}
79
80
		if ( !isset($now) ) {
81
			$now = time();
82
		}
83
		if ( is_string($date) ) {
84
			$date = strtotime($date, $now);
85
		}
86
		if ( is_string( $now ) ) {
87
			$now = strtotime( $now );
88
		}
89
		if ( is_int( $date ) && is_int( $now ) ) {
90
			$interval = getdate($now - $date);
91
92
			if ( $interval['year'] > 1971 ) {
93
				return sprintf( $nls['yearsago'], ( $interval['year'] - 1970 ) );
94
			} else if ( ($interval['year'] > 1970 ) || ( $interval['mon'] > 11 ) ) {
95
				return $nls['lastyear'];
96
			} else if ( $interval['mon'] > 2 ) {
97
				return sprintf( $nls['monthsago'], $interval['mon'] );
98
			} else if ( $interval['mon'] > 1 ) {
99
				return $nls['lastmonth'];
100
			} else if ( $interval['mday'] > 2 ) {
101
				return sprintf( $nls['daysago'], $interval['mday'] );
102
			} else if ( $interval['mday'] > 1 ) {
103
				return $nls['yesterday'];
104
			} else if ( $interval['hours'] > 2 ) {
105
				return sprintf( $nls['hoursago'], $interval['hours'] );
106
			} else if ( $interval['hours'] > 1 ) {
107
				return $nls['hourago'];
108
			} else if ( $interval['minutes'] > 1 ) {
109
				return sprintf( $nls['minutesago'], $interval['minutes'] );
110
			} else if ( $interval['minutes'] > 0 ) {
111
				return $nls['minuteago'];
112
			} else {
113
				return $nls['justnow'];
114
			}
115
		} else {
116
			return ar_error::raiseError( 'Illegal date argument', ar_exceptions::ILLEGAL_ARGUMENT );
117
		}
118
	}
119
}
120
121
class ar_connect_twitterClient extends arBase {
122
123
	private $rootURL = 'https://api.twitter.com/1.1/';
124
	private $client = null;
125
126
	public function __construct( $httpClient = null ) {
127
		if (!$httpClient) {
128
			ar::load('http');
129
			$httpClient = new ar_httpClientStream();
130
		}
131
		$this->client = $httpClient;
132
	}
133
134
	public function parse( $text, $parseTwitterLinks=true ) {
135
		return ar_connect_twitter::parse( $text, $parseTwitterLinks );
136
	}
137
138
	public function friendlyDate( $date, $nls = null, $now = null ) {
139
		return ar_connect_twitter::friendlyDate( $date, $nls, $now );
140
	}
141
142
	public function setAccessToken( $access_token, $access_token_secret, $consumerKey = null, $consumerSecret = null ) {
143
144 View Code Duplication
		if ( !$this->client instanceof ar_connect_oauthClient ) { //FIXME: a real OAuth is also ok
145
			// FIXME: what if you want a caching client?
146
			$this->client = ar_connect_oauth::client( $consumerKey, $consumerSecret );
147
			if ( ar_error::isError($this->client) ) {
148
				return $this->client;
149
			}
150
		}
151
152
		return $this->client->setToken( $access_token, $access_token_secret );
0 ignored issues
show
Documentation Bug introduced by
The method setToken does not exist on object<ar_connect_oauthClient>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
153
	}
154
155
	public function login( $consumerKey = null, $consumerSecret = null, $callback = '', $redirect = true ) {
156
		// FIXME: $redirect should probably be allowed to be an object that implements a redirect() method
157
		$session = ar_loader::session(); //FIXME: allow different session object to be passed
158
		if ( !$session->id() ) {
159
			$session->start();
160
		}
161
162
		if ( isset($callback) && substr( (string) $callback, 0, 4)!='http' && $callback!='oob' ) {
163
			$callback = ar_loader::makeURL().$callback;
164
		}
165
166 View Code Duplication
		if ( !$this->client instanceof ar_connect_oauthClient ) { ////FIXME: a real OAuth is also ok
167
			// FIXME: what if you want a caching client?
168
			$this->client = ar_connect_oauth::client( $consumerKey, $consumerSecret );
169
			if ( ar_error::isError($this->client) ) {
170
				return $this->client;
171
			}
172
		}
173
174
		$access_token        = $session->getvar('access_token');
175
		$access_token_secret = $session->getvar('access_token_secret');
176
		if ( $access_token && $access_token_secret ) {
177
			$this->client->setToken( $access_token, $access_token_secret );
0 ignored issues
show
Documentation Bug introduced by
The method setToken does not exist on object<ar_connect_oauthClient>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
178
			return true;
179
		}
180
181
		$oauth_verifier     = $session->getvar('oauth_verifier');
182
		$oauth_token        = $session->getvar('oauth_token');
183
		$oauth_token_secret = $session->getvar('oauth_token_secret');
184
		if ( !$oauth_verifier ) {
185
			$oauth_verifier  = ar::getvar('oauth_verifier');
186
			if ( $oauth_verifier ) {
187
				$session->putvar( 'oauth_verifier', $oauth_verifier );
188
			} else {
189
				if ( !$callback ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $callback of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
190
					$callback = 'oob';
191
				}
192
				$info = $this->client->getRequestToken( 'https://api.twitter.com/oauth/request_token', (string) $callback );
0 ignored issues
show
Documentation Bug introduced by
The method getRequestToken does not exist on object<ar_connect_oauthClient>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
193
				if ( ar_error::isError($info) ) {
194
					$info->debugInfo = $this->client->debugInfo;
0 ignored issues
show
Documentation introduced by
The property debugInfo does not exist on object<ar_connect_oauthClient>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
195
					return $info;
196
				}
197
				$this->client->setToken( $info['oauth_token'], $info['oauth_token_secret'] );
0 ignored issues
show
Documentation Bug introduced by
The method setToken does not exist on object<ar_connect_oauthClient>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
198
				$session->putvar( 'oauth_token', $info['oauth_token'] );
199
				$session->putvar( 'oauth_token_secret', $info['oauth_token_secret'] );
200
				if ($redirect) {
201
					ar_loader::redirect( 'https://api.twitter.com/oauth/authorize?oauth_token='.RawUrlEncode( $info['oauth_token'] ) );
202
					return false;
203
				} else {
204
					return 'https://api.twitter.com/oauth/authorize?oauth_token='.RawUrlEncode( $info['oauth_token'] );
205
				}
206
			}
207
		}
208
209
		if ( $oauth_verifier ) {
210
			$this->client->setToken( $oauth_token, $oauth_token_secret );
0 ignored issues
show
Documentation Bug introduced by
The method setToken does not exist on object<ar_connect_oauthClient>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
211
			$info = $this->client->getAccessToken( 'https://api.twitter.com/oauth/access_token', '', $oauth_verifier );
0 ignored issues
show
Documentation Bug introduced by
The method getAccessToken does not exist on object<ar_connect_oauthClient>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
212
			if ( ar_error::isError( $info ) ) {
213
				$info->debugInfo = $this->client->debugInfo;
0 ignored issues
show
Documentation introduced by
The property debugInfo does not exist on object<ar_connect_oauthClient>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
214
				return $info;
215
			}
216
			$access_token = $info['oauth_token'];
217
			$access_token_secret = $info['oauth_token_secret'];
218
			$this->client->setToken( $access_token, $access_token_secret );
0 ignored issues
show
Documentation Bug introduced by
The method setToken does not exist on object<ar_connect_oauthClient>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
219
			$session->putvar( 'access_token', $access_token );
220
			$session->putvar( 'access_token_secret', $access_token_secret );
221
			return $info;
222
		}
223
224
		return false;
225
	}
226
227
	public function tweets( $user, $options = array() ) {
228
		// http://dev.twitter.com/doc/get/statuses/user_timeline
229
		$defaults = array(
230
			'count' => 10,
231
			'page' => 1
232
		);
233
		$options += $defaults;
234
		if ( is_numeric($user) ) {
235
			$options['user_id'] = $user;
236
			unset($user);
237
		} else if ($user) {
238
			$options['screen_name'] = $user;
239
		}
240
		return $this->get( 'statuses/user_timeline', $options );
241
	}
242
243
	public function trends( $location = 'place', $options = array() ) {
244
		switch ( $location ) {
245
			case 'place':			//https://dev.twitter.com/docs/api/1.1/get/trends/place
246
				if (!$options['id']) {
247
					$options['id'] = 1; // YAHOO! Where On Earth ID, 1 = worldwide
248
				}
249
				break;
250
			case 'available':		//https://dev.twitter.com/docs/api/1.1/get/trends/available
251
			case 'closest':			//https://dev.twitter.com/docs/api/1.1/get/trends/closest
252
			break;
253
			default :
254
				$location = 'place';
255
				$options['id'] = 1;
256
			break;
257
		}
258
		return $this->get( 'trends/'.$location, $options );
259
	}
260
261
	public function search( $options ) {
262
		if ( is_string($options) ) {
263
			$options = array( 'q' => $options );
264
		}
265
		return $this->get( 'search/tweets', $options );
266
	}
267
268
	public function tweet( $status, $options = array() ) {
269
		$options['status'] = $status;
270
		return $this->post( 'statuses/update', $options );
271
	}
272
273 View Code Duplication
	public function get( $path, $options = array() ) {
274
		$url = ar::url( $this->rootURL.$path.'.json' );
275
		$url->query->import( $options );
276
277
		$json = $this->client->get( $url );
278
279
		if ($json && !ar_error::isError($json) ) {
280
			return json_decode( $json );
281
		} else {
282
			return $json;
283
		}
284
	}
285
286 View Code Duplication
	public function post( $path, $options = array() ) {
287
		$url = ar::url( $this->rootURL.$path.'.json' );
288
		$json = $this->client->post( $url, $options );
289
		if ($json && !ar_error::isError($json) ) {
290
			return json_decode( $json );
291
		} else {
292
			return $json;
293
		}
294
	}
295
296
}
297