Completed
Pull Request — master (#2)
by
unknown
03:16
created

getAllContacts()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 7
Bugs 1 Features 0
Metric Value
c 7
b 1
f 0
dl 0
loc 24
ccs 0
cts 19
cp 0
rs 8.5125
cc 6
eloc 15
nc 6
nop 0
crap 42
1
<?php
2
namespace Azine\HybridAuthBundle\Services;
3
4
use Azine\HybridAuthBundle\Entity\UserContact;
5
6
use Symfony\Component\HttpFoundation\Session\Session;
7
8
class AzineMergedBusinessNetworksProvider {
9
10
	/**
11
	 * @var AzineHybridAuth
12
	 */
13
	private $hybridAuth;
14
15
	/**
16
	 * @var array
17
	 */
18
	private $contacts;
19
20
	/**
21
	 * @var Session
22
	 */
23
	private $session;
24
25
	/**
26
	 * @var array of provider ids
27
	 */
28
	private $providers;
29
30
	/**
31
	 * @var config of the providers
32
	 */
33
	private $providersConfig;
34
35
	/**
36
	 * @var array of provider ids that are loaded already
37
	 */
38
	private $loadedProviders;
39
	
40
	/**
41
	 * @var ContactSorter
42
	 */
43
	private $sorter;
44
	
45
	/**
46
	 * @var ContactMerger
47
	 */
48
	private $merger;
49
50
	/**
51
	 * @var GenderGuesser
52
	 */
53
	private $genderGuesser;
54
55
	/**
56
	 * @var string
57
	 */
58
	const CONTACTS_SESSION_NAME = "hybrid_auth_contacts";
59
	const LOADED_PROVIDERS_NAME = "hybrid_auth_loaded_providers";
60
61
	/**
62
	 * Get the contacts from all configured providers
63
	 * @param AzineHybridAuth $hybridAuth
64
	 * @param Session $session
65
	 * @param array $providers
66
	 */
67 1
	public function __construct(AzineHybridAuth $hybridAuth, Session $session, ContactSorter $sorter, ContactMerger $merger, GenderGuesser $genderGuesser, ContactFilter $contactFilter, array $providers){
68 1
		$this->hybridAuth = $hybridAuth;
69 1
		$this->sorter = $sorter;
70 1
		$this->merger = $merger;
71 1
		$this->contacts = $session->get(self::CONTACTS_SESSION_NAME, array());
0 ignored issues
show
Documentation Bug introduced by
It seems like $session->get(self::CONT..._SESSION_NAME, array()) of type * is incompatible with the declared type array of property $contacts.

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...
72 1
		$this->loadedProviders = $session->get(self::LOADED_PROVIDERS_NAME, array());
0 ignored issues
show
Documentation Bug introduced by
It seems like $session->get(self::LOAD...ROVIDERS_NAME, array()) of type * is incompatible with the declared type array of property $loadedProviders.

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...
73 1
		$this->providers = array_keys($providers);
74 1
		$this->providersConfig = $providers;
0 ignored issues
show
Documentation Bug introduced by
It seems like $providers of type array is incompatible with the declared type object<Azine\HybridAuthBundle\Services\config> of property $providersConfig.

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...
75 1
		$this->session = $session;
76 1
		$this->genderGuesser = $genderGuesser;
77 1
		$this->contactFilter = $contactFilter;
0 ignored issues
show
Bug introduced by
The property contactFilter 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...
78 1
	}
79
80
    /**
81
     * Get user-profiles from xing and linked-in
82
     * @param int $pageSize
83
     * @param int $offset
84
     * @param array $filterParams
85
     * @return array
86
     */
87 1
	public function getContactProfiles($pageSize = 50, $offset = 0, $filterParams = array()){
88
89
		// check if the contacts are loaded already
90 1
		if(sizeof($this->providers) != sizeof($this->loadedProviders)){
91
			$this->getAllContacts();
92
		}
93
94
		// filter according to the $filterParams
95 1
		$contacts = $this->contactFilter->filter($this->contacts, $filterParams);
96
97
		// return one page
98 1
		$contacts =  array_slice($contacts, $offset, $pageSize, true);
99 1
		return $contacts;
100
	}
101
102
	/**
103
	 * Fetch all contacts from the networks
104
	 */
105
	private function getAllContacts(){
106
		$newContactsCount = 0;
107
		foreach ($this->providers as $provider){
108
			$connected = $this->hybridAuth->getProvider(null, $provider, false)->isUserConnected();
109
			if($connected && (!array_key_exists($provider, $this->loadedProviders) || sizeof($this->loadedProviders[$provider]) == 0)){
110
				$newContacts = $this->getUserContactsFor($provider);
111
				$this->loadedProviders[$provider] = $newContacts;
112
				$this->session->set(self::LOADED_PROVIDERS_NAME, $this->loadedProviders);
113
				$this->session->save();
114
				$newContactsCount += sizeof($newContacts);
115
			}
116
		}
117
118
		if($newContactsCount > 0) {
119
			// merge the old and new contacts
120
			$this->contacts = $this->merger->merge($this->loadedProviders);
121
122
			// sort all contacts
123
			usort($this->contacts, array($this->sorter, 'compare'));
124
125
			$this->session->set(self::CONTACTS_SESSION_NAME, $this->contacts);
126
			$this->session->save();
127
		}
128
	}
129
130
	/**
131
	 * Get ALL xing contacts of the current user
132
	 * @param $provider
133
	 * @return array
134
	 * @throws \Exception
135
	 */
136
	public function getUserContactsFor($provider){
137
		if($provider == "Xing"){
138
			return $this->getXingContacts();
139
		} elseif ($provider == "LinkedIn"){
140
			return $this->getLinkedInContacts();
141
		}
142
143
		$userContacts = array();
144
		foreach ($this->hybridAuth->getProvider(null, $provider)->getUserContacts() as $next){
145
			$nextContact = new UserContact($provider);
146
			$nextContact->identifier	= $next->identifier;
0 ignored issues
show
Bug introduced by
The property identifier does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
147
			$nextContact->profileURL	= $next->profileURL;
0 ignored issues
show
Bug introduced by
The property profileURL does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
148
			$nextContact->firstName 	= $next->firstName;
0 ignored issues
show
Bug introduced by
The property firstName does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
149
			$nextContact->lastName		= $next->lastName;
0 ignored issues
show
Bug introduced by
The property lastName does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
150
			$nextContact->displayName	= $nextContact->firstName." ".$nextContact->lastName;
0 ignored issues
show
Bug introduced by
The property displayName does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
151
			$nextContact->description	= $next->description;
0 ignored issues
show
Bug introduced by
The property description does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
152
			$nextContact->email			= $next->email;
0 ignored issues
show
Bug introduced by
The property email does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
153
		}
154
		return $userContacts;
155
	}
156
157
    /**
158
     * Get ALL xing contacts of the current user
159
     * @throws \Exception
160
     * @return array of UserContact
161
     */
162
	public function getXingContacts(){
163
		$api = $this->hybridAuth->getXingApi();
164
		$userFields = implode(',', $this->providersConfig['xing']['fields']);
165
		$fetchSize = 100;
166
		$fetchOffset = 0;
167
		$fetchMore = true;
168
		$users = array();
169
		try {
170
			while ($fetchMore){
171
				$uri = sprintf('users/me/contacts?limit=%1$s&user_fields=%2$s&offset=%3$s', $fetchSize, $userFields, $fetchOffset);
172
				$oResponse = $api->get($uri);
173
				if(isset($oResponse->error_name)){
174
					throw new \Exception($oResponse->error_name." : ".$oResponse->message);
175
				}
176
				$users = array_merge($users, $oResponse->contacts->users);
177
				$fetchOffset = $fetchOffset + $fetchSize;
178
				$fetchMore = $fetchSize == sizeof($oResponse->contacts->users);
179
			}
180
		}
181
		catch(\Exception $e) {
182
			throw new \Exception('Could not fetch contacts. Xing returned an error.', $e->getCode(), $e);
183
		}
184
185
186
		// Create the contacts array.
187
		$xingContacts = array();
188
		foreach($users as $connection) {
189
			$xingContacts[] = $this->createUserContactFromXingProfile($connection);
190
		}
191
192
		return $xingContacts;
193
	}
194
195
    /**
196
     * Get ALL linkedin contacts of the current user
197
     * @throws \Exception
198
     * @return array of UserContact
199
     */
200
	public function getLinkedInContacts(){
201
		$api = $this->hybridAuth->getLinkedInApi();
202
		$userFields = implode(',', $this->providersConfig['linkedin']['fields']);
203
		$fetchSize = 500;
204
		$fetchMore = true;
205
		$fetchOffset = 0;
206
		$users = array();
207
208
		try{
209
			while ($fetchMore){
210
				$uri = sprintf('~/connections:(%1$s)?start=%2$s&count=%3$s', $userFields, $fetchOffset, $fetchSize);
211
				$response = $api->profile($uri);
212
				$connectionsXml = new \SimpleXMLElement( $response['linkedin'] );
213
				foreach ($connectionsXml->person as $person){
214
					$users[] = $person;
215
				}
216
				$fetchMore = $fetchSize == sizeof($connectionsXml->person);
217
				$fetchOffset = $fetchOffset + $fetchSize;
218
			}
219
		}
220
		catch( \LinkedInException $e ){
221
			throw new \Exception( "User contacts request failed! {$this->providerId} returned an error.", $e->getCode(), $e );
0 ignored issues
show
Bug introduced by
The property providerId 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...
222
		}
223
224
		$contacts = array();
225
		foreach( $users as $connection ) {
226
            $contacts[] = $this->createUserContactFromLinkedInProfile($connection);
227
		}
228
229
		return $contacts;
230
	}
231
	
232
	/**
233
	 * Get the basic profile of the current users contact with the given user id.
234
	 * @param string $provider
235
	 * @param string $contactId
236
	 * @return UserContact
237
	 */
238
	public function getUserContactBasicProfile($provider, $contactId){
239
		if(!array_key_exists($provider, $this->loadedProviders)){
240
			$this->loadedProviders[$provider] = $this->getUserContactsFor($provider);
241
			$this->session->set(self::LOADED_PROVIDERS_NAME, $this->loadedProviders);
242
			$this->session->save();
243
		}
244
		
245
		foreach ($this->loadedProviders[$provider] as $userContact){
246
			if($userContact->identifier == $contactId){
247
				return $userContact;
248
			}
249
		}
250
		return null;
251
	}
252
253
    /**
254
     * Get the basic profile of the user with the given profileUrl
255
     * @param string $profileUrl
256
     * @throws \Exception
257
     * @return UserContact
258
     */
259
    public function getUserProfileByUrl($profileUrl){
260
        $matches = array();
261
        preg_match('/https?:\/\/.{0,5}(xing|linkedin)(\.ch|\.com).*/', $profileUrl, $matches);
262
        $provider = $matches[1];
263
        if(strpos($provider, "xing") !== false ){
264
            $matches = array();
265
            preg_match('/.*\/profile\/([]a-z,A-Z,_,0-9]*).*/', $profileUrl, $matches);
266
            if(sizeof($matches) != 2){
267
                return null;
268
            }
269
            $profilePage = $matches[1];
270
            $xingProfiles = $this->hybridAuth->getXingApi()->get("users/$profilePage.json");
271
            return $this->createUserContactFromXingProfile($xingProfiles->users[0]);
272
273
        } elseif (strpos($provider, "linkedin") !== false){
274
            $profileUrl = urlencode($profileUrl);
275
            try{
276
                $response = $this->hybridAuth->getLinkedInApi()->connections("url=$profileUrl:(id,first-name,last-name,picture-url,public-profile-url,summary,headline,specialities,email-address)");
277
            } catch( \LinkedInException $e ){
278
                throw new \Exception( "User profile by url request failed! linkedin returned an error.", $e->getCode(), $e );
279
            }
280
            $connectionsXml = new \SimpleXMLElement( $response['linkedin'] );
281
            return $this->createUserContactFromLinkedInProfile($connectionsXml);
282
        }
283
    }
284
285
	/**
286
	 * @param $xingProfile
287
	 * @return UserContact
288
	 */
289
    private function createUserContactFromXingProfile($xingProfile){
290
				$newContact = new UserContact("Xing");
291
292
				foreach ($xingProfile as $key => $value)  {
293
						$newContact->setField($key, $value);
294
				}
295
296
        return $newContact;
297
    }
298
299
	/**
300
	 * @param $linkedinProfile
301
	 * @return UserContact
302
	 */
303
    private function createUserContactFromLinkedInProfile($linkedinProfile){
304
        $newContact = new UserContact("LinkedIn");
305
        $newContact->identifier  = (string) $linkedinProfile->id;
0 ignored issues
show
Bug introduced by
The property identifier does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
306
        $newContact->firstName   = (string) $linkedinProfile->{'first-name'};
0 ignored issues
show
Bug introduced by
The property firstName does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
307
        $newContact->lastName    = (string) $linkedinProfile->{'last-name'};
0 ignored issues
show
Bug introduced by
The property lastName does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
308
        $newContact->displayName = (string) $linkedinProfile->{'first-name'} . " " . $linkedinProfile->{'last-name'};
0 ignored issues
show
Bug introduced by
The property displayName does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
309
        $newContact->profileURL  = (string) $linkedinProfile->{'public-profile-url'};
0 ignored issues
show
Bug introduced by
The property profileURL does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
310
        if($newContact->profileURL == null) {
311
            $newContact->profileURL = (string)$linkedinProfile->{'site-standard-profile-request'};
312
        }
313
        $newContact->photoURL    = (string) $linkedinProfile->{'picture-url'};
0 ignored issues
show
Bug introduced by
The property photoURL does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
314
        $newContact->description = (string) $linkedinProfile->{'summary'};
0 ignored issues
show
Bug introduced by
The property description does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
315
        $newContact->description .= $newContact->description == "" ? (string) $linkedinProfile->{'specialities'} : "\n". (string) $linkedinProfile->{'specialities'};;
316
		if($linkedinProfile->{'email-address'}) {
317
			$newContact->email = (string)$linkedinProfile->{'email-address'};
0 ignored issues
show
Bug introduced by
The property email does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
318
		}
319
        $newContact->gender 	 = $this->genderGuesser->gender($newContact->firstName, 5);
0 ignored issues
show
Documentation introduced by
$newContact->firstName is of type string, but the function expects a object<string>.

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...
Bug introduced by
The property gender does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
320
        $headline	             = (string) $linkedinProfile->{'headline'};
321
        $newContact->headline = str_replace(" at ", " @ ", $headline);
0 ignored issues
show
Bug introduced by
The property headline does not seem to exist in Azine\HybridAuthBundle\Entity\UserContact.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
322
323
        return $newContact;
324
    }
325
}
326