Рано или поздно каждый разработчик на Yii2 сталкивается с задачей прикрутить к проекту оплату. Казалось бы, что тут сложного? Взял SDK, вызвал метод, получил деньги. Но на практике всё оказывается чуть сложнее: то документация куцая, то вебхуки не приходят, то тестовый режим работает не так, как боевой. В этой статье я расскажу, как без боли интегрировать платежные системы в Yii2, какие подводные камни есть и как их обойти.

Digital-студия WNDER

Почему 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 поможет настроить платежи под ключ.

Студия WNDER