Completed
Push — master ( a5ba68...917ab9 )
by Dominik
20:27 queued 18:43
created

getUserProfileByUrl()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.7
c 0
b 0
f 0
ccs 0
cts 8
cp 0
cc 3
nc 3
nop 1
crap 12
1
<?php
2
3
namespace Azine\HybridAuthBundle\Services;
4
5
use Azine\HybridAuthBundle\Entity\UserContact;
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
     *
59
     * @param AzineHybridAuth $hybridAuth
60
     * @param Session         $session
61
     * @param array           $providers
62 1
     */
63 1
    public function __construct(AzineHybridAuth $hybridAuth, Session $session, ContactSorter $sorter, ContactMerger $merger, GenderGuesser $genderGuesser, ContactFilter $contactFilter, array $providers)
64 1
    {
65 1
        $this->hybridAuth = $hybridAuth;
66 1
        $this->sorter = $sorter;
67 1
        $this->merger = $merger;
68 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...
69 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...
70 1
        $this->providers = array_keys($providers);
71 1
        $this->session = $session;
72 1
        $this->genderGuesser = $genderGuesser;
73
        $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...
74
    }
75
76
    /**
77
     * Get user-profiles from linked-in.
78
     *
79
     * @param int   $pageSize
80
     * @param int   $offset
81 1
     * @param array $filterParams
82
     *
83
     * @return array
84 1
     */
85
    public function getContactProfiles($pageSize = 50, $offset = 0, $filterParams = array())
86
    {
87
        // check if the contacts are loaded already
88
        if (sizeof($this->providers) != sizeof($this->loadedProviders)) {
89 1
            $this->getAllContacts();
90
        }
91
92 1
        // filter according to the $filterParams
93 1
        $contacts = $this->contactFilter->filter($this->contacts, $filterParams);
94
95
        // return one page
96
        $contacts = array_slice($contacts, $offset, $pageSize, true);
97
98
        return $contacts;
99
    }
100
101
    /**
102
     * Fetch all contacts from the networks.
103
     */
104
    private function getAllContacts()
