115 - Add Belga JSON discovery parser for press-release API
This commit is contained in:
parent
00366ffeaa
commit
2a4d4ad84d
5 changed files with 165 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -24,3 +24,4 @@ yarn-error.log
|
||||||
/coverage-report*
|
/coverage-report*
|
||||||
/coverage.xml
|
/coverage.xml
|
||||||
/.php-cs-fixer.dist.php
|
/.php-cs-fixer.dist.php
|
||||||
|
/.php-cs-fixer.cache
|
||||||
|
|
|
||||||
25
app/Services/Parsers/BelgaHomepageParser.php
Normal file
25
app/Services/Parsers/BelgaHomepageParser.php
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Parsers;
|
||||||
|
|
||||||
|
class BelgaHomepageParser
|
||||||
|
{
|
||||||
|
private const ARTICLE_URL_TEMPLATE = 'https://www.belganewsagency.eu/press-releases/%s/';
|
||||||
|
|
||||||
|
public static function extractArticleUrls(string $json): array
|
||||||
|
{
|
||||||
|
$decoded = json_decode($json, true);
|
||||||
|
|
||||||
|
if (! is_array($decoded) || ! isset($decoded['data']) || ! is_array($decoded['data'])) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return collect($decoded['data'])
|
||||||
|
->pluck('id')
|
||||||
|
->filter(fn($id) => is_int($id) || (is_string($id) && ctype_digit($id)))
|
||||||
|
->map(fn($id) => sprintf(self::ARTICLE_URL_TEMPLATE, $id))
|
||||||
|
->unique()
|
||||||
|
->values()
|
||||||
|
->toArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
34
app/Services/Parsers/BelgaHomepageParserAdapter.php
Normal file
34
app/Services/Parsers/BelgaHomepageParserAdapter.php
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Parsers;
|
||||||
|
|
||||||
|
use App\Contracts\HomepageParserInterface;
|
||||||
|
|
||||||
|
class BelgaHomepageParserAdapter implements HomepageParserInterface
|
||||||
|
{
|
||||||
|
private const API_URL = 'https://capi.belga.press/belgapress/api/public/pressreleases?offset=1&count=6&search=&start=&end=&newsroomId=70&language=EN';
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private string $language = 'en',
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function canParse(string $url): bool
|
||||||
|
{
|
||||||
|
return str_contains($url, 'belganewsagency.eu') || str_contains($url, 'capi.belga.press');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function extractArticleUrls(string $html): array
|
||||||
|
{
|
||||||
|
return BelgaHomepageParser::extractArticleUrls($html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHomepageUrl(): string
|
||||||
|
{
|
||||||
|
return str_replace('language=EN', 'language=' . strtoupper($this->language), self::API_URL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSourceName(): string
|
||||||
|
{
|
||||||
|
return 'Belga News Agency';
|
||||||
|
}
|
||||||
|
}
|
||||||
1
tests/Fixtures/belga-pressreleases.json
Normal file
1
tests/Fixtures/belga-pressreleases.json
Normal file
File diff suppressed because one or more lines are too long
104
tests/Unit/Services/Parsers/BelgaHomepageParserTest.php
Normal file
104
tests/Unit/Services/Parsers/BelgaHomepageParserTest.php
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit\Services\Parsers;
|
||||||
|
|
||||||
|
use App\Services\Parsers\BelgaHomepageParser;
|
||||||
|
use App\Services\Parsers\BelgaHomepageParserAdapter;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class BelgaHomepageParserTest extends TestCase
|
||||||
|
{
|
||||||
|
private function fixture(): string
|
||||||
|
{
|
||||||
|
return file_get_contents(__DIR__ . '/../../../Fixtures/belga-pressreleases.json');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_extracts_article_urls_from_api_json(): void
|
||||||
|
{
|
||||||
|
$urls = BelgaHomepageParser::extractArticleUrls($this->fixture());
|
||||||
|
|
||||||
|
$this->assertCount(6, $urls);
|
||||||
|
$this->assertSame('https://www.belganewsagency.eu/press-releases/35285/', $urls[0]);
|
||||||
|
$this->assertContains('https://www.belganewsagency.eu/press-releases/35269/', $urls);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_deduplicates_urls(): void
|
||||||
|
{
|
||||||
|
$json = json_encode(['data' => [
|
||||||
|
['id' => 100],
|
||||||
|
['id' => 100],
|
||||||
|
['id' => '100'],
|
||||||
|
['id' => 101],
|
||||||
|
]]);
|
||||||
|
|
||||||
|
$urls = BelgaHomepageParser::extractArticleUrls($json);
|
||||||
|
|
||||||
|
$this->assertSame([
|
||||||
|
'https://www.belganewsagency.eu/press-releases/100/',
|
||||||
|
'https://www.belganewsagency.eu/press-releases/101/',
|
||||||
|
], $urls);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_returns_empty_array_for_malformed_json(): void
|
||||||
|
{
|
||||||
|
$this->assertSame([], BelgaHomepageParser::extractArticleUrls('<html>404 not found</html>'));
|
||||||
|
$this->assertSame([], BelgaHomepageParser::extractArticleUrls('{"data": ['));
|
||||||
|
$this->assertSame([], BelgaHomepageParser::extractArticleUrls(''));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_returns_empty_array_when_data_key_missing_or_empty(): void
|
||||||
|
{
|
||||||
|
$this->assertSame([], BelgaHomepageParser::extractArticleUrls('{}'));
|
||||||
|
$this->assertSame([], BelgaHomepageParser::extractArticleUrls('{"data": []}'));
|
||||||
|
$this->assertSame([], BelgaHomepageParser::extractArticleUrls('{"data": "not-an-array"}'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_skips_entries_without_usable_id(): void
|
||||||
|
{
|
||||||
|
$json = json_encode(['data' => [
|
||||||
|
['id' => 200],
|
||||||
|
['id' => null],
|
||||||
|
['publishDate' => '2026-08-01T06:24:19'],
|
||||||
|
['id' => 'not-numeric'],
|
||||||
|
['id' => 201],
|
||||||
|
]]);
|
||||||
|
|
||||||
|
$urls = BelgaHomepageParser::extractArticleUrls($json);
|
||||||
|
|
||||||
|
$this->assertSame([
|
||||||
|
'https://www.belganewsagency.eu/press-releases/200/',
|
||||||
|
'https://www.belganewsagency.eu/press-releases/201/',
|
||||||
|
], $urls);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_adapter_delegates_and_reports_source(): void
|
||||||
|
{
|
||||||
|
$adapter = new BelgaHomepageParserAdapter('en');
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
BelgaHomepageParser::extractArticleUrls($this->fixture()),
|
||||||
|
$adapter->extractArticleUrls($this->fixture())
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertTrue($adapter->canParse('https://www.belganewsagency.eu/press-releases/35285/'));
|
||||||
|
$this->assertTrue($adapter->canParse('https://capi.belga.press/belgapress/api/public/pressreleases'));
|
||||||
|
$this->assertFalse($adapter->canParse('https://www.vrt.be/vrtnws/en/'));
|
||||||
|
$this->assertSame('Belga News Agency', $adapter->getSourceName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_adapter_uppercases_language_in_api_url(): void
|
||||||
|
{
|
||||||
|
$this->assertStringContainsString('language=EN', (new BelgaHomepageParserAdapter('en'))->getHomepageUrl());
|
||||||
|
$this->assertStringContainsString('language=NL', (new BelgaHomepageParserAdapter('nl'))->getHomepageUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_adapter_api_url_pins_load_bearing_query_params(): void
|
||||||
|
{
|
||||||
|
$url = (new BelgaHomepageParserAdapter('en'))->getHomepageUrl();
|
||||||
|
|
||||||
|
$this->assertStringStartsWith('https://capi.belga.press/belgapress/api/public/pressreleases?', $url);
|
||||||
|
$this->assertStringContainsString('newsroomId=70', $url);
|
||||||
|
$this->assertStringContainsString('offset=1', $url);
|
||||||
|
$this->assertStringContainsString('count=6', $url);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue