Completed
Push — master ( 25c591...f27f8c )
by Dominik
03:59
created

createUserContactFromLinkedInProfile()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 22
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 3
Bugs 1 Features 1
Metric Value
c 3
b 1
f 1
dl 0
loc 22
rs 8.9197
ccs 0
cts 20
cp 0
cc 4
eloc 18
nc 8
nop 1
crap 20
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 array of provider ids that are loaded already
32
	 */
33
	private $loadedProviders;
34
	
35
	/**
36
	 * @var ContactSorter
37
	 */
38
	private $sorter;
39
	
40
	/**
41
	 * @var ContactMerger
42
	 */
43
	private $merger;
44
45
	/**
46
	 * @var GenderGuesser
47
	 */
48
	private $genderGuesser;
49
50
	/**
51
	 * @var string
52
	 */
53
	const CONTACTS_SESSION_NAME = "hybrid_auth_contacts";
54
	const LOADED_PROVIDERS_NAME = "hybrid_auth_loaded_providers";
55
56
	/**
57
	 * Get the contacts from all configured providers
58
	 * @param AzineHybridAuth $hybridAuth
59
	 * @param Session $session
60
	 * @param array $providers
61
	 */
62 1
	public function __construct(AzineHybridAuth $hybridAuth, Session $session, ContactSorter $sorter, ContactMerger $merger, GenderGuesser $genderGuesser, ContactFilter $contactFilter, array $providers){
63 1
		$this->hybridAuth = $hybridAuth;
64 1
		$this->sorter = $sorter;
65 1
		$this->merger = $merger;
66 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...
67 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...
68 1
		$this->providers = array_keys($providers);
69 1
		$this->session = $session;
70 1
		$this->genderGuesser = $genderGuesser;
71 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...
72 1
	}
73
74
    /**
75
     * Get user-profiles from xing and linked-in
76
     * @param int $pageSize
77
     * @param int $offset
78
     * @param array $filterParams
79
     * @return array
80
     */
81 1
	public function getContactProfiles($pageSize = 50, $offset = 0, $filterParams = array()){
82
83
		// check if the contacts are loaded already
84 1
		if(sizeof($this->providers) != sizeof($this->loadedProviders)){
85
			$this->getAllContacts();
86
		}
87
88
		// filter according to the $filterParams
89 1
		$contacts = $this->contactFilter->filter($this->contacts, $filterParams);
90
91
		// return one page
92 1
		$contacts =  array_slice($contacts, $offset, $pageSize, true);
93 1
		return $contacts;
94
	}
95
96
	/**
97
	 * Fetch all contacts from the networks
98
	 */
99
	private function getAllContacts(){
100
		$newContactsCount = 0;
101
		foreach ($this->providers as $provider){
102
			$connected = $this->hybridAuth->getProvider(null, $provider, false)->isUserConnected();
103
			if($connected && (!array_key_exists($provider, $this->loadedProviders) || sizeof($this->loadedProviders[$provider]) == 0)){
104
				$newContacts = $this->getUserContactsFor($provider);
105
				$this->loadedProviders[$provider] = $newContacts;
106
				$this->session->set(self::LOADED_PROVIDERS_NAME, $this->loadedProviders);
107
				$this->session->save();
108
				$newContactsCount += sizeof($newContacts);
109
			}
110
		}
111
112
		if($newContactsCount > 0) {
113
			// merge the old and new contacts
114
			$this->contacts = $this->merger->merge($this->loadedProviders);
115
116
			// sort all contacts
117
			usort($this->contacts, array($this->sorter, 'compare'));
118
		}
119
120
		$this->session->set(self::CONTACTS_SESSION_NAME, $this->contacts);
121
		$this->session->save();
122
	}
123
124
	/**
125
	 * Get ALL xing contacts of the current user
126
	 * @param $provider
127
	 * @return array
128
	 * @throws \Exception
129
	 */
130
	public function getUserContactsFor($provider){
131
		if($provider == "Xing"){
132
			return $this->getXingContacts();
133
		} elseif ($provider == "LinkedIn"){
134
			return $this->getLinkedInContacts();
135
		}
136
137
		$userContacts = array();
138
		foreach ($this->hybridAuth->getProvider(null, $provider)->getUserContacts() as $next){
139
			$nextContact = new UserContact($provider);
140
			$nextContact->identifier	= $next->identifier;
141
			$nextContact->profileURL	= $next->profileURL;
142
			$nextContact->firstName 	= $next->firstName;
143
			$nextContact->lastName		= $next->lastName;
144
			$nextContact->displayName	= $nextContact->firstName." ".$nextContact->lastName;
145
			$nextContact->description	= $next->description;
146
			$nextContact->email			= $next->email;
147
		}
148
		return $userContacts;
149
	}
150
151
    /**
152
     * Get ALL xing contacts of the current user
153
     * @throws \Exception
154
     * @return array of UserContact
155
     */
