Files
portal/app/app/Services/Autopodbor/AutopodborNormalizer.php
T
2026-06-28 14:33:11 +03:00

106 lines
4.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\Autopodbor;
use App\Support\PhoneNormalizer;
/**
* Нормализует домены и телефоны для дедупликации конкурентов и источников.
*/
final class AutopodborNormalizer
{
/**
* Возвращает «голову» домена: без схемы, www, пути, порта, нижний регистр.
* Примеры:
* https://www.Okna-Komfort.RU/contacts → okna-komfort.ru
* http://site.ru:8080/path?x=1 → site.ru
*/
public function domainHead(string $raw): string
{
$s = trim(mb_strtolower($raw));
// Убираем схему (http://, https://, ftp:// и т.п.)
$s = preg_replace('#^[a-z]+://#', '', $s);
// Убираем www.
$s = preg_replace('#^www\.#', '', $s);
// Берём только host часть (до первого /)
$s = explode('/', $s)[0];
// Убираем query string если вдруг осталась
$s = explode('?', $s)[0];
// Убираем порт
$s = explode(':', $s)[0];
return $s;
}
/**
* Нормализует телефон к виду 7xxxxxxxxxx (11 цифр, без плюса).
* Использует существующий PhoneNormalizer::normalize, который возвращает +7XXXXXXXXXX.
*/
public function phone(string $raw): string
{
$normalized = PhoneNormalizer::normalize($raw);
if ($normalized === null) {
// Fallback: оставить только цифры и привести к 7xxxxxxxxxx
$digits = preg_replace('/\D+/', '', $raw) ?? '';
if (strlen($digits) === 11 && ($digits[0] === '8' || $digits[0] === '7')) {
return '7' . substr($digits, 1);
}
if (strlen($digits) === 10) {
return '7' . $digits;
}
return $digits;
}
// PhoneNormalizer возвращает +7XXXXXXXXXX — срезаем ведущий '+'
return ltrim($normalized, '+');
}
/**
* Строит dedup-ключ для источника (сайт или звонок).
* Формат: «type:нормализованный_идентификатор»
*/
public function sourceKey(string $type, string $identifier): string
{
$id = $type === 'call'
? $this->phone($identifier)
: $this->domainHead($identifier);
return $type . ':' . $id;
}
/**
* Срезает хвостовой значок (✓ или 🎭) вместе с пробелами перед ним.
* Если значка нет — строка возвращается без изменений.
* Примеры:
* 'Окна Комфорт ✓' → 'Окна Комфорт'
* 'Окна Комфорт 🎭' → 'Окна Комфорт'
* 'Окна Комфорт' → 'Окна Комфорт'
* 'Балкон-Сервис 16' → 'Балкон-Сервис 16'
*/
public function stripBadge(string $name): string
{
// Срезаем ровно один хвостовой значок (✓ или 🎭) вместе с пробелами перед ним.
// Используем mb-безопасный regex с флагом u (эмодзи 🎭 — 4-байтный).
return preg_replace('/\s*(?:\x{2713}|\x{1F3AD})\s*$/u', '', $name) ?? $name;
}
/**
* Строит dedup-ключ для конкурента.
* Если есть сайт — «site:домен», иначе «name:имя_в_нижнем_регистре».
*/
public function competitorKey(string $name, ?string $siteUrl): string
{
if ($siteUrl !== null) {
return 'site:' . $this->domainHead($siteUrl);
}
// Нижний регистр + схлопываем пробелы
$normalized = preg_replace('#\s+#u', ' ', trim(mb_strtolower($name)));
return 'name:' . $normalized;
}
}