Рано или поздно каждый разработчик на Yii2 сталкивается с задачей прикрутить к проекту оплату. Казалось бы, что тут сложного? Взял SDK, вызвал метод, получил деньги. Но на практике всё оказывается чуть сложнее: то документация куцая, то вебхуки не приходят, то тестовый режим работает не так, как боевой. В этой статье я расскажу, как без боли интегрировать платежные системы в Yii2, какие подводные камни есть и как их обойти.
Почему Yii2 и платежки — это не страшно
Yii2 — это мощный фреймворк, который даёт нам кучу инструментов: компоненты, модули, поведение, миграции. Платежные системы — это просто внешние API, с которыми нужно общаться. Если подойти с умом, интеграция превращается в рутину, а не в головную боль. Главное — понять архитектуру и не пытаться всё сделать в одном контроллере.
Я обычно разбиваю задачу на три части: создание платежа, обработка ответа от платежной системы (вебхук) и возврат пользователя на сайт. Каждая часть — отдельная ответственность. Так проще тестировать и поддерживать.
Выбор платежной системы: на что смотреть
Прежде чем писать код, надо выбрать, с кем работать. У каждой платежки свои тарифы, API, требования. Вот таблица, которая поможет сравнить популярные варианты.
| Платежная система | Комиссия | Сложность интеграции | Поддержка в РФ |
|---|---|---|---|
| ЮKassa | 2.8% - 3.5% | Средняя | Да |
| Тинькофф | 2.5% - 3% | Низкая | Да |
| PayPal | 4.4% + $0.3 | Высокая | Нет |
| Stripe | 2.9% + $0.3 | Средняя | Ограниченно |
Для российских проектов чаще берут ЮKassa или Тинькофф. Они дают хорошую документацию и тестовые среды. Если нужен международный приём, смотрите в сторону Stripe или PayPal, но учитывайте юридические нюансы.
Архитектура интеграции: не пихайте всё в контроллер
Типичная ошибка новичка — написать весь код оплаты в одном действии контроллера. Потом добавить второй способ оплаты, третий, и начинается каша. Я предлагаю сразу сделать правильно: создать отдельный модуль или компонент для работы с платежами.
Например, можно сделать компонент PaymentComponent, который будет отвечать за создание платежа, проверку статуса и обработку вебхуков. А в контроллере только вызывать его методы.
Вот пример структуры:
// config/web.php
'components' => [
'payment' => [
'class' => 'app\components\PaymentComponent',
'apiKey' => 'your_api_key',
'shopId' => 'your_shop_id',
],
],
Теперь в любом месте приложения можно обратиться к Yii::$app->payment и вызвать нужный метод. Это чисто и удобно.
Пишем код: создание платежа и обработка вебхука
Давайте рассмотрим конкретный пример на основе ЮKassa. У них есть официальный SDK для PHP, но мы будем использовать его через Yii2-обёртку. Предположим, у нас есть модель Order с полями id, amount, status.
Создаём действие для инициализации платежа:
public function actionCreatePayment($orderId)
{
$order = Order::findOne($orderId);
if (!$order) {
throw new NotFoundHttpException('Заказ не найден');
}
$payment = Yii::$app->payment->createPayment([
'amount' => $order->amount,
'currency' => 'RUB',
'description' => 'Оплата заказа #' . $order->id,
'return_url' => Url::to(['order/success', 'id' => $order->id], true),
]);
// Сохраняем идентификатор платежа в заказе
$order->payment_id = $payment['id'];
$order->save();
// Перенаправляем пользователя на страницу оплаты
return $this->redirect($payment['confirmation']['confirmation_url']);
}
Теперь про вебхуки. Платежная система после успешной оплаты отправит POST-запрос на ваш сервер. Нужно создать отдельное действие, которое примет уведомление и обновит статус заказа.
public function actionWebhook()
{
$request = Yii::$app->request;
if (!$request->isPost) {
throw new BadRequestHttpException('Only POST allowed');
}
$data = json_decode($request->getRawBody(), true);
// Проверяем подпись или IP-адрес отправителя
if (!Yii::$app->payment->validateWebhook($data)) {
throw new ForbiddenHttpException('Invalid signature');
}
$event = $data['event'];
$paymentId = $data['object']['id'];
$order = Order::findOne(['payment_id' => $paymentId]);
if (!$order) {
return 'Order not found';
}
if ($event === 'payment.succeeded') {
$order->status = Order::STATUS_PAID;
$order->save();
} elseif ($event === 'payment.canceled') {
$order->status = Order::STATUS_CANCELED;
$order->save();
}
return 'OK';
}
Обратите внимание: вебхук должен отвечать быстро и не выполнять тяжёлых операций. Если нужно отправить письмо или сгенерировать чек, лучше поставить задачу в очередь.
Лайфхаки и подводные камни
За годы работы я собрал несколько советов, которые сэкономят вам нервы.
- Всегда используйте тестовый режим. Даже если уверены, что всё работает. Платежки дают песочницу, где можно прогнать все сценарии.
- Логируйте всё. Запросы, ответы, вебхуки. При разборе инцидентов логи — ваш лучший друг.
- Не доверяйте сумме из вебхука. Сверяйте с суммой заказа в базе. Мошенники могут подменить данные.
- Используйте идемпотентность. Если вебхук пришёл дважды, не обрабатывайте его повторно. Сохраняйте ID события.
Ещё один момент: возвраты. Пользователь может запросить возврат средств. В Yii2 удобно сделать отдельное действие, которое вызывает метод refund у платежного компонента. Не забудьте обновить статус заказа.
Что в итоге
Интеграция платежных систем в Yii2 — задача, которая требует аккуратности и понимания архитектуры. Вынесите логику в компонент, используйте тестовый режим, логируйте всё и не забывайте про безопасность. Тогда оплата будет работать как часы, а вы сэкономите время на отладку.
Если чувствуете, что не хватает опыта, обратитесь к профессионалам. Digital-студия WNDER поможет настроить платежи под ключ.