105
    {
106
        $newContactsCount = 0;
107
        foreach ($this->providers as $provider) {
108
            $connected = $this->hybridAuth->getProvider(null, $provider, false)->isConnected();
109
            if ($connected && (!array_key_exists($provider, $this->loadedProviders) || 0 == sizeof($this->loadedProviders[$provider]))) {
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 contacts of the current user.
132
     *
133
     * @param $provider
134
     *
135
     * @return array
136
     *
137
     * @throws \Exception
138
     */
139
    public function getUserContactsFor($provider)
140
    {
141
        if ('LinkedIn' == $provider) {
142
            return $this->getLinkedInContacts();
143
        }
144
145
        $userContacts = array();
146
        foreach ($this->hybridAuth->getProvider(null, $provider)->getUserContacts() as $next) {
147
            $nextContact = new UserContact($provider);
148
            $nextContact->identifier = $next->identifier;
149
            $nextContact->profileURL = $next->profileURL;
150
            $nextContact->firstName = $next->firstName;
151
            $nextContact->lastName = $next->lastName;
152
            $nextContact->displayName = $nextContact->firstName.' '.$nextContact->lastName;
153
            $nextContact->description = $next->description;
154
            $nextContact->email = $next->email;
155
        }
156
157
        return $userContacts;
158
    }
159
160
    /**
161
     * Get ALL linkedin contacts of the current user.
162
     *
163
     * @throws \Exception
164
     *
165
     * @return array of UserContact
166
     */
167
    public function getLinkedInContacts()
168
    {
169
        $api = $this->hybridAuth->getLinkedInApi();
170
        $fetchSize = 500;
171
        $fetchMore = true;
172
        $fetchOffset = 0;
173
        $users = array();
174
175
        try {
176
            while ($fetchMore) {
177
                $response = $api->profile("~/connections:(id,first-name,last-name,picture-url,public-profile-url,summary,headline,specialities)?start=$fetchOffset&count=$fetchSize");
178
                $connectionsXml = new \SimpleXMLElement($response['linkedin']);
179
                foreach ($connectionsXml->person as $person) {
180
                    $users[] = $person;
181
                }
182
                $fetchMore = $fetchSize == sizeof($connectionsXml->person);
183
                $fetchOffset = $fetchOffset + $fetchSize;
184
            }
185
        } catch (\LinkedInException $e) {
0 ignored issues
show
Bug introduced by
The class LinkedInException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
186
            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...
187
        }
188
189
        $contacts = array();
190
        foreach ($users as $connection) {
191
            $contacts[] = $this->createUserContactFromLinkedInProfile($connection);
192
        }
193
194
        return $contacts;
195
    }
196
197
    /**
198
     * Get the basic profile of the current users contact with the given user id.
199
     *
200
     * @param string $provider
201
     * @param string $contactId
202
     *
203
     * @return UserContact
204
     */
205
    public function getUserContactBasicProfile($provider, $contactId)
206
    {
207
        if (!array_key_exists($provider, $this->loadedProviders)) {
208
            $this->loadedProviders[$provider] = $this->getUserContactsFor($provider);
209
            $this->session->set(self::LOADED_PROVIDERS_NAME, $this->loadedProviders);
210
            $this->session->save();
211
        }
212
213
        foreach ($this->loadedProviders[$provider] as $userContact) {
214
            if ($userContact->identifier == $contactId) {
215
                return $userContact;
216
            }
217
        }
218
219
        return null;
220
    }
221
222
    /**
223
     * Get the basic profile of the user with the given profileUrl.
224
     *
225
     * @param string $profileUrl
226
     *
227
     * @throws \Exception
228
     *
229
     * @return UserContact
230
     */
231
    public function getUserProfileByUrl($profileUrl)
232
    {
233
        $matches = array();
234
        preg_match('/https?:\/\/.{0,5}(linkedin)(\.ch|\.com).*/', $profileUrl, $matches);
235
        $provider = $matches[1];
236
        if (false !== strpos($provider, 'linkedin')) {
237
            $profileUrl = urlencode($profileUrl);
238
            try {
239
                $response = $this->hybridAuth->getLinkedInApi()->connections("url=$profileUrl:(id,first-name,last-name,picture-url,public-profile-url,summary,headline,specialities,email-address)");
240
            } catch (\LinkedInException $e) {
0 ignored issues
show
Bug introduced by
The class LinkedInException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
241
                throw new \Exception('User profile by url request failed! linkedin returned an error.', $e->getCode(), $e);
242
            }
243
            $connectionsXml = new \SimpleXMLElement($response['linkedin']);
244
245
            return $this->createUserContactFromLinkedInProfile($connectionsXml);
246
        }
247
    }
248
249
    /**
250
     * @param $linkedinProfile
251
     *
252
     * @return UserContact
253
     */
254
    private function createUserContactFromLinkedInProfile($linkedinProfile)
255
    {
256
        $newContact = new UserContact('LinkedIn');
257
        $newContact->identifier = (string) $linkedinProfile->id;
258
        $newContact->firstName = (string) $linkedinProfile->{'first-name'};
259
        $newContact->lastName = (string) $linkedinProfile->{'last-name'};
260
        $newContact->displayName = (string) $linkedinProfile->{'first-name'}.' '.$linkedinProfile->{'last-name'};
261
        $newContact->profileURL = (string) $linkedinProfile->{'public-profile-url'};
262
        if (null == $newContact->profileURL) {
263
            $newContact->profileURL = (string) $linkedinProfile->{'site-standard-profile-request'};
264
        }
265
        $newContact->photoURL = (string) $linkedinProfile->{'picture-url'};
266
        $newContact->description = (string) $linkedinProfile->{'summary'};
267
        $newContact->description .= '' == $newContact->description ? (string) $linkedinProfile->{'specialities'} : "\n".(string) $linkedinProfile->{'specialities'};
268
        if ($linkedinProfile->{'email-address'}) {
269
            $newContact->email = (string) $linkedinProfile->{'email-address'};
270
        }
271
        $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...
272
        $headline = (string) $linkedinProfile->{'headline'};
273
        $newContact->headline = str_replace(' at ', ' @ ', $headline);
274
275
        return $newContact;
276
    }
277
}
278