156
	public function getXingContacts(){
157
		$api = $this->hybridAuth->getXingApi();
158
		$fetchSize = 100;
159
		$fetchOffset = 0;
160
		$fetchMore = true;
161
		$users = array();
162
		try {
163
			while ($fetchMore){
164
				$oResponse = $api->get("users/me/contacts?limit=$fetchSize&user_fields=id,display_name,permalink,web_profiles,photo_urls,first_name,last_name,interests,gender,active_email,professional_experience&offset=$fetchOffset");
165
				if(isset($oResponse->error_name)){
166
					throw new \Exception($oResponse->error_name." : ".$oResponse->message);
167
				}
168
				$users = array_merge($users, $oResponse->contacts->users);
169
				$fetchOffset = $fetchOffset + $fetchSize;
170
				$fetchMore = $fetchSize == sizeof($oResponse->contacts->users);
171
			}
172
		}
173
		catch(\Exception $e) {
174
			throw new \Exception('Could not fetch contacts. Xing returned an error.', $e->getCode(), $e);
175
		}
176
177
178
		// Create the contacts array.
179
		$xingContacts = array();
180
		foreach($users as $connection) {
181
			$xingContacts[] = $this->createUserContactFromXingProfile($connection);
182
		}
183
184
		return $xingContacts;
185
	}
186
187
    /**
188
     * Get ALL linkedin contacts of the current user
189
     * @throws \Exception
190
     * @return array of UserContact
191
     */
192
	public function getLinkedInContacts(){
193
		$api = $this->hybridAuth->getLinkedInApi();
194
		$fetchSize = 500;
195
		$fetchMore = true;
196
		$fetchOffset = 0;
197
		$users = array();
198
199
		try{
200
			while ($fetchMore){
201
				$response = $api->profile("~/connections:(id,first-name,last-name,picture-url,public-profile-url,summary,headline,specialities)?start=$fetchOffset&count=$fetchSize");
202
				$connectionsXml = new \SimpleXMLElement( $response['linkedin'] );
203
				foreach ($connectionsXml->person as $person){
204
					$users[] = $person;
205
				}
206
				$fetchMore = $fetchSize == sizeof($connectionsXml->person);
207
				$fetchOffset = $fetchOffset + $fetchSize;
208
			}
209
		}
210
		catch( \LinkedInException $e ){
211
			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...
212
		}
213
214
		$contacts = array();
215
		foreach( $users as $connection ) {
216
            $contacts[] = $this->createUserContactFromLinkedInProfile($connection);
217
		}
218
219
		return $contacts;
220
	}
221
	
222
	/**
223
	 * Get the basic profile of the current users contact with the given user id.
224
	 * @param string $provider
225
	 * @param string $contactId
226
	 * @return UserContact
227
	 */
228
	public function getUserContactBasicProfile($provider, $contactId){
229
		if(!array_key_exists($provider, $this->loadedProviders)){
230
			$this->loadedProviders[$provider] = $this->getUserContactsFor($provider);
231
			$this->session->set(self::LOADED_PROVIDERS_NAME, $this->loadedProviders);
232
			$this->session->save();
233
		}
234
		
235
		foreach ($this->loadedProviders[$provider] as $userContact){
236
			if($userContact->identifier == $contactId){
237
				return $userContact;
238
			}
239
		}
240
		return null;
241
	}
242
243
    /**
244
     * Get the basic profile of the user with the given profileUrl
245
     * @param string $profileUrl
246
     * @throws \Exception
247
     * @return UserContact
248
     */
249
    public function getUserProfileByUrl($profileUrl){
250
        $matches = array();
251
        preg_match('/https?:\/\/.{0,5}(xing|linkedin)(\.ch|\.com).*/', $profileUrl, $matches);
252
        $provider = $matches[1];
253
        if(strpos($provider, "xing") !== false ){
254
            $matches = array();
255
            preg_match('/.*\/profile\/([]a-z,A-Z,_,0-9]*).*/', $profileUrl, $matches);
256
            if(sizeof($matches) != 2){
257
                return null;
258
            }
259
            $profilePage = $matches[1];
260
            $xingProfiles = $this->hybridAuth->getXingApi()->get("users/$profilePage.json");
261
            return $this->createUserContactFromXingProfile($xingProfiles->users[0]);
262
263
        } elseif (strpos($provider, "linkedin") !== false){
264
            $profileUrl = urlencode($profileUrl);
265
            try{
266
                $response = $this->hybridAuth->getLinkedInApi()->connections("url=$profileUrl:(id,first-name,last-name,picture-url,public-profile-url,summary,headline,specialities,email-address)");
267
            } catch( \LinkedInException $e ){
268
                throw new \Exception( "User profile by url request failed! linkedin returned an error.", $e->getCode(), $e );
269
            }
270
            $connectionsXml = new \SimpleXMLElement( $response['linkedin'] );
271
            return $this->createUserContactFromLinkedInProfile($connectionsXml);
272
        }
273
    }
274
275
	/**
276
	 * @param $xingProfile
277
	 * @return UserContact
278
	 */
