Installation:
composer require arturwwl/przelewy24-bundle
Register the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3.x):
return [
// ...
Arturwwl\Przelewy24Bundle\ArturwwlPrzelewy24Bundle::class => ['all' => true],
];
Routing:
Add to config/routes.yaml:
arturwwl_przelewy24:
resource: "@ArturwwlPrzelewy24Bundle/Resources/config/routing.xml"
Configuration:
Add to config/packages/arturwwl_przelewy24.yaml:
arturwwl_przelewy24:
sandbox: true # Set to false for production
merchant_id: "%env(PRZELEWY24_MERCHANT_ID)%"
crc_key: "%env(PRZELEWY24_CRC_KEY)%"
use Arturwwl\Przelewy24Bundle\Factory\ProcessFactory;
use Arturwwl\Przelewy24Bundle\Model\Payment;
class PaymentController extends AbstractController
{
public function initiatePayment(ProcessFactory $processFactory): Response
{
$payment = (new Payment())
->setCurrency('PLN')
->setSessionId(uniqid()) // Unique order identifier
->setAmount(100.00)
->setDescription('Test payment')
->setEmail('customer@example.com')
->setStatusUrl($this->generateUrl('payment_status'))
->setReturnUrl($this->generateUrl('payment_return', [], UrlGeneratorInterface::ABSOLUTE_URL));
$processFactory->setPayment($payment);
$url = $processFactory->createAndGetUrl(
$this->getParameter('arturwwl_przelewy24.merchant_id'),
$this->getParameter('arturwwl_przelewy24.crc_key')
);
return $this->redirect($url);
}
}
Initiate Payment:
ProcessFactory to create a Payment object.sessionId, amount, currency, returnUrl, statusUrl).createAndGetUrl().Handle Callbacks:
przelewy24.event.payment_success (via Symfony Events).statusUrl to verify payments:
public function paymentStatus(ProcessFactory $processFactory, Request $request): Response
{
$response = $processFactory->verifyPayment(
$request->query->get('sessionId'),
$request->query->get('amount'),
$request->query->get('currency'),
$request->query->get('signature')
);
if ($response->isSuccess()) {
// Dispatch event or update order status
}
return new Response('OK');
}
Event-Driven Logic:
# config/services.yaml
App\EventListener\Przelewy24SuccessListener:
tags:
- { name: kernel.event_listener, event: przelewy24.event.payment_success, method: onPaymentSuccess }
Order Management:
Store sessionId in your database to link payments to orders. Use it to fetch order details in event listeners.
$order = $this->orderRepository->findOneBy(['token' => $event->getPayment()->getSessionId()]);
Testing:
Use the built-in test tools (/p24-test) to simulate payments in development.
Trigger fake success with /p24-fake-success/{sessionId}.
Customization:
Extend the Payment model or override services via dependency injection:
# config/services.yaml
services:
Arturwwl\Przelewy24Bundle\Model\Payment:
arguments:
$customField: '%some_value%'
Session ID Uniqueness:
sessionId must be unique and persistent (e.g., a database-generated token). Reusing IDs can corrupt payment tracking.URL Validation:
returnUrl and statusUrl must be absolute URLs (use UrlGeneratorInterface::ABSOLUTE_URL).Sandbox vs. Production:
sandbox: true) before switching to production.Event Dispatching:
statusUrl endpoint to ensure events fire.CRC Key Sensitivity:
crc_key must match exactly (case-sensitive) between your config and Przelewy24’s merchant settings.Verify Payments Manually:
Use the test tool (/p24-test) to check if your statusUrl endpoint is reachable and correctly processes Przelewy24’s callbacks.
Log Events: Add logging to event listeners to debug:
public function onPaymentSuccess(PaymentEventInterface $event)
{
$this->logger->info('Payment success', [
'sessionId' => $event->getPayment()->getSessionId(),
'amount' => $event->getPayment()->getAmount(),
]);
}
Check Guzzle Responses: If payments fail silently, enable Guzzle logging:
$processFactory->setClient($this->createClientWithLogging());
Custom Payment Data:
Extend the Payment model to add fields:
class CustomPayment extends Payment
{
private $customField;
public function setCustomField($value): self
{
$this->customField = $value;
return $this;
}
}
Override the service in config/services.yaml:
services:
Arturwwl\Przelewy24Bundle\Model\Payment: '@App\Model\CustomPayment'
Override ProcessFactory: Create a decorator to modify behavior:
class CustomProcessFactoryDecorator implements ProcessFactoryInterface
{
private $decorated;
public function __construct(ProcessFactory $decorated)
{
$this->decorated = $decorated;
}
public function createAndGetUrl($merchantId, $crcKey)
{
// Add custom logic (e.g., logging)
return $this->decorated->createAndGetUrl($merchantId, $crcKey);
}
}
Register it as a replacement in config/services.yaml.
Add New Events: Extend the bundle’s event system by creating custom events and dispatching them in listeners:
class PaymentProcessedEvent extends Event
{
// ...
}
Dispatch in a listener:
$eventDispatcher->dispatch(new PaymentProcessedEvent($payment));
Environment Variables:
Use Symfony’s %env() syntax for sensitive data (e.g., merchant_id and crc_key).
Example in .env:
PRZELEWY24_MERCHANT_ID=your_merchant_id
PRZELEWY24_CRC_KEY=your_crc_key
Bundle Parameters: Access config via:
$merchantId = $this->getParameter('arturwwl_przelewy24.merchant_id');
Or inject the config directly:
public function __construct(array $config)
{
$this->merchantId = $config['merchant_id'];
}
How can I help you explore Laravel packages today?