1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace SocialLinks; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* @method html() |
7
|
|
|
* @method openGraph() |
8
|
|
|
* @method schema() |
9
|
|
|
* @method twitterCard() |
10
|
|
|
*/ |
11
|
|
|
class Page |
12
|
|
|
{ |
13
|
|
|
protected $config = array(); |
14
|
|
|
protected $providers = array(); |
15
|
|
|
protected $metas = array(); |
16
|
|
|
protected $info = array( |
17
|
|
|
'url' => null, |
18
|
|
|
'title' => null, |
19
|
|
|
'text' => null, |
20
|
|
|
'image' => null, |
21
|
|
|
'twitterUser' => null, |
22
|
|
|
); |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* Constructor. |
26
|
|
|
* |
27
|
|
|
* @param array $info The page info. Only url, title, text, image and twitterUser fields are available |
28
|
|
|
* @param array $config Configuration options |
29
|
|
|
*/ |
30
|
|
|
public function __construct(array $info, array $config = array()) |
31
|
|
|
{ |
32
|
|
|
if (array_diff_key($info, $this->info)) { |
33
|
|
|
throw new \Exception('Only the following fields are available:'.implode(',', array_keys($this->info))); |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
$this->info = array_map('static::normalize', $info + $this->info); |
37
|
|
|
$this->config = $config; |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Normalize value before save it: |
42
|
|
|
* - remove html tags |
43
|
|
|
* - remove line-ending and multiple spaces |
44
|
|
|
* - remove spaces around |
45
|
|
|
* - decode escaped html entities. |
46
|
|
|
* |
47
|
|
|
* @param string |
48
|
|
|
* |
49
|
|
|
* @return string |
50
|
|
|
*/ |
51
|
|
|
protected static function normalize($value) |
52
|
|
|
{ |
53
|
|
|
return trim(strip_tags(htmlspecialchars_decode(preg_replace('/\s+/', ' ', $value)))); |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* Magic method to check if a provider exists. |
58
|
|
|
* |
59
|
|
|
* @param string $key |
60
|
|
|
* |
61
|
|
|
* @return bool |
62
|
|
|
*/ |
63
|
|
|
public function __isset($key) |
64
|
|
|
{ |
65
|
|
|
$key = strtolower($key); |
66
|
|
|
|
67
|
|
|
if (isset($this->providers[$key])) { |
68
|
|
|
return true; |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
$class = 'SocialLinks\\Providers\\'.ucfirst($key); |
72
|
|
|
|
73
|
|
|
return class_exists($class); |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Magic method to instantiate and return providers in lazy mode. |
78
|
|
|
* |
79
|
|
|
* @param string $key The provider name |
80
|
|
|
* |
81
|
|
|
* @throws \Exception if the provider does not exists |
82
|
|
|
* |
83
|
|
|
* @return Providers\ProviderInterface |
84
|
|
|
*/ |
85
|
|
View Code Duplication |
public function __get($key) |
|
|
|
|
86
|
|
|
{ |
87
|
|
|
$key = strtolower($key); |
88
|
|
|
|
89
|
|
|
if (isset($this->providers[$key])) { |
90
|
|
|
return $this->providers[$key]; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
$class = 'SocialLinks\\Providers\\'.ucfirst($key); |
94
|
|
|
|
95
|
|
|
if (class_exists($class)) { |
96
|
|
|
return $this->providers[$key] = new $class($this); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
throw new \Exception("The provider $key does not exists"); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* Magic method to instantiate and return metas in lazy mode. |
104
|
|
|
* |
105
|
|
|
* @param string $key The meta collection name |
106
|
|
|
* @param array $arguments The arguments passed to the method |
107
|
|
|
* |
108
|
|
|
* @throws \Exception if the meta does not exists |
109
|
|
|
* |
110
|
|
|
* @return Metas\MetaInterface |
111
|
|
|
*/ |
112
|
|
View Code Duplication |
public function __call($key, $arguments) |
|
|
|
|
113
|
|
|
{ |
114
|
|
|
$key = strtolower($key); |
115
|
|
|
|
116
|
|
|
if (isset($this->metas[$key])) { |
117
|
|
|
return $this->metas[$key]; |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
$class = 'SocialLinks\\Metas\\'.ucfirst($key); |
121
|
|
|
|
122
|
|
|
if (class_exists($class)) { |
123
|
|
|
return $this->metas[$key] = new $class($this); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
throw new \Exception("The meta $key does not exists"); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* Preload the counter. |
131
|
|
|
* |
132
|
|
|
* @param array $providers |
133
|
|
|
*/ |
134
|
|
|
public function shareCount(array $providers) |
135
|
|
|
{ |
136
|
|
|
if (count($providers) < 2) { |
137
|
|
|
return; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
$connections = array(); |
141
|
|
|
$curl = curl_multi_init(); |
142
|
|
|
|
143
|
|
|
foreach ($providers as $provider) { |
144
|
|
|
$request = $this->$provider->shareCountRequest(); |
145
|
|
|
|
146
|
|
|
if ($request !== null) { |
147
|
|
|
$connections[$provider] = $request; |
148
|
|
|
curl_multi_add_handle($curl, $request); |
149
|
|
|
} else { |
150
|
|
|
$this->$provider->shareCount = null; |
151
|
|
|
} |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
do { |
155
|
|
|
$return = curl_multi_exec($curl, $active); |
156
|
|
|
} while ($return === CURLM_CALL_MULTI_PERFORM); |
157
|
|
|
|
158
|
|
|
while ($active && $return === CURLM_OK) { |
159
|
|
|
if (curl_multi_select($curl) === -1) { |
160
|
|
|
usleep(100); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
do { |
164
|
|
|
$return = curl_multi_exec($curl, $active); |
165
|
|
|
} while ($return === CURLM_CALL_MULTI_PERFORM); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
foreach ($connections as $provider => $request) { |
169
|
|
|
$this->$provider->shareCount = $this->$provider->shareCount(curl_multi_getcontent($request)); |
170
|
|
|
|
171
|
|
|
curl_multi_remove_handle($curl, $request); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
curl_multi_close($curl); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* Gets the page url. |
179
|
|
|
* |
180
|
|
|
* @return string|null |
181
|
|
|
*/ |
182
|
|
|
public function getUrl() |
183
|
|
|
{ |
184
|
|
|
return $this->info['url']; |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* Gets the page title. |
189
|
|
|
* |
190
|
|
|
* @return string|null |
191
|
|
|
*/ |
192
|
|
|
public function getTitle() |
193
|
|
|
{ |
194
|
|
|
return $this->info['title']; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* Gets the page text description. |
199
|
|
|
* |
200
|
|
|
* @return string|null |
201
|
|
|
*/ |
202
|
|
|
public function getText() |
203
|
|
|
{ |
204
|
|
|
return $this->info['text']; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* Gets the page image. |
209
|
|
|
* |
210
|
|
|
* @return string|null |
211
|
|
|
*/ |
212
|
|
|
public function getImage() |
213
|
|
|
{ |
214
|
|
|
return $this->info['image']; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* Gets the page twitterUser. |
219
|
|
|
* |
220
|
|
|
* @return string|null |
221
|
|
|
*/ |
222
|
|
|
public function getTwitterUser() |
223
|
|
|
{ |
224
|
|
|
return $this->info['twitterUser']; |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
/** |
228
|
|
|
* Gets some page info. |
229
|
|
|
* |
230
|
|
|
* @param array|null Array with the page fields to return as $name => $rename. Set null to return all info |
231
|
|
|
* |
232
|
|
|
* @return array |
233
|
|
|
*/ |
234
|
|
|
public function get(array $info = null) |
235
|
|
|
{ |
236
|
|
|
if ($info === null) { |
237
|
|
|
return $this->info; |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
$data = array(); |
241
|
|
|
|
242
|
|
|
foreach ($info as $name => $rename) { |
243
|
|
|
if (is_int($name)) { |
244
|
|
|
$name = $rename; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
if (!isset($this->info[$name])) { |
248
|
|
|
continue; |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
$data[$rename] = $this->info[$name]; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
return $data; |
255
|
|
|
} |
256
|
|
|
|
257
|
|
|
/** |
258
|
|
|
* Gets one or all configuration option. |
259
|
|
|
* |
260
|
|
|
* @param string|null $name |
261
|
|
|
* |
262
|
|
|
* @return string|array|null |
263
|
|
|
*/ |
264
|
|
|
public function getConfig($name = null) |
265
|
|
|
{ |
266
|
|
|
if ($name === null) { |
267
|
|
|
return $this->config; |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
return isset($this->config[$name]) ? $this->config[$name] : null; |
271
|
|
|
} |
272
|
|
|
} |
273
|
|
|
|
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.