115 lines
4.2 KiB
PHP
115 lines
4.2 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
use App\Services\Autopodbor\Agent\Extract\TwoGisReader;
|
||
|
|
use App\Services\Autopodbor\Agent\Fetch\BatchPageFetcher;
|
||
|
|
use App\Services\Autopodbor\Agent\Fetch\DirectoryCard;
|
||
|
|
use App\Services\Autopodbor\Agent\Fetch\FetchedSite;
|
||
|
|
use App\Services\Autopodbor\Agent\Fetch\Fetcher;
|
||
|
|
use App\Services\Autopodbor\Agent\Study\DeepStudyCollector;
|
||
|
|
use App\Services\Autopodbor\Agent\Study\Fingerprint;
|
||
|
|
use App\Services\Autopodbor\Agent\Study\SiteOpener;
|
||
|
|
|
||
|
|
// Земля: клиент привязал карточку 2ГИС с номером 002005 → он якорь и источник. Слепой поиск по
|
||
|
|
// широкому имени «Притяжение» вернул чужой салон (303303) — он должен отсеяться (не бьётся с якорем).
|
||
|
|
// Доказано на живых данных (стоматология/салоны попадали в карточку конкурента) — 2026-07-06.
|
||
|
|
|
||
|
|
const CLIENT_CARD = 'https://2gis.ru/krasnoyarsk/firm/CLIENT';
|
||
|
|
const FOREIGN_FIRM = 'https://2gis.ru/krasnoyarsk/firm/FOREIGN';
|
||
|
|
|
||
|
|
function fakeXfetch(): BatchPageFetcher
|
||
|
|
{
|
||
|
|
return new class implements BatchPageFetcher
|
||
|
|
{
|
||
|
|
public function html(string $url): string
|
||
|
|
{
|
||
|
|
if ($url === CLIENT_CARD) {
|
||
|
|
return 'CLIENT';
|
||
|
|
}
|
||
|
|
if (str_contains($url, '/search/')) {
|
||
|
|
return 'SEARCH';
|
||
|
|
}
|
||
|
|
if (str_contains($url, 'FOREIGN')) {
|
||
|
|
return 'FOREIGN';
|
||
|
|
}
|
||
|
|
|
||
|
|
return '';
|
||
|
|
}
|
||
|
|
|
||
|
|
public function htmlBatch(array $urls): array
|
||
|
|
{
|
||
|
|
$out = [];
|
||
|
|
foreach ($urls as $u) {
|
||
|
|
$out[$u] = $this->html($u);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $out;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function fakeReader(): TwoGisReader
|
||
|
|
{
|
||
|
|
return new class implements TwoGisReader
|
||
|
|
{
|
||
|
|
public function listing(string $payload): array
|
||
|
|
{
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
|
||
|
|
public function card(string $payload, string $url): array
|
||
|
|
{
|
||
|
|
if ($payload === 'CLIENT') {
|
||
|
|
return [new DirectoryCard(number: '8 (391) 200-20-05', office: null, url: $url, source: '2ГИС', siteUrl: null, description: null)];
|
||
|
|
}
|
||
|
|
if ($payload === 'FOREIGN') {
|
||
|
|
return [new DirectoryCard(number: '8 (391) 230-33-03', office: null, url: $url, source: '2ГИС', siteUrl: 'http://salon.ru', description: 'Парикмахерские')];
|
||
|
|
}
|
||
|
|
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
|
||
|
|
public function branchList(string $payload): array
|
||
|
|
{
|
||
|
|
return $payload === 'SEARCH' ? ['/krasnoyarsk/firm/FOREIGN'] : [];
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function emptyOpener(): SiteOpener
|
||
|
|
{
|
||
|
|
$fetcher = new class implements Fetcher
|
||
|
|
{
|
||
|
|
public function site(string $url): FetchedSite
|
||
|
|
{
|
||
|
|
return new FetchedSite($url, '');
|
||
|
|
}
|
||
|
|
|
||
|
|
public function directory(string $url): array
|
||
|
|
{
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
return new SiteOpener($fetcher);
|
||
|
|
}
|
||
|
|
|
||
|
|
it('привязанная карточка = якорь: её номер в источниках, чужой салон из слепого поиска отсеян', function () {
|
||
|
|
$collector = new DeepStudyCollector(xfetch: fakeXfetch(), opener: emptyOpener(), reader: fakeReader());
|
||
|
|
$fp = new Fingerprint('Притяжение', '', 'Красноярск', '391', 'krasnoyarsk', false, '', [CLIENT_CARD]);
|
||
|
|
|
||
|
|
$calls = array_map(
|
||
|
|
fn ($r) => $r['identifier'],
|
||
|
|
array_values(array_filter($collector->collect($fp), fn ($r) => $r['signal_type'] === 'call')),
|
||
|
|
);
|
||
|
|
|
||
|
|
expect($calls)->toContain('73912002005') // номер с привязанной карточки — есть
|
||
|
|
->and($calls)->not->toContain('73912303303'); // салон из слепого поиска — отсеян
|
||
|
|
});
|
||
|
|
|
||
|
|
it('нет якоря совсем (без сайта и без карточек) — слепой поиск не берётся, пусто', function () {
|
||
|
|
$collector = new DeepStudyCollector(xfetch: fakeXfetch(), opener: emptyOpener(), reader: fakeReader());
|
||
|
|
$fp = new Fingerprint('Притяжение', '', 'Красноярск', '391', 'krasnoyarsk', false, '', []);
|
||
|
|
|
||
|
|
expect($collector->collect($fp))->toBe([]);
|
||
|
|
});
|