LinkedinGroup::getStats()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 7
rs 9.4285
cc 1
eloc 4
nc 1
nop 0
1
<?php
2
3
namespace Borfast\Socializr\Connectors;
4
5
use OAuth\Common\Storage\Exception\TokenNotFoundException;
6
use Borfast\Socializr\Exceptions\AuthorizationException;
7
use Borfast\Socializr\Exceptions\LinkedinForbiddenException;
8
use Borfast\Socializr\Exceptions\LinkedinPostingException;
9
use Borfast\Socializr\Post;
10
use Borfast\Socializr\Profile;
11
use Borfast\Socializr\Response;
12
use GuzzleHttp\Client as Guzzle;
13
use GuzzleHttp\Exception\ClientException;
14
15
class LinkedinGroup extends AbstractConnector
16
{
17
    public static $provider = 'linkedin';
18
19
    /**
20
     * @param Post $post
21
     * @return Response
22
     * @throws LinkedinForbiddenException
23
     * @throws LinkedinPostingException
24
     */
25
    public function post(Post $post)
26
    {
27
        $group_id = $post->options['group_id'];
28
29
        try {
30
            $token = $this->service->getStorage()->retrieveAccessToken('Linkedin')->getAccessToken();
31
        } catch (TokenNotFoundException $e) {
32
            throw new AuthorizationException();
33
        }
34
35
        $path = '/groups/'.$group_id.'/posts?format=json&oauth2_access_token='.$token;
36
        $params = [
37
            'title' => $post->title,
38
            'summary' => '',
39
            'content' => [
40
                'title' => $post->title . ' @',
41
                'submitted-url' => $post->url,
42
                'description' => $post->body,
43
            ],
44
        ];
45
46
        // Add media files, if they were sent.
47
        if (isset($post->media) && array_key_exists(0, $post->media)) {
48
            $params['content']['submitted-image-url'] = $post->media[0];
49
        }
50
51
        $params = json_encode($params);
52
53
        $url = 'https://api.linkedin.com/v1'.$path;
54
        // Linkedin API requires the Content-Type header set to application/json
55
        $options = [
56
            'headers' => ['Content-Type' => 'application/json'],
57
            'body' => $params
58
        ];
59
60
        $client = new Guzzle();
61
        try {
62
            $result = $client->post($url, $options);
63
        } catch (ClientException $e) {
64
            if ($e->getCode() >= 400) {
65
                throw new LinkedinForbiddenException($e);
66
            } else {
67
                throw $e;
68
            }
69
        }
70
71
        if ($result->getStatusCode() > 300) {
72
            $msg = "Error posting to Linkedin group. Error code from Linkedin: %s. Error message from Linkedin: %s";
73
            $msg = sprintf($msg, $result->status_code, json_decode($result->body)->message);
0 ignored issues
show
Bug introduced by
Accessing status_code on the interface GuzzleHttp\Message\ResponseInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
Accessing body on the interface GuzzleHttp\Message\ResponseInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
74
            throw new LinkedinPostingException($msg, $result->status_code);
0 ignored issues
show
Bug introduced by
Accessing status_code on the interface GuzzleHttp\Message\ResponseInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
75
        }
76
77
        $response = new Response;
78
        $response->setRawResponse($result); // This is already JSON.
79
        $response->setProvider(static::$provider);
80
        //$response->setPostId($result->getHeader('x-li-uuid'));
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
81
82
        // As amazing as it may sound, there's a three year old bug that LinkedIn
83
        // knows of but doesn't fix, which is simply the group posts URL is not
84
        // returned when we create the post, and when the post endpoint is queried
85
        // it returns a URL containing an incorrect domain: api.linkedin.com
86
        // instead of www.linkedin.com. They acknowledge this in the "Known Issues"
87
        // section of the groups API documentation and say the workaround is simple:
88
        // just swap the domains. Well, thanks for nothing. Would it be so hard for
89
        // them to return a public URL along with the response of the creation?...
90
        // So we need to make another API call to fetch the correct URL, because
91
        // it's not even possible to generate it manually.
92
93
        // Moderated groups don't return a 'location' header, so let's skip it if that's the case.
94
        $location = $result->getHeader('Location');
95
        if (!empty($location)) {
96
            $url = $location . ':(id,site-group-post-url)?format=json&oauth2_access_token=' . $token;
97
            $result = $client->get($url);
98
            $json = $result->json();
99
100
            $post_url = str_replace('api.linkedin.com/v1', 'www.linkedin.com', $json['siteGroupPostUrl']);
101
            $response->setPostUrl($post_url);
102
        }
103
104
        return $response;
105
    }
106
107
108 View Code Duplication
    public function getProfile()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
109
    {
110
        $path = '/people/~:(id,first-name,last-name,maiden-name,public-profile-url,formatted-name,num-connections,email-address,num-recommenders)?format=json';
111
        $response = $this->service->request($path);
112
        $profile_json = json_decode($response, true);
113
114
        $mapping = [
115
            'id' => 'id',
116
            'email' => 'emailAddress',
117
            'name' => 'formattedName',
118
            'first_name' => 'firstName',
119
            'middle_name' => 'maidenName',
120
            'last_name' => 'lastName',
121
            // 'username' => 'username',
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
122
            'link' => 'publicProfileUrl'
123
        ];
124
125
        $profile = Profile::create($mapping, $profile_json);
126
        $profile->provider = static::$provider;
127
        $profile->raw_response = $response;
128
129
        return $profile;
130
    }
131
132
    public function getStats()
133
    {
134
        $path = 'groups/'.$this->id.':(id,num-members)?format=json';
135
        $response = json_decode($this->request($path));
136
137
        return $response->numMembers;
138
    }
139
}
140