279
    private function createUserContactFromXingProfile($xingProfile){
280
        $newContact = new UserContact("Xing");
281
        $newContact->identifier	    = (property_exists($xingProfile, 'id'))          	? $xingProfile->id                  : '';
282
        $newContact->firstName 	    = (property_exists($xingProfile, 'first_name'))		? $xingProfile->first_name 	        : '';
283
        $newContact->lastName		= (property_exists($xingProfile, 'last_name')) 		? $xingProfile->last_name 	        : '';
284
        $newContact->displayName	= $newContact->firstName." ".$newContact->lastName;
285
        $newContact->profileURL	    = (property_exists($xingProfile, 'permalink'))   	? $xingProfile->permalink           : '';
286
        $newContact->photoURL       = (property_exists($xingProfile, 'photo_urls'))   	? $xingProfile->photo_urls->size_96x96   : '';
287
        $newContact->photoUrlBig    = (property_exists($xingProfile, 'photo_urls'))   	? $xingProfile->photo_urls->size_256x256   : '';
288
        $newContact->description	= (property_exists($xingProfile, 'interests'))   	? $xingProfile->interests           : '';
289
        $newContact->description	.= (property_exists($xingProfile, 'haves'))   	    ? "\n".$xingProfile->haves           : '';
290
        $newContact->description	.= (property_exists($xingProfile, 'wants'))   	    ? "\n".$xingProfile->wants           : '';
291
        $newContact->email			= (property_exists($xingProfile, 'active_email'))	? $xingProfile->active_email        : '';
292
        $newContact->gender		    = (property_exists($xingProfile, 'gender'))			? $xingProfile->gender              : '';
293
        $primaryCompany             = (property_exists($xingProfile, 'professional_experience') && property_exists($xingProfile->professional_experience, 'primary_company')) ? $xingProfile->professional_experience->primary_company : null;
294
        // company name and title are not always available.
295
        if($primaryCompany) {
296
            $company = (property_exists($primaryCompany, 'name'))	? $primaryCompany->name        : '';
297
            $title = (property_exists($primaryCompany, 'title'))	? $primaryCompany->title        : '';
298
            if($title && $company) {
299
                $newContact->headline = $title . " @ " . $company;
300
            } else {
301
                $newContact->headline = $title . $company;
302
            }
303
        }
304
305
        // My own priority: Homepage, blog, other, something else.
306
        if (property_exists($xingProfile, 'web_profiles')) {
307
            $newContact->webSiteURL = (property_exists($xingProfile->web_profiles, 'homepage')) ? $xingProfile->web_profiles->homepage[0] : null;
308 View Code Duplication
            if (null === $newContact->webSiteURL) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
309
                $newContact->webSiteURL = (property_exists($xingProfile->web_profiles, 'blog')) ? $xingProfile->web_profiles->blog[0] : null;
310
            }
311 View Code Duplication
            if (null === $newContact->webSiteURL) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
312
                $newContact->webSiteURL = (property_exists($xingProfile->web_profiles, 'other')) ? $xingProfile->web_profiles->other[0] : null;
313
            }
314
            // Just use *anything*!
315
            if (null === $newContact->webSiteURL) {
316
                foreach ($xingProfile->web_profiles as $aUrl) {
317
                    $newContact->webSiteURL = $aUrl[0];
318
                    break;
319
                }
320
            }
321
        }
322
323
        return $newContact;
324
    }
325
326
	/**
327
	 * @param $linkedinProfile
328
	 * @return UserContact
329
	 */
330
    private function createUserContactFromLinkedInProfile($linkedinProfile){
331
        $newContact = new UserContact("LinkedIn");
332
        $newContact->identifier  = (string) $linkedinProfile->id;
333
        $newContact->firstName   = (string) $linkedinProfile->{'first-name'};
334
        $newContact->lastName    = (string) $linkedinProfile->{'last-name'};
335
        $newContact->displayName = (string) $linkedinProfile->{'first-name'} . " " . $linkedinProfile->{'last-name'};
336
        $newContact->profileURL  = (string) $linkedinProfile->{'public-profile-url'};
337
        if($newContact->profileURL == null) {
338
            $newContact->profileURL = (string)$linkedinProfile->{'site-standard-profile-request'};
339
        }
340
        $newContact->photoURL    = (string) $linkedinProfile->{'picture-url'};
341
        $newContact->description = (string) $linkedinProfile->{'summary'};
342
        $newContact->description .= $newContact->description == "" ? (string) $linkedinProfile->{'specialities'} : "\n". (string) $linkedinProfile->{'specialities'};;
343
		if($linkedinProfile->{'email-address'}) {
344
			$newContact->email = (string)$linkedinProfile->{'email-address'};
345
		}
346
        $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...
347
        $headline	             = (string) $linkedinProfile->{'headline'};
348
        $newContact->headline = str_replace(" at ", " @ ", $headline);
349
350
        return $newContact;
351
    }
352
}