letoceiling / travelpayouts
Полный пакет для работы с Travelpayouts API (Авиабилеты, Ж/д билеты, Автобусы, Электрички)
Requires
- php: ^8.1
- guzzlehttp/guzzle: ^7.0
- illuminate/support: ^10.0|^11.0
- symfony/validator: ^6.0|^7.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- mockery/mockery: ^1.6
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0
README
Полный и гибкий PHP-пакет для работы с Travelpayouts API. Поддерживает поиск и работу с авиабилетами, ж/д билетами, автобусами, электричками и статистикой партнерской программы.
Содержание
- Возможности
- Требования
- Установка
- Быстрый старт
- Документация по сервисам
- Расширенные возможности
- Структура данных
- Обработка ошибок
- Валидация
- Интеграция с Laravel
- Лучшие практики
- Примеры использования
- Тестирование
- Troubleshooting
- FAQ
- Дополнительная документация
Возможности
- ✈️ Авиабилеты (Aviasales API) - поиск билетов, календари цен, популярные направления
- 🚂 Ж/д билеты - поиск билетов на поезда, информация о станциях
- 🚌 Автобусные билеты - поиск автобусных маршрутов
- 🚋 Электрички - поиск билетов на электрички
- 📊 Статистика - статистика бронирований, баланс, партнерская программа
- 🔄 Кэширование - встроенная поддержка кэширования для оптимизации
- 📝 Логирование - поддержка PSR-3 логирования
- 🔁 Retry механизм - автоматические повторы запросов при ошибках
- ✅ Валидация - автоматическая валидация входных данных
- 🎯 Type Safety - строгая типизация (PHP 8.1+)
- 🏗️ Laravel интеграция - готовый Service Provider и Facade
Требования
- PHP >= 8.1
- Guzzle HTTP Client ^7.0
- Symfony Validator ^6.0|^7.0
- Illuminate/Support ^10.0|^11.0 (для Laravel)
Установка
Установка через Composer
composer require letoceiling/travelpayouts
Laravel
Пакет автоматически регистрирует Service Provider. Опубликуйте конфигурационный файл:
php artisan vendor:publish --provider="Letoceiling\Travelpayouts\TravelpayoutsServiceProvider"
В файле .env добавьте:
TRAVELPAYOUTS_TOKEN=your_api_token TRAVELPAYOUTS_MARKER=your_marker
Быстрый старт
Базовая конфигурация
use Letoceiling\Travelpayouts\TravelpayoutsClient; $client = new TravelpayoutsClient([ 'token' => 'your_api_token', 'marker' => 'your_marker', // опционально 'base_uri' => 'https://api.travelpayouts.com', // по умолчанию 'timeout' => 30, // опционально, по умолчанию 30 секунд ]);
Laravel
use Letoceiling\Travelpayouts\Facades\Travelpayouts; // Использование через Facade $results = Travelpayouts::flight()->getDirectFlights([ 'origin' => 'MOW', 'destination' => 'LED', ]);
Документация по сервисам
✈️ Авиабилеты (FlightService)
Важно: Для работы с API авиабилетов необходимо зарегистрироваться на платформе Travelpayouts и подключиться к программе Aviasales. API данных доступно всем партнёрам сразу после регистрации.
getDirectFlights() - Прямые рейсы без пересадок
Получить самый дешевый билет без пересадок для указанного направления.
Параметры:
origin(string, обязательный) - IATA код города отправления (например, 'MOW')destination(string, обязательный) - IATA код города назначения (например, 'LED')depart_date(string, опциональный) - Месяц вылета в формате YYYY-MM (например, '2025-12')return_date(string, опциональный) - Месяц возвращения в формате YYYY-MMmarket(string, опциональный) - Рынок данных, по умолчанию 'ru'currency(string, опциональный) - Валюта цен (USD, EUR, RUB и т.д.)
Возвращает: array - Массив с данными о билетах, структурированный по датам
Пример:
$flightService = $client->flight(); $flights = $flightService->getDirectFlights([ 'origin' => 'MOW', 'destination' => 'LED', 'depart_date' => '2025-12', 'return_date' => '2025-12', 'market' => 'ru', 'currency' => 'USD', ]); // Структура ответа: // [ // 'success' => true, // 'data' => [ // '2025-12-01' => [ // 'price' => 4500, // 'currency' => 'USD', // 'airline' => 'SU', // 'flight_number' => 123, // 'departure_at' => '2025-12-01T10:00:00Z', // 'return_at' => '2025-12-01T12:00:00Z', // 'transfers' => 0, // ], // ... // ] // ] foreach ($flights['data'] ?? [] as $date => $flight) { echo "Дата: {$date}\n"; echo "Цена: {$flight['price']} {$flight['currency']}\n"; echo "Авиакомпания: {$flight['airline']}\n"; echo "Вылет: {$flight['departure_at']}\n"; }
getPriceCalendar() - Календарь цен (v1 API)
Возвращает самый дешевый билет для каждого дня месяца (без пересадок, с одной или двумя пересадками).
Параметры:
origin(string, обязательный) - IATA код города отправленияdestination(string, обязательный) - IATA код города назначенияdeparture_date(string, опциональный) - Месяц вылета в формате YYYY-MMreturn_date(string, опциональный) - Месяц возвращения в формате YYYY-MMcalendar_type(string, опциональный) - Тип календаря: 'departure_date' или 'return_date', по умолчанию 'departure_date'trip_duration(int, опциональный) - Длительность пребывания в днях (для поездок туда-обратно)market(string, опциональный) - Рынок данных, по умолчанию 'ru'
Возвращает: array - Календарь цен по дням месяца
Пример:
$calendar = $flightService->getPriceCalendar([ 'origin' => 'MOW', 'destination' => 'BCN', 'departure_date' => '2025-12', 'return_date' => '2025-12', 'calendar_type' => 'departure_date', 'trip_duration' => 7, 'market' => 'ru', ]); // Результат содержит календарь с ценами на каждый день foreach ($calendar['data'] ?? [] as $date => $price) { echo "Дата: {$date}, Минимальная цена: {$price}\n"; }
getLowPriceCalendar() - Календарь низких цен (v2 API)
Более современная версия API календаря цен с улучшенной структурой данных.
Параметры:
origin(string, обязательный) - IATA код города отправленияdestination(string, обязательный) - IATA код города назначенияdepart_date(string, опциональный) - Дата или месяц в формате YYYY-MM-DD или YYYY-MMreturn_date(string, опциональный) - Дата возвращенияcurrency(string, опциональный) - Валюта цен
Возвращает: array - Календарь низких цен
Пример:
$calendar = $flightService->getLowPriceCalendar([ 'origin' => 'MOW', 'destination' => 'LED', 'depart_date' => '2025-12-21', 'return_date' => '2025-12-28', 'currency' => 'USD', ]);
getWeekPriceMatrix() - Матрица цен на неделю
Возвращает цены на билеты в пределах недели относительно указанных дат вылета и возвращения.
Параметры:
origin(string, обязательный) - IATA код города отправленияdestination(string, обязательный) - IATA код города назначенияdepart_date(string, опциональный) - Дата вылетаreturn_date(string, опциональный) - Дата возвращенияcurrency(string, опциональный) - Валюта цен
Возвращает: array - Матрица цен на неделю
Пример:
$matrix = $flightService->getWeekPriceMatrix([ 'origin' => 'MOW', 'destination' => 'LED', 'depart_date' => '2025-12-21', 'return_date' => '2025-12-28', 'currency' => 'USD', ]);
getMonthPriceMatrix() - Матрица цен на месяц
Полная матрица цен для всего месяца.
Параметры:
origin(string, обязательный) - IATA код города отправленияdestination(string, обязательный) - IATA код города назначенияdepart_date(string, опциональный) - Месяц в формате YYYY-MMreturn_date(string, опциональный) - Месяц возвращенияcurrency(string, опциональный) - Валюта цен
Возвращает: array - Матрица цен на месяц
Пример:
$matrix = $flightService->getMonthPriceMatrix([ 'origin' => 'MOW', 'destination' => 'LED', 'depart_date' => '2025-12', 'currency' => 'USD', ]);
getPopularDirections() - Популярные направления
Получить список популярных направлений из указанного города с минимальными ценами.
Параметры:
origin(string, обязательный) - IATA код города отправленияcurrency(string, опциональный) - Валюта цен
Возвращает: array - Массив популярных направлений
Пример:
$directions = $flightService->getPopularDirections('MOW', 'USD'); foreach ($directions as $direction) { echo "Направление: {$direction['destination']}\n"; echo "Цена: {$direction['price']} USD\n"; echo "Популярность: {$direction['count']}\n"; // Количество поисков }
getAirlines() - Справочник авиакомпаний
Получить полный список всех авиакомпаний.
Возвращает: array - Справочник авиакомпаний с кодами IATA, названиями и другой информацией
Пример:
$airlines = $flightService->getAirlines(); foreach ($airlines as $code => $airline) { echo "Код: {$code}\n"; echo "Название: {$airline['name']}\n"; echo "Страна: {$airline['country']}\n"; }
getAirports() - Справочник аэропортов
Получить полный список всех аэропортов.
Возвращает: array - Справочник аэропортов с кодами IATA, координатами и другой информацией
Пример:
$airports = $flightService->getAirports(); foreach ($airports as $code => $airport) { echo "Код: {$code}\n"; echo "Название: {$airport['name']}\n"; echo "Город: {$airport['city']}\n"; echo "Координаты: {$airport['coordinates']['lat']}, {$airport['coordinates']['lon']}\n"; }
getCities() - Справочник городов
Получить полный список всех городов.
Возвращает: array - Справочник городов с кодами IATA и названиями
Пример:
$cities = $flightService->getCities(); foreach ($cities as $code => $city) { echo "Код: {$code}\n"; echo "Название: {$city['name']}\n"; echo "Страна: {$city['country']}\n"; } // Найти город по коду if (isset($cities['MOW'])) { echo "Москва найдена: " . $cities['MOW']['name'] . "\n"; }
🚂 Ж/д билеты (RailwayService)
search() - Поиск ж/д билетов
Параметры:
origin(string, обязательный) - Город или станция отправленияdestination(string, обязательный) - Город или станция назначенияdeparture_date(string, обязательный) - Дата отправления в формате Y-m-dreturn_date(string, опциональный) - Дата возвращения в формате Y-m-dadults(int, опциональный) - Количество взрослых, по умолчанию 1, максимум 10children(int, опциональный) - Количество детей, максимум 10infants(int, опциональный) - Количество младенцев, максимум 2class(string, опциональный) - Класс вагона: 'first', 'second', 'third', 'fourth'
Возвращает: SearchResult - Объект с результатами поиска
Пример:
$railwayService = $client->railway(); // Простой поиск $results = $railwayService->search([ 'origin' => 'Moscow', 'destination' => 'Saint Petersburg', 'departure_date' => '2025-12-25', ]); // Поиск с возвратом и пассажирами $results = $railwayService->search([ 'origin' => 'Moscow', 'destination' => 'Saint Petersburg', 'departure_date' => '2025-12-25', 'return_date' => '2025-12-30', 'adults' => 2, 'children' => 1, 'infants' => 0, 'class' => 'second', ]); // Работа с результатами echo "Найдено рейсов: " . $results->getCount() . "\n"; if ($results->isNotEmpty()) { foreach ($results->trips as $trip) { echo "Маршрут: {$trip['origin']} -> {$trip['destination']}\n"; echo "Дата отправления: {$trip['departureDate']}\n"; echo "Время отправления: {$trip['departureTime']}\n"; if (isset($trip['arrivalDate'])) { echo "Дата прибытия: {$trip['arrivalDate']}\n"; echo "Время прибытия: {$trip['arrivalTime']}\n"; } echo "Цена: {$trip['price']} {$trip['currency']}\n"; if (isset($trip['class'])) { echo "Класс: {$trip['class']}\n"; } } // Метаданные поиска if ($results->meta) { echo "Всего найдено: " . $results->meta->totalCount . "\n"; } // Пагинация if ($results->pagination) { echo "Страница: {$results->pagination->currentPage} из {$results->pagination->lastPage}\n"; } }
getStations() - Информация о станциях
Получить список станций с возможностью поиска.
Параметры:
query(string, опциональный) - Поисковый запрос для фильтрации станций
Возвращает: array - Массив станций
Пример:
// Поиск станций $stations = $railwayService->getStations('Moscow'); foreach ($stations as $station) { echo "Название: {$station['name']}\n"; echo "Код: {$station['code']}\n"; echo "Город: {$station['city']}\n"; } // Получить все станции $allStations = $railwayService->getStations();
getTripDetails() - Детали рейса
Получить детальную информацию о конкретном рейсе.
Параметры:
tripId(string, обязательный) - ID рейса
Возвращает: array - Детальная информация о рейсе
Пример:
$tripDetails = $railwayService->getTripDetails('trip_id_123'); echo "Маршрут: {$tripDetails['origin']} -> {$tripDetails['destination']}\n"; echo "Поезд: {$tripDetails['train']}\n"; echo "Вагоны: " . count($tripDetails['cars'] ?? []) . "\n"; foreach ($tripDetails['cars'] ?? [] as $car) { echo " - Вагон {$car['number']}: {$car['type']}, мест свободно: {$car['seats_available']}\n"; }
🚌 Автобусные билеты (BusService)
search() - Поиск автобусных билетов
Параметры: Аналогичны RailwayService::search()
Возвращает: SearchResult - Объект с результатами поиска
Пример:
$busService = $client->bus(); $results = $busService->search([ 'origin' => 'Moscow', 'destination' => 'Kazan', 'departure_date' => '2025-12-25', 'adults' => 1, ]);
getStations() - Станции автобусов
$stations = $busService->getStations('Moscow');
getTripDetails() - Детали рейса
$tripDetails = $busService->getTripDetails('trip_id_123');
🚋 Электрички (CommuterService)
search() - Поиск билетов на электрички
Параметры: Аналогичны RailwayService::search()
Возвращает: SearchResult - Объект с результатами поиска
Пример:
$commuterService = $client->commuter(); $results = $commuterService->search([ 'origin' => 'Moscow', 'destination' => 'Zelenograd', 'departure_date' => '2025-12-25', ]);
getStations() - Станции электричек
$stations = $commuterService->getStations('Moscow');
getTripDetails() - Детали рейса
$tripDetails = $commuterService->getTripDetails('trip_id_123');
📊 Статистика (StatisticsService)
getBookings() - Статистика бронирований
Получить статистику бронирований через вашу партнерскую программу.
Важно: Этот метод возвращает статистику уже оформленных бронирований, но НЕ выполняет бронирование.
Параметры:
start_date(string, опциональный) - Начальная дата периода в формате Y-m-dend_date(string, опциональный) - Конечная дата периода в формате Y-m-dstatus(string, опциональный) - Статус бронирования ('confirmed', 'cancelled' и т.д.)
Возвращает: array - Массив с информацией о бронированиях
Пример:
$statisticsService = $client->statistics(); // Статистика за период $bookings = $statisticsService->getBookings([ 'start_date' => '2025-01-01', 'end_date' => '2025-12-31', 'status' => 'confirmed', ]); foreach ($bookings as $booking) { echo "Бронирование #{$booking['id']}\n"; echo "Дата: {$booking['date']}\n"; echo "Сумма: {$booking['amount']} {$booking['currency']}\n"; echo "Комиссия: {$booking['commission']} {$booking['currency']}\n"; echo "Статус: {$booking['status']}\n"; }
getPartnerStats() - Статистика партнера
Получить общую статистику по партнерской программе.
Параметры:
params(array, опциональный) - Дополнительные параметры запроса
Возвращает: array - Статистика партнера
Пример:
$partnerStats = $statisticsService->getPartnerStats(); echo "Всего бронирований: {$partnerStats['total_bookings']}\n"; echo "Общая сумма: {$partnerStats['total_amount']} {$partnerStats['currency']}\n"; echo "Комиссия: {$partnerStats['total_commission']} {$partnerStats['currency']}\n"; echo "Конверсия: {$partnerStats['conversion_rate']}%\n";
getBalance() - Баланс
Получить текущий баланс в партнерской программе.
Возвращает: array - Информация о балансе
Пример:
$balance = $statisticsService->getBalance(); echo "Текущий баланс: {$balance['balance']} {$balance['currency']}\n"; echo "Доступно к выводу: {$balance['available']} {$balance['currency']}\n"; echo "В обработке: {$balance['pending']} {$balance['currency']}\n";
Расширенные возможности
Кэширование
Пакет поддерживает кэширование через PSR-16 SimpleCache интерфейс для оптимизации производительности и уменьшения нагрузки на API.
use Psr\SimpleCache\CacheInterface; // Laravel use Illuminate\Support\Facades\Cache; $client->setCache(Cache::store('redis')); // или app('cache.store') // Теперь все запросы будут кэшироваться автоматически // Время жизни кэша настраивается для каждого сервиса
Рекомендации Travelpayouts по времени жизни кэша:
- API данных (авиабилеты): 24 часа
- Станции, города, аэропорты, авиакомпании: 7-30 дней
- Статистика: 5-15 минут
- Поиск ж/д/автобусов: 1 час
- Популярные направления: 7 дней
Настройка времени жизни кэша для конкретного сервиса:
$flightService = $client->flight(); $flightService->setDefaultTtl(86400); // 24 часа
Логирование
Поддержка PSR-3 логирования для отслеживания запросов и ошибок:
use Psr\Log\LoggerInterface; // Laravel $logger = app('log'); $client->setLogger($logger); // Все запросы и ошибки будут логироваться // Уровни логирования: // - INFO: Успешные запросы // - WARNING: Повторы запросов // - ERROR: Ошибки API
Пример настройки логирования в Laravel:
// config/logging.php 'channels' => [ 'travelpayouts' => [ 'driver' => 'daily', 'path' => storage_path('logs/travelpayouts.log'), 'level' => 'debug', ], ], // Использование $client->setLogger(Log::channel('travelpayouts'));
Retry механизм
Автоматические повторы запросов при временных ошибках (timeout, 5xx ошибки):
$client = new TravelpayoutsClient([ 'token' => 'your_token', 'retries' => 3, // Количество попыток 'retry_delay' => 1000, // Задержка между попытками (мс) 'enable_retry' => true, // Включить/выключить retry механизм ]);
Настройка retry в Laravel конфигурации:
// config/travelpayouts.php return [ 'retries' => env('TRAVELPAYOUTS_RETRIES', 3), 'retry_delay' => env('TRAVELPAYOUTS_RETRY_DELAY', 1000), ];
Структура данных
SearchResult
Объект, возвращаемый методами поиска для ж/д, автобусов и электричек:
use Letoceiling\Travelpayouts\DTOs\SearchResult; $results = $railwayService->search($params); // Свойства: $results->trips; // array - Массив найденных рейсов $results->meta; // SearchMeta|null - Метаданные поиска $results->pagination; // Pagination|null - Информация о пагинации // Методы: $results->getCount(); // int - Количество найденных рейсов $results->isEmpty(); // bool - Проверка на пустой результат $results->isNotEmpty(); // bool - Проверка на наличие результатов $results->toArray(); // array - Преобразование в массив
SearchMeta
Метаданные о поисковом запросе:
$meta = $results->meta; $meta->totalCount; // int|null - Всего найдено рейсов $meta->filteredCount; // int|null - Количество после фильтрации $meta->filters; // array|null - Примененные фильтры $meta->additional; // array|null - Дополнительная информация
Pagination
Информация о пагинации:
$pagination = $results->pagination; $pagination->currentPage; // int - Текущая страница $pagination->perPage; // int - Элементов на странице $pagination->total; // int - Всего элементов $pagination->lastPage; // int - Последняя страница // Методы: $pagination->hasNextPage(); // bool - Есть следующая страница $pagination->hasPreviousPage(); // bool - Есть предыдущая страница $pagination->toArray(); // array - Преобразование в массив
Обработка ошибок
Пакет использует исключения для обработки различных типов ошибок:
use Letoceiling\Travelpayouts\Exceptions\ValidationException; use Letoceiling\Travelpayouts\Exceptions\ApiException; use Letoceiling\Travelpayouts\Exceptions\InvalidTokenException; use Letoceiling\Travelpayouts\Exceptions\TravelpayoutsException; try { $results = $railwayService->search($params); } catch (ValidationException $e) { // Ошибки валидации входных данных $errors = $e->getErrors(); foreach ($errors as $field => $message) { echo "{$field}: {$message}\n"; } } catch (InvalidTokenException $e) { // Неверный или отсутствующий API токен echo "Invalid API token: " . $e->getMessage() . "\n"; // Проверьте токен в конфигурации } catch (ApiException $e) { // Ошибки API (4xx, 5xx) echo "API Error: " . $e->getMessage() . "\n"; $response = $e->getResponse(); // Получить полный ответ $statusCode = $e->getCode(); // HTTP статус код // Обработка специфичных ошибок if ($statusCode === 429) { echo "Превышен лимит запросов. Попробуйте позже.\n"; } elseif ($statusCode >= 500) { echo "Ошибка сервера Travelpayouts. Попробуйте позже.\n"; } } catch (TravelpayoutsException $e) { // Общие ошибки пакета echo "Error: " . $e->getMessage() . "\n"; } catch (\Exception $e) { // Неожиданные ошибки echo "Unexpected error: " . $e->getMessage() . "\n"; }
Валидация
Все запросы автоматически валидируются перед отправкой к API:
Ж/д, Автобусы, Электрички
origin- обязательное, минимум 2 символаdestination- обязательное, минимум 2 символаdeparture_date- обязательное, формат Y-m-d, не раньше сегодняreturn_date- опциональное, должно быть позжеdeparture_dateadults- опциональное, по умолчанию 1, минимум 1, максимум 10children- опциональное, минимум 0, максимум 10infants- опциональное, минимум 0, максимум 2class- опциональное, должно быть одним из: 'first', 'second', 'third', 'fourth'
Авиабилеты
origin- обязательное, IATA код города (3 символа, буквы)destination- обязательное, IATA код города (3 символа, буквы)depart_date/departure_date- опциональное, формат YYYY-MM или YYYY-MM-DDreturn_date- опциональное, формат YYYY-MM или YYYY-MM-DDmarket- опциональное, по умолчанию 'ru', обычно 'ru', 'en', 'tr' и т.д.currency- опциональное, валюта цен (USD, EUR, RUB и т.д.)
Интеграция с Laravel
Service Provider
Пакет автоматически регистрирует Service Provider в Laravel. Клиент доступен через dependency injection:
use Letoceiling\Travelpayouts\TravelpayoutsClient; class FlightController extends Controller { public function __construct( private TravelpayoutsClient $travelpayouts ) {} public function search() { $results = $this->travelpayouts->flight()->getDirectFlights([ 'origin' => 'MOW', 'destination' => 'LED', ]); return response()->json($results); } }
Facade
Используйте Facade для удобного доступа:
use Letoceiling\Travelpayouts\Facades\Travelpayouts; Route::get('/flights', function () { $flights = Travelpayouts::flight()->getDirectFlights([ 'origin' => 'MOW', 'destination' => 'LED', ]); return view('flights', ['flights' => $flights]); });
Конфигурация
Опубликуйте конфигурационный файл:
php artisan vendor:publish --provider="Letoceiling\Travelpayouts\TravelpayoutsServiceProvider"
Файл config/travelpayouts.php:
return [ 'token' => env('TRAVELPAYOUTS_TOKEN'), 'marker' => env('TRAVELPAYOUTS_MARKER'), 'base_uri' => env('TRAVELPAYOUTS_BASE_URI', 'https://api.travelpayouts.com'), 'timeout' => env('TRAVELPAYOUTS_TIMEOUT', 30), 'retries' => env('TRAVELPAYOUTS_RETRIES', 3), 'retry_delay' => env('TRAVELPAYOUTS_RETRY_DELAY', 1000), ];
Кэширование в Laravel
use Illuminate\Support\Facades\Cache; use Letoceiling\Travelpayouts\Facades\Travelpayouts; // Настройка кэширования Travelpayouts::setCache(Cache::store('redis')); // Использование с кэшированием $flights = Travelpayouts::flight()->getDirectFlights([ 'origin' => 'MOW', 'destination' => 'LED', ]);
Логирование в Laravel
use Illuminate\Support\Facades\Log; use Letoceiling\Travelpayouts\Facades\Travelpayouts; Travelpayouts::setLogger(Log::channel('travelpayouts'));
Service Container Binding
Вы можете переопределить клиент в сервис-провайдере:
// app/Providers/AppServiceProvider.php use Letoceiling\Travelpayouts\TravelpayoutsClient; public function register() { $this->app->singleton(TravelpayoutsClient::class, function ($app) { $config = $app['config']['travelpayouts']; $client = new TravelpayoutsClient([ 'token' => $config['token'], 'marker' => $config['marker'], 'base_uri' => $config['base_uri'], 'timeout' => $config['timeout'], ]); // Настройка кэширования if ($config['cache']['enabled'] ?? false) { $client->setCache($app['cache.store']); } // Настройка логирования $client->setLogger($app['log']); return $client; }); }
Лучшие практики
1. Всегда используйте кэширование
// ✅ Хорошо $client->setCache($cache); $flights = $client->flight()->getDirectFlights($params); // ❌ Плохо - каждый раз запрос к API $flights = $client->flight()->getDirectFlights($params);
2. Обрабатывайте ошибки
// ✅ Хорошо try { $results = $railwayService->search($params); } catch (ValidationException $e) { return response()->json(['errors' => $e->getErrors()], 422); } catch (ApiException $e) { Log::error('Travelpayouts API error', ['exception' => $e]); return response()->json(['error' => 'Service unavailable'], 503); } // ❌ Плохо - игнорирование ошибок $results = $railwayService->search($params);
3. Используйте правильные форматы дат
// ✅ Хорошо 'departure_date' => '2025-12-25', // Y-m-d для ж/д 'depart_date' => '2025-12', // YYYY-MM для авиа (месяц) 'depart_date' => '2025-12-25', // YYYY-MM-DD для авиа (дата) // ❌ Плохо 'departure_date' => '25.12.2025', // Неправильный формат
4. Валидируйте входные данные на стороне приложения
// ✅ Хорошо $request->validate([ 'origin' => 'required|string|min:2', 'destination' => 'required|string|min:2', 'departure_date' => 'required|date|after:today', ]); // Пакет также валидирует данные, но лучше проверить заранее
5. Логируйте важные операции
// ✅ Хорошо Log::info('Flight search', [ 'origin' => $params['origin'], 'destination' => $params['destination'], 'date' => $params['depart_date'], ]);
6. Используйте правильные IATA коды
// ✅ Хорошо - используйте справочники $cities = $flightService->getCities(); if (!isset($cities[$origin])) { throw new InvalidArgumentException("Invalid origin city code: {$origin}"); } // ❌ Плохо - хардкод без проверки $flights = $flightService->getDirectFlights(['origin' => 'XXX']);
Примеры использования
Поиск дешевых авиабилетов
$flightService = $client->flight(); // Найти самые дешевые билеты из Москвы в Санкт-Петербург на декабрь $calendar = $flightService->getLowPriceCalendar([ 'origin' => 'MOW', 'destination' => 'LED', 'depart_date' => '2025-12', 'currency' => 'RUB', ]); // Найти самый дешевый день $minPrice = PHP_INT_MAX; $bestDate = null; foreach ($calendar['data'] ?? [] as $date => $flight) { if (isset($flight['price']) && $flight['price'] < $minPrice) { $minPrice = $flight['price']; $bestDate = $date; } } if ($bestDate) { echo "Самый дешевый билет на {$bestDate}: {$minPrice} RUB\n"; } else { echo "Билеты не найдены\n"; }
Поиск популярных направлений
$directions = $flightService->getPopularDirections('MOW', 'USD'); // Отсортировать по цене usort($directions, fn($a, $b) => ($a['price'] ?? 0) <=> ($b['price'] ?? 0)); // Показать топ-10 самых дешевых направлений $top10 = array_slice($directions, 0, 10); foreach ($top10 as $direction) { echo "{$direction['destination']}: {$direction['price']} USD\n"; }
Комплексный поиск ж/д билетов
$railwayService = $client->railway(); try { // Поиск билетов на поезд $results = $railwayService->search([ 'origin' => 'Moscow', 'destination' => 'Saint Petersburg', 'departure_date' => '2025-12-25', 'return_date' => '2025-12-30', 'adults' => 2, 'children' => 1, 'class' => 'second', ]); if ($results->isEmpty()) { echo "Билеты не найдены\n"; return; } echo "Найдено рейсов: " . $results->getCount() . "\n"; // Показать информацию о каждом рейсе foreach ($results->trips as $index => $trip) { echo "\n--- Рейс #" . ($index + 1) . " ---\n"; echo "Отправление: {$trip['origin']}\n"; echo "Прибытие: {$trip['destination']}\n"; echo "Дата отправления: {$trip['departureDate']}\n"; echo "Время отправления: {$trip['departureTime']}\n"; if (isset($trip['arrivalDate'])) { echo "Дата прибытия: {$trip['arrivalDate']}\n"; echo "Время прибытия: {$trip['arrivalTime']}\n"; } echo "Цена: {$trip['price']} {$trip['currency']}\n"; if (isset($trip['class'])) { echo "Класс: {$trip['class']}\n"; } } // Метаданные if ($results->meta) { echo "\nВсего найдено: " . ($results->meta->totalCount ?? 'N/A') . "\n"; } // Пагинация if ($results->pagination && $results->pagination->hasNextPage()) { echo "Есть еще результаты на следующих страницах\n"; } } catch (ValidationException $e) { echo "Ошибки валидации:\n"; foreach ($e->getErrors() as $field => $message) { echo " {$field}: {$message}\n"; } } catch (ApiException $e) { echo "Ошибка API: " . $e->getMessage() . "\n"; }
Работа со статистикой
$statisticsService = $client->statistics(); try { // Получить статистику за текущий месяц $bookings = $statisticsService->getBookings([ 'start_date' => date('Y-m-01'), 'end_date' => date('Y-m-t'), ]); // Получить баланс $balance = $statisticsService->getBalance(); echo "Текущий баланс: {$balance['balance']} {$balance['currency']}\n"; echo "Доступно к выводу: {$balance['available']} {$balance['currency']}\n"; echo "В обработке: {$balance['pending']} {$balance['currency']}\n"; echo "Бронирований за месяц: " . count($bookings) . "\n"; // Подсчет общей суммы комиссий $totalCommission = 0; foreach ($bookings as $booking) { if (isset($booking['commission'])) { $totalCommission += $booking['commission']; } } echo "Общая комиссия за месяц: {$totalCommission} {$balance['currency']}\n"; } catch (ApiException $e) { echo "Ошибка при получении статистики: " . $e->getMessage() . "\n"; }
Использование с кэшированием
use Psr\SimpleCache\CacheInterface; // Настройка кэширования $client->setCache($cache); // Первый запрос - идет к API $flights1 = $client->flight()->getDirectFlights([ 'origin' => 'MOW', 'destination' => 'LED', ]); // Второй запрос - из кэша (если TTL не истек) $flights2 = $client->flight()->getDirectFlights([ 'origin' => 'MOW', 'destination' => 'LED', ]);
Тестирование
# Запустить все тесты composer test # Статический анализ кода composer analyse # Проверка стиля кода composer check-style # Автоисправление стиля composer fix
Troubleshooting
Ошибка "Token is required"
Проблема: Не указан API токен
Решение:
// Проверьте конфигурацию $client = new TravelpayoutsClient([ 'token' => 'your_api_token', // Обязательно ]);
Ошибка "Invalid API token"
Проблема: Указан неверный токен
Решение:
- Проверьте токен в личном кабинете Travelpayouts
- Убедитесь, что токен скопирован полностью
- Проверьте, что токен не истек
Пустые результаты поиска
Проблема: Поиск не возвращает результатов
Возможные причины:
- Нет рейсов на указанные даты
- Неправильно указаны города/станции
- Дата в прошлом
- Неправильный формат даты
Решение:
// Проверьте параметры $results = $railwayService->search([ 'origin' => 'Moscow', // Правильное название 'destination' => 'Saint Petersburg', 'departure_date' => '2025-12-25', // Дата в будущем, формат Y-m-d ]); if ($results->isEmpty()) { echo "Рейсы не найдены на указанные даты\n"; // Попробуйте другую дату или проверьте наличие рейсов }
Медленная работа API
Проблема: Запросы выполняются медленно
Решение:
- Включите кэширование
- Увеличьте timeout
- Используйте retry механизм
$client = new TravelpayoutsClient([ 'token' => 'your_token', 'timeout' => 60, // Увеличить таймаут ]); $client->setCache($cache); // Включить кэширование
Ошибка 429 (Too Many Requests)
Проблема: Превышен лимит запросов
Решение:
- Включите кэширование для уменьшения количества запросов
- Увеличьте задержку между запросами
- Используйте retry механизм с экспоненциальной задержкой
$client = new TravelpayoutsClient([ 'token' => 'your_token', 'retries' => 3, 'retry_delay' => 2000, // Увеличить задержку ]);
FAQ
Можно ли оформлять билеты через пакет?
Нет. Пакет предоставляет только функциональность поиска. Оформление билетов происходит на сайтах партнеров Travelpayouts. Пользователи перенаправляются на сайт партнера для завершения бронирования.
Есть ли тестовая среда?
Нет. Travelpayouts не предоставляет отдельной тестовой среды. После регистрации вы получаете доступ к реальному API.
Как получить IATA коды городов?
Используйте метод getCities():
$cities = $flightService->getCities(); foreach ($cities as $code => $city) { echo "{$code}: {$city['name']}\n"; }
Как долго кэшировать данные?
Travelpayouts рекомендует:
- API данных (авиабилеты): 24 часа
- Справочники (города, аэропорты): 7-30 дней
- Статистика: 5-15 минут
Поддерживается ли API поиска в реальном времени?
Текущая версия пакета использует API данных (кэшированные данные). API поиска в реальном времени требует отдельной заявки и соответствия требованиям (минимум 50,000 пользователей в месяц).
Как отслеживать бронирования?
Используйте метод getBookings() в StatisticsService для получения статистики бронирований через вашу партнерскую программу.
Дополнительная документация
- Возможности API и ограничения - Что поддерживается и что нет
- Официальная документация Travelpayouts
- API авиабилетов (Aviasales)
- API данных Aviasales
- CHANGELOG
- CONTRIBUTING
Важные замечания
⚠️ Ограничения пакета
Пакет НЕ поддерживает:
- ❌ Оформление билетов
- ❌ Покупку билетов
- ❌ Оплату билетов
- ❌ Тестовую среду (sandbox)
Что поддерживается:
- ✅ Поиск билетов (авиа, ж/д, автобусы, электрички)
- ✅ Сравнение цен
- ✅ Получение справочной информации
- ✅ Статистика бронирований (после оформления пользователями)
Travelpayouts работает по модели партнерской программы: пользователи перенаправляются на сайты партнеров для оформления билетов. Вы получаете комиссию с каждого оформленного бронирования.
Подробнее см. API_CAPABILITIES.md
API данных vs API поиска
API данных (используется в пакете):
- Доступно всем партнёрам после регистрации
- Данные кэшируются на стороне Travelpayouts (2-7 дней)
- Подходит для информирования пользователей и контентных страниц
- Рекомендуется кэшировать на 24 часа
API поиска в реальном времени:
- Требует одобрения заявки
- Минимум 50,000 пользователей в месяц
- Актуальные данные в реальном времени
- Подходит для полноценного поиска билетов
IATA коды
Для работы с API авиабилетов используются IATA коды городов (например, MOW для Москвы, LED для Санкт-Петербурга). Список кодов можно получить через метод getCities().
Кэширование
Travelpayouts рекомендует кэшировать результаты API данных на своей стороне минимум на 24 часа для уменьшения нагрузки на серверы и увеличения скорости работы приложения.
Лицензия
MIT License
Поддержка
Если у вас возникли вопросы или проблемы:
- Создайте Issue в репозитории
- Обратитесь к официальной документации Travelpayouts
Авторы
- Letoceiling Coder - Разработка - GitHub
Благодарности
- Travelpayouts за предоставление API
- Сообществу за обратную связь и улучшения