1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Borfast\Socializr\Connectors; |
4
|
|
|
|
5
|
|
|
use Borfast\Socializr\Exceptions\AuthorizationException; |
6
|
|
|
use Borfast\Socializr\Exceptions\ExpiredTokenException; |
7
|
|
|
use Borfast\Socializr\Exceptions\GenericPostingException; |
8
|
|
|
use Borfast\Socializr\Group; |
9
|
|
|
use Borfast\Socializr\Page; |
10
|
|
|
use Borfast\Socializr\Post; |
11
|
|
|
use Borfast\Socializr\Profile; |
12
|
|
|
use Borfast\Socializr\Response; |
13
|
|
|
|
14
|
|
|
class Facebook extends AbstractConnector |
15
|
|
|
{ |
16
|
|
|
public static $provider = 'Facebook'; |
17
|
|
|
|
18
|
|
|
/** @var Profile */ |
19
|
|
|
protected $profile = null; |
20
|
|
|
|
21
|
|
|
public function request($path, $method = 'GET', $params = [], $headers = []) |
22
|
|
|
{ |
23
|
|
|
$result = parent::request($path, $method, $params, $headers); |
24
|
|
|
|
25
|
|
|
$json_result = json_decode($result, true); |
26
|
|
|
|
27
|
|
|
|
28
|
|
|
if (isset($json_result['error'])) { |
29
|
|
|
if (isset($json_result['error']['error_subcode'])) { |
30
|
|
|
$error_subcode = $json_result['error']['error_subcode']; |
31
|
|
|
} else { |
32
|
|
|
$error_subcode = 'n/a'; |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
$error_type = $json_result['error']['type']; |
36
|
|
|
$error_code = $json_result['error']['code']; |
37
|
|
|
$error_message = $json_result['error']['message']; |
38
|
|
|
|
39
|
|
|
$msg = 'Error type: %s. Error code: %s. Error subcode: %s. Message: %s'; |
40
|
|
|
$msg = sprintf( |
41
|
|
|
$msg, |
42
|
|
|
$error_type, |
43
|
|
|
$error_code, |
44
|
|
|
$error_subcode, |
45
|
|
|
$error_message |
46
|
|
|
); |
47
|
|
|
|
48
|
|
|
|
49
|
|
|
if ($error_type == 'OAuthException' && |
50
|
|
|
// Handling random issues by steering them towards GenericPostingException |
51
|
|
|
$error_code != 1 && |
52
|
|
|
strpos($error_message, 'Provided link was incorrect or disallowed') === false && |
53
|
|
|
strpos($error_message, 'Service temporarily unavailable') === false |
54
|
|
|
) { |
55
|
|
|
throw new ExpiredTokenException($msg); |
56
|
|
|
} else if ($error_type == 'GraphMethodException' && $error_code == '100') { |
57
|
|
|
throw new AuthorizationException(); |
58
|
|
|
} else { |
59
|
|
|
throw new GenericPostingException($msg); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
return $result; |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
|
68
|
|
|
public function post(Post $post) |
69
|
|
|
{ |
70
|
|
|
$msg = $post->title; |
71
|
|
|
$msg .= "\n\n"; |
72
|
|
|
$msg .= $post->body; |
73
|
|
|
$msg = trim($msg); |
74
|
|
|
|
75
|
|
|
if (empty($post->media)) { |
76
|
|
|
$path = '/'.$this->getProfile()->id.'/feed'; |
77
|
|
|
|
78
|
|
|
$params = [ |
79
|
|
|
// 'caption' => $post->title, |
|
|
|
|
80
|
|
|
'description' => '', |
81
|
|
|
'link' => $post->url, |
82
|
|
|
'message' => $msg |
83
|
|
|
]; |
84
|
|
|
} else { |
85
|
|
|
$path = '/'.$this->getProfile()->id.'/photos'; |
86
|
|
|
|
87
|
|
|
$msg .= "\n"; |
88
|
|
|
$msg .= $post->url; |
89
|
|
|
|
90
|
|
|
$params = [ |
91
|
|
|
'url' => $post->media[0], |
92
|
|
|
'caption' => $msg |
93
|
|
|
]; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
$method = 'POST'; |
97
|
|
|
|
98
|
|
|
$result = $this->request($path, $method, $params); |
99
|
|
|
|
100
|
|
|
$json_result = json_decode($result, true); |
101
|
|
|
|
102
|
|
|
// If there's no ID, the post didn't go through |
103
|
|
|
if (!isset($json_result['id'])) { |
104
|
|
|
$msg = "Unknown error posting to Facebook profile."; |
105
|
|
|
throw new GenericPostingException($msg, 1); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
$response = new Response; |
109
|
|
|
$response->setRawResponse($result); // This is already JSON. |
110
|
|
|
$response->setProvider('Facebook'); |
111
|
|
|
$response->setPostId($json_result['id']); |
112
|
|
|
|
113
|
|
|
return $response; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
View Code Duplication |
public function getProfile() |
|
|
|
|
117
|
|
|
{ |
118
|
|
|
if (is_null($this->profile)) { |
119
|
|
|
$path = '/me'; |
120
|
|
|
$result = $this->request($path); |
121
|
|
|
$json_result = json_decode($result, true); |
122
|
|
|
|
123
|
|
|
$mapping = [ |
124
|
|
|
'id' => 'id', |
125
|
|
|
'email' => 'email', |
126
|
|
|
'name' => 'name', |
127
|
|
|
'first_name' => 'first_name', |
128
|
|
|
'middle_name' => 'middle_name', |
129
|
|
|
'last_name' => 'last_name', |
130
|
|
|
'username' => 'username', |
131
|
|
|
// 'username' => 'email', // Facebook Graph API 2.0 doesn't have username |
|
|
|
|
132
|
|
|
'link' => 'link' |
133
|
|
|
]; |
134
|
|
|
|
135
|
|
|
$this->profile = Profile::create($mapping, $json_result); |
136
|
|
|
$this->profile->provider = static::$provider; |
137
|
|
|
$this->profile->raw_response = $result; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
return $this->profile; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
public function getPermissions() |
144
|
|
|
{ |
145
|
|
|
$profile = $this->getProfile(); |
146
|
|
|
|
147
|
|
|
$path = '/'.$profile->id.'/permissions'; |
148
|
|
|
return $this->request($path); |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
public function getStats() |
152
|
|
|
{ |
153
|
|
|
return $this->getFriendsCount(); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
public function getPages() |
157
|
|
|
{ |
158
|
|
|
$profile = $this->getProfile(); |
159
|
|
|
|
160
|
|
|
$path = '/'.$profile->id.'/accounts?fields=name,picture,access_token,id,can_post,likes,link,username'; |
161
|
|
|
$result = $this->request($path); |
162
|
|
|
$json_result = json_decode($result, true); |
163
|
|
|
|
164
|
|
|
$pages = []; |
165
|
|
|
|
166
|
|
|
$mapping = [ |
167
|
|
|
'id' => 'id', |
168
|
|
|
'name' => 'name', |
169
|
|
|
'link' => 'link', |
170
|
|
|
'can_post' => 'can_post', |
171
|
|
|
'access_token' => 'access_token' |
172
|
|
|
]; |
173
|
|
|
|
174
|
|
|
// Make the page IDs available as the array keys |
175
|
|
View Code Duplication |
if (!empty($json_result['data'])) { |
|
|
|
|
176
|
|
|
foreach ($json_result['data'] as $page) { |
177
|
|
|
$pages[$page['id']] = Page::create($mapping, $page); |
178
|
|
|
$pages[$page['id']]->picture = $page['picture']['data']['url']; |
179
|
|
|
$pages[$page['id']]->provider = static::$provider; |
180
|
|
|
$pages[$page['id']]->raw_response = $result; |
181
|
|
|
} |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
return $pages; |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
public function getGroups() |
188
|
|
|
{ |
189
|
|
|
$profile = $this->getProfile(); |
190
|
|
|
|
191
|
|
|
$path = '/'.$profile->id.'/groups?fields=id,name,icon'; |
192
|
|
|
$result = $this->request($path); |
193
|
|
|
$json_result = json_decode($result, true); |
194
|
|
|
|
195
|
|
|
$groups = []; |
196
|
|
|
|
197
|
|
|
$mapping = [ |
198
|
|
|
'id' => 'id', |
199
|
|
|
'name' => 'name', |
200
|
|
|
'picture' => 'icon' |
201
|
|
|
]; |
202
|
|
|
|
203
|
|
|
// Make the group IDs available as the array keys |
204
|
|
|
if (!empty($json_result['data'])) { |
205
|
|
|
foreach ($json_result['data'] as $group) { |
206
|
|
|
$groups[$group['id']] = Group::create($mapping, $group); |
207
|
|
|
$groups[$group['id']]->picture = $group['icon']; |
208
|
|
|
$groups[$group['id']]->link = 'https://www.facebook.com/groups/' . $group['id']; |
209
|
|
|
$groups[$group['id']]->can_post = true; |
210
|
|
|
$groups[$group['id']]->provider = static::$provider; |
211
|
|
|
$groups[$group['id']]->raw_response = $result; |
212
|
|
|
} |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
return $groups; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
/**************************************************** |
219
|
|
|
* |
220
|
|
|
* From here on these are Facebook-specific methods. |
221
|
|
|
* |
222
|
|
|
***************************************************/ |
223
|
|
|
public function getFriendsCount() |
224
|
|
|
{ |
225
|
|
|
$path = '/'.$this->getProfile()->id.'/friends'; |
226
|
|
|
$result = $this->request($path); |
227
|
|
|
|
228
|
|
|
$response = json_decode($result); |
229
|
|
|
|
230
|
|
|
if (property_exists($response, 'summary')) { |
231
|
|
|
$response = $response->summary->total_count; |
232
|
|
|
} else { |
233
|
|
|
$response = '-'; |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
return $response; |
237
|
|
|
} |
238
|
|
|
} |
239
|
|
|
|
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.