diff options
author | ArthurHoaro <arthur@hoa.ro> | 2018-05-19 15:04:04 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2018-06-04 18:51:22 +0200 |
commit | d3f42ca487287447efb81061609644108044a038 (patch) | |
tree | 6e9d5a33290f857c8f7a04dbdf8cf0ca749db149 /tests/api/controllers/links/GetLinksTest.php | |
parent | 17e45b2e9c33c736751e059276fadb480f98e621 (diff) | |
download | Shaarli-d3f42ca487287447efb81061609644108044a038.tar.gz Shaarli-d3f42ca487287447efb81061609644108044a038.tar.zst Shaarli-d3f42ca487287447efb81061609644108044a038.zip |
Implements Tags endpoints for Shaarli's REST API
Endpoints:
* List All Tags [GET]
* Get a tag [GET]
* Update a tag [PUT]
* Delete a tag [DELETE]
Fixes #904
References shaarli/api-documentation#34
Diffstat (limited to 'tests/api/controllers/links/GetLinksTest.php')
-rw-r--r-- | tests/api/controllers/links/GetLinksTest.php | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/tests/api/controllers/links/GetLinksTest.php b/tests/api/controllers/links/GetLinksTest.php new file mode 100644 index 00000000..d22ed3bf --- /dev/null +++ b/tests/api/controllers/links/GetLinksTest.php | |||
@@ -0,0 +1,472 @@ | |||
1 | <?php | ||
2 | namespace Shaarli\Api\Controllers; | ||
3 | |||
4 | use Shaarli\Config\ConfigManager; | ||
5 | |||
6 | use Slim\Container; | ||
7 | use Slim\Http\Environment; | ||
8 | use Slim\Http\Request; | ||
9 | use Slim\Http\Response; | ||
10 | |||
11 | /** | ||
12 | * Class GetLinksTest | ||
13 | * | ||
14 | * Test get Link list REST API service. | ||
15 | * | ||
16 | * @see http://shaarli.github.io/api-documentation/#links-links-collection-get | ||
17 | * | ||
18 | * @package Shaarli\Api\Controllers | ||
19 | */ | ||
20 | class GetLinksTest extends \PHPUnit_Framework_TestCase | ||
21 | { | ||
22 | /** | ||
23 | * @var string datastore to test write operations | ||
24 | */ | ||
25 | protected static $testDatastore = 'sandbox/datastore.php'; | ||
26 | |||
27 | /** | ||
28 | * @var ConfigManager instance | ||
29 | */ | ||
30 | protected $conf; | ||
31 | |||
32 | /** | ||
33 | * @var \ReferenceLinkDB instance. | ||
34 | */ | ||
35 | protected $refDB = null; | ||
36 | |||
37 | /** | ||
38 | * @var Container instance. | ||
39 | */ | ||
40 | protected $container; | ||
41 | |||
42 | /** | ||
43 | * @var Links controller instance. | ||
44 | */ | ||
45 | protected $controller; | ||
46 | |||
47 | /** | ||
48 | * Number of JSON field per link. | ||
49 | */ | ||
50 | const NB_FIELDS_LINK = 9; | ||
51 | |||
52 | /** | ||
53 | * Before every test, instantiate a new Api with its config, plugins and links. | ||
54 | */ | ||
55 | public function setUp() | ||
56 | { | ||
57 | $this->conf = new ConfigManager('tests/utils/config/configJson'); | ||
58 | $this->refDB = new \ReferenceLinkDB(); | ||
59 | $this->refDB->write(self::$testDatastore); | ||
60 | |||
61 | $this->container = new Container(); | ||
62 | $this->container['conf'] = $this->conf; | ||
63 | $this->container['db'] = new \LinkDB(self::$testDatastore, true, false); | ||
64 | $this->container['history'] = null; | ||
65 | |||
66 | $this->controller = new Links($this->container); | ||
67 | } | ||
68 | |||
69 | /** | ||
70 | * After every test, remove the test datastore. | ||
71 | */ | ||
72 | public function tearDown() | ||
73 | { | ||
74 | @unlink(self::$testDatastore); | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * Test basic getLinks service: returns all links. | ||
79 | */ | ||
80 | public function testGetLinks() | ||
81 | { | ||
82 | // Used by index_url(). | ||
83 | $_SERVER['SERVER_NAME'] = 'domain.tld'; | ||
84 | $_SERVER['SERVER_PORT'] = 80; | ||
85 | $_SERVER['SCRIPT_NAME'] = '/'; | ||
86 | |||
87 | $env = Environment::mock([ | ||
88 | 'REQUEST_METHOD' => 'GET', | ||
89 | ]); | ||
90 | $request = Request::createFromEnvironment($env); | ||
91 | |||
92 | $response = $this->controller->getLinks($request, new Response()); | ||
93 | $this->assertEquals(200, $response->getStatusCode()); | ||
94 | $data = json_decode((string) $response->getBody(), true); | ||
95 | $this->assertEquals($this->refDB->countLinks(), count($data)); | ||
96 | |||
97 | // Check order | ||
98 | $order = [41, 8, 6, 7, 0, 1, 9, 4, 42]; | ||
99 | $cpt = 0; | ||
100 | foreach ($data as $link) { | ||
101 | $this->assertEquals(self::NB_FIELDS_LINK, count($link)); | ||
102 | $this->assertEquals($order[$cpt++], $link['id']); | ||
103 | } | ||
104 | |||
105 | // Check first element fields | ||
106 | $first = $data[0]; | ||
107 | $this->assertEquals('http://domain.tld/?WDWyig', $first['url']); | ||
108 | $this->assertEquals('WDWyig', $first['shorturl']); | ||
109 | $this->assertEquals('Link title: @website', $first['title']); | ||
110 | $this->assertEquals( | ||
111 | 'Stallman has a beard and is part of the Free Software Foundation (or not). Seriously, read this. #hashtag', | ||
112 | $first['description'] | ||
113 | ); | ||
114 | $this->assertEquals('sTuff', $first['tags'][0]); | ||
115 | $this->assertEquals(false, $first['private']); | ||
116 | $this->assertEquals( | ||
117 | \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20150310_114651')->format(\DateTime::ATOM), | ||
118 | $first['created'] | ||
119 | ); | ||
120 | $this->assertEmpty($first['updated']); | ||
121 | |||
122 | // Multi tags | ||
123 | $link = $data[1]; | ||
124 | $this->assertEquals(7, count($link['tags'])); | ||
125 | |||
126 | // Update date | ||
127 | $this->assertEquals( | ||
128 | \DateTime::createFromFormat(\LinkDB::LINK_DATE_FORMAT, '20160803_093033')->format(\DateTime::ATOM), | ||
129 | $link['updated'] | ||
130 | ); | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * Test getLinks service with offset and limit parameter: | ||
135 | * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC). | ||
136 | */ | ||
137 | public function testGetLinksOffsetLimit() | ||
138 | { | ||
139 | $env = Environment::mock([ | ||
140 | 'REQUEST_METHOD' => 'GET', | ||
141 | 'QUERY_STRING' => 'offset=1&limit=1' | ||
142 | ]); | ||
143 | $request = Request::createFromEnvironment($env); | ||
144 | $response = $this->controller->getLinks($request, new Response()); | ||
145 | $this->assertEquals(200, $response->getStatusCode()); | ||
146 | $data = json_decode((string) $response->getBody(), true); | ||
147 | $this->assertEquals(1, count($data)); | ||
148 | $this->assertEquals(8, $data[0]['id']); | ||
149 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); | ||
150 | } | ||
151 | |||
152 | /** | ||
153 | * Test getLinks with limit=all (return all link). | ||
154 | */ | ||
155 | public function testGetLinksLimitAll() | ||
156 | { | ||
157 | $env = Environment::mock([ | ||
158 | 'REQUEST_METHOD' => 'GET', | ||
159 | 'QUERY_STRING' => 'limit=all' | ||
160 | ]); | ||
161 | $request = Request::createFromEnvironment($env); | ||
162 | $response = $this->controller->getLinks($request, new Response()); | ||
163 | $this->assertEquals(200, $response->getStatusCode()); | ||
164 | $data = json_decode((string) $response->getBody(), true); | ||
165 | $this->assertEquals($this->refDB->countLinks(), count($data)); | ||
166 | // Check order | ||
167 | $order = [41, 8, 6, 7, 0, 1, 9, 4, 42]; | ||
168 | $cpt = 0; | ||
169 | foreach ($data as $link) { | ||
170 | $this->assertEquals(self::NB_FIELDS_LINK, count($link)); | ||
171 | $this->assertEquals($order[$cpt++], $link['id']); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | /** | ||
176 | * Test getLinks service with offset and limit parameter: | ||
177 | * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC). | ||
178 | */ | ||
179 | public function testGetLinksOffsetTooHigh() | ||
180 | { | ||
181 | $env = Environment::mock([ | ||
182 | 'REQUEST_METHOD' => 'GET', | ||
183 | 'QUERY_STRING' => 'offset=100' | ||
184 | ]); | ||
185 | $request = Request::createFromEnvironment($env); | ||
186 | $response = $this->controller->getLinks($request, new Response()); | ||
187 | $this->assertEquals(200, $response->getStatusCode()); | ||
188 | $data = json_decode((string) $response->getBody(), true); | ||
189 | $this->assertEmpty(count($data)); | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * Test getLinks with visibility parameter set to all | ||
194 | */ | ||
195 | public function testGetLinksVisibilityAll() | ||
196 | { | ||
197 | $env = Environment::mock( | ||
198 | [ | ||
199 | 'REQUEST_METHOD' => 'GET', | ||
200 | 'QUERY_STRING' => 'visibility=all' | ||
201 | ] | ||
202 | ); | ||
203 | $request = Request::createFromEnvironment($env); | ||
204 | $response = $this->controller->getLinks($request, new Response()); | ||
205 | $this->assertEquals(200, $response->getStatusCode()); | ||
206 | $data = json_decode((string)$response->getBody(), true); | ||
207 | $this->assertEquals($this->refDB->countLinks(), count($data)); | ||
208 | $this->assertEquals(41, $data[0]['id']); | ||
209 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); | ||
210 | } | ||
211 | |||
212 | /** | ||
213 | * Test getLinks with visibility parameter set to private | ||
214 | */ | ||
215 | public function testGetLinksVisibilityPrivate() | ||
216 | { | ||
217 | $env = Environment::mock([ | ||
218 | 'REQUEST_METHOD' => 'GET', | ||
219 | 'QUERY_STRING' => 'visibility=private' | ||
220 | ]); | ||
221 | $request = Request::createFromEnvironment($env); | ||
222 | $response = $this->controller->getLinks($request, new Response()); | ||
223 | $this->assertEquals(200, $response->getStatusCode()); | ||
224 | $data = json_decode((string) $response->getBody(), true); | ||
225 | $this->assertEquals($this->refDB->countPrivateLinks(), count($data)); | ||
226 | $this->assertEquals(6, $data[0]['id']); | ||
227 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); | ||
228 | } | ||
229 | |||
230 | /** | ||
231 | * Test getLinks with visibility parameter set to public | ||
232 | */ | ||
233 | public function testGetLinksVisibilityPublic() | ||
234 | { | ||
235 | $env = Environment::mock( | ||
236 | [ | ||
237 | 'REQUEST_METHOD' => 'GET', | ||
238 | 'QUERY_STRING' => 'visibility=public' | ||
239 | ] | ||
240 | ); | ||
241 | $request = Request::createFromEnvironment($env); | ||
242 | $response = $this->controller->getLinks($request, new Response()); | ||
243 | $this->assertEquals(200, $response->getStatusCode()); | ||
244 | $data = json_decode((string)$response->getBody(), true); | ||
245 | $this->assertEquals($this->refDB->countPublicLinks(), count($data)); | ||
246 | $this->assertEquals(41, $data[0]['id']); | ||
247 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); | ||
248 | } | ||
249 | |||
250 | /** | ||
251 | * Test getLinks service with offset and limit parameter: | ||
252 | * limit=1 and offset=1 should return only the second link, ID=8 (ordered by creation date DESC). | ||
253 | */ | ||
254 | public function testGetLinksSearchTerm() | ||
255 | { | ||
256 | // Only in description - 1 result | ||
257 | $env = Environment::mock([ | ||
258 | 'REQUEST_METHOD' => 'GET', | ||
259 | 'QUERY_STRING' => 'searchterm=Tropical' | ||
260 | ]); | ||
261 | $request = Request::createFromEnvironment($env); | ||
262 | $response = $this->controller->getLinks($request, new Response()); | ||
263 | $this->assertEquals(200, $response->getStatusCode()); | ||
264 | $data = json_decode((string) $response->getBody(), true); | ||
265 | $this->assertEquals(1, count($data)); | ||
266 | $this->assertEquals(1, $data[0]['id']); | ||
267 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); | ||
268 | |||
269 | // Only in tags - 1 result | ||
270 | $env = Environment::mock([ | ||
271 | 'REQUEST_METHOD' => 'GET', | ||
272 | 'QUERY_STRING' => 'searchterm=tag3' | ||
273 | ]); | ||
274 | $request = Request::createFromEnvironment($env); | ||
275 | $response = $this->controller->getLinks($request, new Response()); | ||
276 | $this->assertEquals(200, $response->getStatusCode()); | ||
277 | $data = json_decode((string) $response->getBody(), true); | ||
278 | $this->assertEquals(1, count($data)); | ||
279 | $this->assertEquals(0, $data[0]['id']); | ||
280 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); | ||
281 | |||
282 | // Multiple results (2) | ||
283 | $env = Environment::mock([ | ||
284 | 'REQUEST_METHOD' => 'GET', | ||
285 | 'QUERY_STRING' => 'searchterm=stallman' | ||
286 | ]); | ||
287 | $request = Request::createFromEnvironment($env); | ||
288 | $response = $this->controller->getLinks($request, new Response()); | ||
289 | $this->assertEquals(200, $response->getStatusCode()); | ||
290 | $data = json_decode((string) $response->getBody(), true); | ||
291 | $this->assertEquals(2, count($data)); | ||
292 | $this->assertEquals(41, $data[0]['id']); | ||
293 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); | ||
294 | $this->assertEquals(8, $data[1]['id']); | ||
295 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[1])); | ||
296 | |||
297 | // Multiword - 2 results | ||
298 | $env = Environment::mock([ | ||
299 | 'REQUEST_METHOD' => 'GET', | ||
300 | 'QUERY_STRING' => 'searchterm=stallman+software' | ||
301 | ]); | ||
302 | $request = Request::createFromEnvironment($env); | ||
303 | $response = $this->controller->getLinks($request, new Response()); | ||
304 | $this->assertEquals(200, $response->getStatusCode()); | ||
305 | $data = json_decode((string) $response->getBody(), true); | ||
306 | $this->assertEquals(2, count($data)); | ||
307 | $this->assertEquals(41, $data[0]['id']); | ||
308 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); | ||
309 | $this->assertEquals(8, $data[1]['id']); | ||
310 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[1])); | ||
311 | |||
312 | // URL encoding | ||
313 | $env = Environment::mock([ | ||
314 | 'REQUEST_METHOD' => 'GET', | ||
315 | 'QUERY_STRING' => 'searchterm='. urlencode('@web') | ||
316 | ]); | ||
317 | $request = Request::createFromEnvironment($env); | ||
318 | $response = $this->controller->getLinks($request, new Response()); | ||
319 | $this->assertEquals(200, $response->getStatusCode()); | ||
320 | $data = json_decode((string) $response->getBody(), true); | ||
321 | $this->assertEquals(2, count($data)); | ||
322 | $this->assertEquals(41, $data[0]['id']); | ||
323 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); | ||
324 | $this->assertEquals(8, $data[1]['id']); | ||
325 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[1])); | ||
326 | } | ||
327 | |||
328 | public function testGetLinksSearchTermNoResult() | ||
329 | { | ||
330 | $env = Environment::mock([ | ||
331 | 'REQUEST_METHOD' => 'GET', | ||
332 | 'QUERY_STRING' => 'searchterm=nope' | ||
333 | ]); | ||
334 | $request = Request::createFromEnvironment($env); | ||
335 | $response = $this->controller->getLinks($request, new Response()); | ||
336 | $this->assertEquals(200, $response->getStatusCode()); | ||
337 | $data = json_decode((string) $response->getBody(), true); | ||
338 | $this->assertEquals(0, count($data)); | ||
339 | } | ||
340 | |||
341 | public function testGetLinksSearchTags() | ||
342 | { | ||
343 | // Single tag | ||
344 | $env = Environment::mock([ | ||
345 | 'REQUEST_METHOD' => 'GET', | ||
346 | 'QUERY_STRING' => 'searchtags=dev', | ||
347 | ]); | ||
348 | $request = Request::createFromEnvironment($env); | ||
349 | $response = $this->controller->getLinks($request, new Response()); | ||
350 | $this->assertEquals(200, $response->getStatusCode()); | ||
351 | $data = json_decode((string) $response->getBody(), true); | ||
352 | $this->assertEquals(2, count($data)); | ||
353 | $this->assertEquals(0, $data[0]['id']); | ||
354 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); | ||
355 | $this->assertEquals(4, $data[1]['id']); | ||
356 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[1])); | ||
357 | |||
358 | // Multitag + exclude | ||
359 | $env = Environment::mock([ | ||
360 | 'REQUEST_METHOD' => 'GET', | ||
361 | 'QUERY_STRING' => 'searchtags=stuff+-gnu', | ||
362 | ]); | ||
363 | $request = Request::createFromEnvironment($env); | ||
364 | $response = $this->controller->getLinks($request, new Response()); | ||
365 | $this->assertEquals(200, $response->getStatusCode()); | ||
366 | $data = json_decode((string) $response->getBody(), true); | ||
367 | $this->assertEquals(1, count($data)); | ||
368 | $this->assertEquals(41, $data[0]['id']); | ||
369 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); | ||
370 | |||
371 | // wildcard: placeholder at the start | ||
372 | $env = Environment::mock([ | ||
373 | 'REQUEST_METHOD' => 'GET', | ||
374 | 'QUERY_STRING' => 'searchtags=*Tuff', | ||
375 | ]); | ||
376 | $request = Request::createFromEnvironment($env); | ||
377 | $response = $this->controller->getLinks($request, new Response()); | ||
378 | $this->assertEquals(200, $response->getStatusCode()); | ||
379 | $data = json_decode((string) $response->getBody(), true); | ||
380 | $this->assertEquals(2, count($data)); | ||
381 | $this->assertEquals(41, $data[0]['id']); | ||
382 | |||
383 | // wildcard: placeholder at the end | ||
384 | $env = Environment::mock([ | ||
385 | 'REQUEST_METHOD' => 'GET', | ||
386 | 'QUERY_STRING' => 'searchtags=c*', | ||
387 | ]); | ||
388 | $request = Request::createFromEnvironment($env); | ||
389 | $response = $this->controller->getLinks($request, new Response()); | ||
390 | $this->assertEquals(200, $response->getStatusCode()); | ||
391 | $data = json_decode((string) $response->getBody(), true); | ||
392 | $this->assertEquals(4, count($data)); | ||
393 | $this->assertEquals(6, $data[0]['id']); | ||
394 | |||
395 | // wildcard: placeholder at the middle | ||
396 | $env = Environment::mock([ | ||
397 | 'REQUEST_METHOD' => 'GET', | ||
398 | 'QUERY_STRING' => 'searchtags=w*b', | ||
399 | ]); | ||
400 | $request = Request::createFromEnvironment($env); | ||
401 | $response = $this->controller->getLinks($request, new Response()); | ||
402 | $this->assertEquals(200, $response->getStatusCode()); | ||
403 | $data = json_decode((string) $response->getBody(), true); | ||
404 | $this->assertEquals(4, count($data)); | ||
405 | $this->assertEquals(6, $data[0]['id']); | ||
406 | |||
407 | // wildcard: match all | ||
408 | $env = Environment::mock([ | ||
409 | 'REQUEST_METHOD' => 'GET', | ||
410 | 'QUERY_STRING' => 'searchtags=*', | ||
411 | ]); | ||
412 | $request = Request::createFromEnvironment($env); | ||
413 | $response = $this->controller->getLinks($request, new Response()); | ||
414 | $this->assertEquals(200, $response->getStatusCode()); | ||
415 | $data = json_decode((string) $response->getBody(), true); | ||
416 | $this->assertEquals(9, count($data)); | ||
417 | $this->assertEquals(41, $data[0]['id']); | ||
418 | |||
419 | // wildcard: optional ('*' does not need to expand) | ||
420 | $env = Environment::mock([ | ||
421 | 'REQUEST_METHOD' => 'GET', | ||
422 | 'QUERY_STRING' => 'searchtags=*stuff*', | ||
423 | ]); | ||
424 | $request = Request::createFromEnvironment($env); | ||
425 | $response = $this->controller->getLinks($request, new Response()); | ||
426 | $this->assertEquals(200, $response->getStatusCode()); | ||
427 | $data = json_decode((string) $response->getBody(), true); | ||
428 | $this->assertEquals(2, count($data)); | ||
429 | $this->assertEquals(41, $data[0]['id']); | ||
430 | |||
431 | // wildcard: exclusions | ||
432 | $env = Environment::mock([ | ||
433 | 'REQUEST_METHOD' => 'GET', | ||
434 | 'QUERY_STRING' => 'searchtags=*a*+-*e*', | ||
435 | ]); | ||
436 | $request = Request::createFromEnvironment($env); | ||
437 | $response = $this->controller->getLinks($request, new Response()); | ||
438 | $this->assertEquals(200, $response->getStatusCode()); | ||
439 | $data = json_decode((string) $response->getBody(), true); | ||
440 | $this->assertEquals(1, count($data)); | ||
441 | $this->assertEquals(41, $data[0]['id']); // finds '#hashtag' in descr. | ||
442 | |||
443 | // wildcard: exclude all | ||
444 | $env = Environment::mock([ | ||
445 | 'REQUEST_METHOD' => 'GET', | ||
446 | 'QUERY_STRING' => 'searchtags=-*', | ||
447 | ]); | ||
448 | $request = Request::createFromEnvironment($env); | ||
449 | $response = $this->controller->getLinks($request, new Response()); | ||
450 | $this->assertEquals(200, $response->getStatusCode()); | ||
451 | $data = json_decode((string) $response->getBody(), true); | ||
452 | $this->assertEquals(0, count($data)); | ||
453 | } | ||
454 | |||
455 | /** | ||
456 | * Test getLinks service with search tags+terms. | ||
457 | */ | ||
458 | public function testGetLinksSearchTermsAndTags() | ||
459 | { | ||
460 | $env = Environment::mock([ | ||
461 | 'REQUEST_METHOD' => 'GET', | ||
462 | 'QUERY_STRING' => 'searchterm=poke&searchtags=dev', | ||
463 | ]); | ||
464 | $request = Request::createFromEnvironment($env); | ||
465 | $response = $this->controller->getLinks($request, new Response()); | ||
466 | $this->assertEquals(200, $response->getStatusCode()); | ||
467 | $data = json_decode((string) $response->getBody(), true); | ||
468 | $this->assertEquals(1, count($data)); | ||
469 | $this->assertEquals(0, $data[0]['id']); | ||
470 | $this->assertEquals(self::NB_FIELDS_LINK, count($data[0])); | ||
471 | } | ||
472 | } | ||